Vitaly Buka | 4615e0d | 2015-10-14 15:35:12 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Weave Authors. All rights reserved. |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Vitaly Buka | 912b698 | 2015-07-06 11:13:03 -0700 | [diff] [blame] | 5 | #ifndef LIBWEAVE_SRC_COMMANDS_PROP_VALUES_H_ |
| 6 | #define LIBWEAVE_SRC_COMMANDS_PROP_VALUES_H_ |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 7 | |
| 8 | #include <map> |
| 9 | #include <memory> |
| 10 | #include <string> |
| 11 | |
Vitaly Buka | 0801a1f | 2015-08-14 10:03:46 -0700 | [diff] [blame] | 12 | #include <weave/error.h> |
Alex Vakulenko | 5f47206 | 2014-08-14 17:54:04 -0700 | [diff] [blame] | 13 | |
Stefan Sauer | 2d16dfa | 2015-09-25 17:08:35 +0200 | [diff] [blame] | 14 | #include "src/commands/schema_utils.h" |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 15 | |
| 16 | namespace base { |
| 17 | class Value; |
| 18 | class DictionaryValue; |
| 19 | } // namespace base |
| 20 | |
Vitaly Buka | b6f015a | 2015-07-09 14:59:23 -0700 | [diff] [blame] | 21 | namespace weave { |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 22 | |
| 23 | // Enumeration to indicate supported command parameter types. |
| 24 | enum class ValueType { |
| 25 | Int, |
| 26 | Double, |
| 27 | String, |
Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 28 | Boolean, |
Alex Vakulenko | 29e6444 | 2015-03-20 13:59:19 -0700 | [diff] [blame] | 29 | Object, |
| 30 | Array, |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 31 | }; |
| 32 | |
Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 33 | class PropValue; |
| 34 | class IntValue; |
| 35 | class DoubleValue; |
| 36 | class StringValue; |
| 37 | class BooleanValue; |
| 38 | class ObjectValue; |
Alex Vakulenko | 29e6444 | 2015-03-20 13:59:19 -0700 | [diff] [blame] | 39 | class ArrayValue; |
Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 40 | |
| 41 | class PropType; |
| 42 | |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 43 | // Helper methods to get the parameter type enum value for the given |
| 44 | // native C++ data representation. |
| 45 | // The generic GetValueType<T>() is undefined, however particular |
| 46 | // type specializations return the appropriate ValueType. |
Vitaly Buka | a647c85 | 2015-07-06 14:51:01 -0700 | [diff] [blame] | 47 | template <typename T> |
| 48 | ValueType GetValueType(); // Undefined. |
| 49 | template <> |
| 50 | inline ValueType GetValueType<int>() { |
| 51 | return ValueType::Int; |
| 52 | } |
| 53 | template <> |
| 54 | inline ValueType GetValueType<double>() { |
| 55 | return ValueType::Double; |
| 56 | } |
| 57 | template <> |
| 58 | inline ValueType GetValueType<std::string>() { |
| 59 | return ValueType::String; |
| 60 | } |
| 61 | template <> |
| 62 | inline ValueType GetValueType<bool>() { |
| 63 | return ValueType::Boolean; |
| 64 | } |
| 65 | template <> |
Vitaly Buka | 774cdf5 | 2015-07-21 13:55:00 -0700 | [diff] [blame] | 66 | inline ValueType GetValueType<ValueMap>() { |
Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 67 | return ValueType::Object; |
| 68 | } |
Vitaly Buka | a647c85 | 2015-07-06 14:51:01 -0700 | [diff] [blame] | 69 | template <> |
Vitaly Buka | 774cdf5 | 2015-07-21 13:55:00 -0700 | [diff] [blame] | 70 | inline ValueType GetValueType<ValueVector>() { |
Alex Vakulenko | 29e6444 | 2015-03-20 13:59:19 -0700 | [diff] [blame] | 71 | return ValueType::Array; |
| 72 | } |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 73 | |
Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 74 | // The base class for property values. |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 75 | // Concrete value classes of various types will be derived from this base. |
Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 76 | // A property value is the actual command parameter value (or a concrete value |
| 77 | // that can be used in constraints and presets). The PropValue is mostly |
| 78 | // just parsed content of base::Value when a command is dispatched, however |
| 79 | // it does have some additional functionality: |
| 80 | // - it has a reference to the type definition (PropType) which is used |
| 81 | // when validating the value, especially for "object" types. |
| 82 | // - it can be compared with another instances of values of the same type. |
| 83 | // This is used to validate the values against "enum"/"one of" constraints. |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 84 | class PropValue { |
| 85 | public: |
Vitaly Buka | 79c05e9 | 2015-07-29 12:25:37 -0700 | [diff] [blame] | 86 | // Only CreateDefaultValue should use this constructor. |
| 87 | explicit PropValue(const PropType& type); |
Alex Vakulenko | 5ef7579 | 2015-03-19 15:50:44 -0700 | [diff] [blame] | 88 | virtual ~PropValue(); |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 89 | |
| 90 | // Gets the type of the value. |
| 91 | virtual ValueType GetType() const = 0; |
| 92 | |
| 93 | // Type conversion methods. Used in lieu of RTTI and dynamic_cast<>. |
| 94 | virtual IntValue* GetInt() { return nullptr; } |
| 95 | virtual IntValue const* GetInt() const { return nullptr; } |
| 96 | virtual DoubleValue* GetDouble() { return nullptr; } |
| 97 | virtual DoubleValue const* GetDouble() const { return nullptr; } |
| 98 | virtual StringValue* GetString() { return nullptr; } |
| 99 | virtual StringValue const* GetString() const { return nullptr; } |
| 100 | virtual BooleanValue* GetBoolean() { return nullptr; } |
| 101 | virtual BooleanValue const* GetBoolean() const { return nullptr; } |
Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 102 | virtual ObjectValue* GetObject() { return nullptr; } |
| 103 | virtual ObjectValue const* GetObject() const { return nullptr; } |
Alex Vakulenko | 29e6444 | 2015-03-20 13:59:19 -0700 | [diff] [blame] | 104 | virtual ArrayValue* GetArray() { return nullptr; } |
| 105 | virtual ArrayValue const* GetArray() const { return nullptr; } |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 106 | |
| 107 | // Makes a full copy of this value class. |
Alex Vakulenko | 5ef7579 | 2015-03-19 15:50:44 -0700 | [diff] [blame] | 108 | virtual std::unique_ptr<PropValue> Clone() const = 0; |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 109 | |
Vitaly Buka | 6942e1f | 2015-07-28 15:33:55 -0700 | [diff] [blame] | 110 | // Saves the value as a JSON object. Never fails. |
| 111 | virtual std::unique_ptr<base::Value> ToJson() const = 0; |
Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 112 | |
Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 113 | // Return the type definition of this value. |
Alex Vakulenko | 5ef7579 | 2015-03-19 15:50:44 -0700 | [diff] [blame] | 114 | const PropType* GetPropType() const { return type_.get(); } |
Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 115 | // Compares two values and returns true if they are equal. |
| 116 | virtual bool IsEqual(const PropValue* value) const = 0; |
| 117 | |
| 118 | protected: |
Vitaly Buka | c58a828 | 2015-07-29 01:25:20 -0700 | [diff] [blame] | 119 | // Special out-of-line constructor to help implement PropValue::Clone(). |
| 120 | // That method needs to clone the underlying type but can't do this in this |
| 121 | // header file since PropType is just forward-declared (it needs PropValue |
| 122 | // fully defined in its own inner workings). |
| 123 | explicit PropValue(const PropValue& other); |
| 124 | |
| 125 | private: |
Alex Vakulenko | 5ef7579 | 2015-03-19 15:50:44 -0700 | [diff] [blame] | 126 | std::unique_ptr<const PropType> type_; |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 127 | }; |
| 128 | |
Alex Vakulenko | 29e6444 | 2015-03-20 13:59:19 -0700 | [diff] [blame] | 129 | // A helper template base class for implementing value classes. |
Vitaly Buka | c58a828 | 2015-07-29 01:25:20 -0700 | [diff] [blame] | 130 | template <typename T> |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 131 | class TypedValueBase : public PropValue { |
| 132 | public: |
Vitaly Buka | 52d006a | 2015-11-21 17:14:51 -0800 | [diff] [blame] | 133 | TypedValueBase(const PropType& type) : PropValue(type) {} |
Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 134 | |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 135 | // Overrides from PropValue base class. |
Alex Vakulenko | 5a9e718 | 2014-08-11 15:59:58 -0700 | [diff] [blame] | 136 | ValueType GetType() const override { return GetValueType<T>(); } |
Alex Vakulenko | 5ef7579 | 2015-03-19 15:50:44 -0700 | [diff] [blame] | 137 | |
Vitaly Buka | 6942e1f | 2015-07-28 15:33:55 -0700 | [diff] [blame] | 138 | std::unique_ptr<base::Value> ToJson() const override { |
| 139 | return TypedValueToJson(value_); |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 140 | } |
| 141 | |
Alex Vakulenko | 5a9e718 | 2014-08-11 15:59:58 -0700 | [diff] [blame] | 142 | bool IsEqual(const PropValue* value) const override { |
Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 143 | if (GetType() != value->GetType()) |
| 144 | return false; |
Vitaly Buka | 79c05e9 | 2015-07-29 12:25:37 -0700 | [diff] [blame] | 145 | return CompareValue(GetValue(), |
| 146 | static_cast<const TypedValueBase*>(value)->GetValue()); |
Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 147 | } |
| 148 | |
| 149 | // Helper methods to get and set the C++ representation of the value. |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 150 | const T& GetValue() const { return value_; } |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 151 | |
| 152 | protected: |
Vitaly Buka | c58a828 | 2015-07-29 01:25:20 -0700 | [diff] [blame] | 153 | explicit TypedValueBase(const TypedValueBase& other) |
| 154 | : PropValue(other), value_(other.value_) {} |
| 155 | |
Vitaly Buka | 79c05e9 | 2015-07-29 12:25:37 -0700 | [diff] [blame] | 156 | TypedValueBase(const PropType& type, T value) |
| 157 | : PropValue(type), value_(value) {} |
| 158 | |
Vitaly Buka | c58a828 | 2015-07-29 01:25:20 -0700 | [diff] [blame] | 159 | private: |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 160 | T value_{}; // The value of the parameter in C++ data representation. |
| 161 | }; |
| 162 | |
Vitaly Buka | c58a828 | 2015-07-29 01:25:20 -0700 | [diff] [blame] | 163 | // A helper template base class for implementing value classes. |
| 164 | template <typename Derived, typename T> |
| 165 | class TypedValueWithClone : public TypedValueBase<T> { |
| 166 | public: |
Vitaly Buka | 52d006a | 2015-11-21 17:14:51 -0800 | [diff] [blame] | 167 | TypedValueWithClone(const PropType& type) : TypedValueBase<T>(type) {} |
| 168 | TypedValueWithClone(const PropType& type, const T& value) |
| 169 | : TypedValueBase<T>(type, value) {} |
Vitaly Buka | c58a828 | 2015-07-29 01:25:20 -0700 | [diff] [blame] | 170 | |
| 171 | std::unique_ptr<PropValue> Clone() const override { |
| 172 | return std::unique_ptr<PropValue>{ |
| 173 | new Derived{*static_cast<const Derived*>(this)}}; |
| 174 | } |
Vitaly Buka | 79c05e9 | 2015-07-29 12:25:37 -0700 | [diff] [blame] | 175 | |
| 176 | static std::unique_ptr<Derived> CreateFromJson(const base::Value& value, |
| 177 | const PropType& type, |
Vitaly Buka | 0801a1f | 2015-08-14 10:03:46 -0700 | [diff] [blame] | 178 | ErrorPtr* error) { |
Vitaly Buka | 79c05e9 | 2015-07-29 12:25:37 -0700 | [diff] [blame] | 179 | T tmp_value; |
| 180 | if (!TypedValueFromJson(&value, &type, &tmp_value, error)) |
| 181 | return nullptr; |
| 182 | |
| 183 | // Only place where invalid value can exist. |
Vitaly Buka | 52d006a | 2015-11-21 17:14:51 -0800 | [diff] [blame] | 184 | std::unique_ptr<Derived> result(new Derived(type, tmp_value)); |
Vitaly Buka | 79c05e9 | 2015-07-29 12:25:37 -0700 | [diff] [blame] | 185 | if (!result->GetPropType()->ValidateConstraints(*result, error)) |
| 186 | return nullptr; |
| 187 | |
| 188 | return result; |
| 189 | } |
Vitaly Buka | c58a828 | 2015-07-29 01:25:20 -0700 | [diff] [blame] | 190 | }; |
| 191 | |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 192 | // Value of type Integer. |
Vitaly Buka | c58a828 | 2015-07-29 01:25:20 -0700 | [diff] [blame] | 193 | class IntValue final : public TypedValueWithClone<IntValue, int> { |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 194 | public: |
Vitaly Buka | 52d006a | 2015-11-21 17:14:51 -0800 | [diff] [blame] | 195 | explicit IntValue(const PropType& type) |
| 196 | : TypedValueWithClone<IntValue, int>(type) {} |
| 197 | IntValue(const PropType& type, int value) |
| 198 | : TypedValueWithClone<IntValue, int>(type, value) {} |
| 199 | |
Alex Vakulenko | 5a9e718 | 2014-08-11 15:59:58 -0700 | [diff] [blame] | 200 | IntValue* GetInt() override { return this; } |
| 201 | IntValue const* GetInt() const override { return this; } |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 202 | }; |
| 203 | |
| 204 | // Value of type Number. |
Vitaly Buka | c58a828 | 2015-07-29 01:25:20 -0700 | [diff] [blame] | 205 | class DoubleValue final : public TypedValueWithClone<DoubleValue, double> { |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 206 | public: |
Vitaly Buka | 52d006a | 2015-11-21 17:14:51 -0800 | [diff] [blame] | 207 | explicit DoubleValue(const PropType& type) |
| 208 | : TypedValueWithClone<DoubleValue, double>(type) {} |
| 209 | DoubleValue(const PropType& type, double value) |
| 210 | : TypedValueWithClone<DoubleValue, double>(type, value) {} |
| 211 | |
Alex Vakulenko | 5a9e718 | 2014-08-11 15:59:58 -0700 | [diff] [blame] | 212 | DoubleValue* GetDouble() override { return this; } |
| 213 | DoubleValue const* GetDouble() const override { return this; } |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 214 | }; |
| 215 | |
| 216 | // Value of type String. |
Vitaly Buka | c58a828 | 2015-07-29 01:25:20 -0700 | [diff] [blame] | 217 | class StringValue final : public TypedValueWithClone<StringValue, std::string> { |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 218 | public: |
Vitaly Buka | 52d006a | 2015-11-21 17:14:51 -0800 | [diff] [blame] | 219 | explicit StringValue(const PropType& type) |
| 220 | : TypedValueWithClone<StringValue, std::string>(type) {} |
| 221 | StringValue(const PropType& type, std::string value) |
| 222 | : TypedValueWithClone<StringValue, std::string>(type, value) {} |
| 223 | |
Alex Vakulenko | 5a9e718 | 2014-08-11 15:59:58 -0700 | [diff] [blame] | 224 | StringValue* GetString() override { return this; } |
| 225 | StringValue const* GetString() const override { return this; } |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 226 | }; |
| 227 | |
| 228 | // Value of type Boolean. |
Vitaly Buka | c58a828 | 2015-07-29 01:25:20 -0700 | [diff] [blame] | 229 | class BooleanValue final : public TypedValueWithClone<BooleanValue, bool> { |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 230 | public: |
Vitaly Buka | 52d006a | 2015-11-21 17:14:51 -0800 | [diff] [blame] | 231 | explicit BooleanValue(const PropType& type) |
| 232 | : TypedValueWithClone<BooleanValue, bool>(type) {} |
| 233 | BooleanValue(const PropType& type, bool value) |
| 234 | : TypedValueWithClone<BooleanValue, bool>(type, value) {} |
| 235 | |
Alex Vakulenko | 5a9e718 | 2014-08-11 15:59:58 -0700 | [diff] [blame] | 236 | BooleanValue* GetBoolean() override { return this; } |
| 237 | BooleanValue const* GetBoolean() const override { return this; } |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 238 | }; |
| 239 | |
Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 240 | // Value of type Object. |
Vitaly Buka | c58a828 | 2015-07-29 01:25:20 -0700 | [diff] [blame] | 241 | class ObjectValue final : public TypedValueWithClone<ObjectValue, ValueMap> { |
Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 242 | public: |
Vitaly Buka | 52d006a | 2015-11-21 17:14:51 -0800 | [diff] [blame] | 243 | explicit ObjectValue(const PropType& type) |
| 244 | : TypedValueWithClone<ObjectValue, ValueMap>(type) {} |
| 245 | ObjectValue(const PropType& type, ValueMap value) |
| 246 | : TypedValueWithClone<ObjectValue, ValueMap>(type, value) {} |
| 247 | |
Alex Vakulenko | 5a9e718 | 2014-08-11 15:59:58 -0700 | [diff] [blame] | 248 | ObjectValue* GetObject() override { return this; } |
| 249 | ObjectValue const* GetObject() const override { return this; } |
Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 250 | }; |
Alex Vakulenko | 29e6444 | 2015-03-20 13:59:19 -0700 | [diff] [blame] | 251 | |
| 252 | // Value of type Array. |
Vitaly Buka | c58a828 | 2015-07-29 01:25:20 -0700 | [diff] [blame] | 253 | class ArrayValue final : public TypedValueWithClone<ArrayValue, ValueVector> { |
Alex Vakulenko | 29e6444 | 2015-03-20 13:59:19 -0700 | [diff] [blame] | 254 | public: |
Vitaly Buka | 52d006a | 2015-11-21 17:14:51 -0800 | [diff] [blame] | 255 | explicit ArrayValue(const PropType& type) |
| 256 | : TypedValueWithClone<ArrayValue, ValueVector>(type) {} |
| 257 | ArrayValue(const PropType& type, ValueVector value) |
| 258 | : TypedValueWithClone<ArrayValue, ValueVector>(type, value) {} |
| 259 | |
Alex Vakulenko | 29e6444 | 2015-03-20 13:59:19 -0700 | [diff] [blame] | 260 | ArrayValue* GetArray() override { return this; } |
| 261 | ArrayValue const* GetArray() const override { return this; } |
| 262 | }; |
| 263 | |
Vitaly Buka | b6f015a | 2015-07-09 14:59:23 -0700 | [diff] [blame] | 264 | } // namespace weave |
Alex Vakulenko | e439a0f | 2014-05-21 12:26:47 -0700 | [diff] [blame] | 265 | |
Vitaly Buka | 912b698 | 2015-07-06 11:13:03 -0700 | [diff] [blame] | 266 | #endif // LIBWEAVE_SRC_COMMANDS_PROP_VALUES_H_ |