| // Copyright 2015 The Weave Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef LIBWEAVE_SRC_COMMANDS_PROP_VALUES_H_ | |
| #define LIBWEAVE_SRC_COMMANDS_PROP_VALUES_H_ | |
| #include <map> | |
| #include <memory> | |
| #include <string> | |
| #include <weave/error.h> | |
| #include "src/commands/schema_utils.h" | |
| namespace base { | |
| class Value; | |
| class DictionaryValue; | |
| } // namespace base | |
| namespace weave { | |
| // Enumeration to indicate supported command parameter types. | |
| enum class ValueType { | |
| Int, | |
| Double, | |
| String, | |
| Boolean, | |
| Object, | |
| Array, | |
| }; | |
| class PropValue; | |
| class IntValue; | |
| class DoubleValue; | |
| class StringValue; | |
| class BooleanValue; | |
| class ObjectValue; | |
| class ArrayValue; | |
| class PropType; | |
| // Helper methods to get the parameter type enum value for the given | |
| // native C++ data representation. | |
| // The generic GetValueType<T>() is undefined, however particular | |
| // type specializations return the appropriate ValueType. | |
| template <typename T> | |
| ValueType GetValueType(); // Undefined. | |
| template <> | |
| inline ValueType GetValueType<int>() { | |
| return ValueType::Int; | |
| } | |
| template <> | |
| inline ValueType GetValueType<double>() { | |
| return ValueType::Double; | |
| } | |
| template <> | |
| inline ValueType GetValueType<std::string>() { | |
| return ValueType::String; | |
| } | |
| template <> | |
| inline ValueType GetValueType<bool>() { | |
| return ValueType::Boolean; | |
| } | |
| template <> | |
| inline ValueType GetValueType<ValueMap>() { | |
| return ValueType::Object; | |
| } | |
| template <> | |
| inline ValueType GetValueType<ValueVector>() { | |
| return ValueType::Array; | |
| } | |
| // The base class for property values. | |
| // Concrete value classes of various types will be derived from this base. | |
| // A property value is the actual command parameter value (or a concrete value | |
| // that can be used in constraints and presets). The PropValue is mostly | |
| // just parsed content of base::Value when a command is dispatched, however | |
| // it does have some additional functionality: | |
| // - it has a reference to the type definition (PropType) which is used | |
| // when validating the value, especially for "object" types. | |
| // - it can be compared with another instances of values of the same type. | |
| // This is used to validate the values against "enum"/"one of" constraints. | |
| class PropValue { | |
| public: | |
| // Only CreateDefaultValue should use this constructor. | |
| explicit PropValue(const PropType& type); | |
| virtual ~PropValue(); | |
| // Gets the type of the value. | |
| virtual ValueType GetType() const = 0; | |
| // Type conversion methods. Used in lieu of RTTI and dynamic_cast<>. | |
| virtual IntValue* GetInt() { return nullptr; } | |
| virtual IntValue const* GetInt() const { return nullptr; } | |
| virtual DoubleValue* GetDouble() { return nullptr; } | |
| virtual DoubleValue const* GetDouble() const { return nullptr; } | |
| virtual StringValue* GetString() { return nullptr; } | |
| virtual StringValue const* GetString() const { return nullptr; } | |
| virtual BooleanValue* GetBoolean() { return nullptr; } | |
| virtual BooleanValue const* GetBoolean() const { return nullptr; } | |
| virtual ObjectValue* GetObject() { return nullptr; } | |
| virtual ObjectValue const* GetObject() const { return nullptr; } | |
| virtual ArrayValue* GetArray() { return nullptr; } | |
| virtual ArrayValue const* GetArray() const { return nullptr; } | |
| // Makes a full copy of this value class. | |
| virtual std::unique_ptr<PropValue> Clone() const = 0; | |
| // Saves the value as a JSON object. Never fails. | |
| virtual std::unique_ptr<base::Value> ToJson() const = 0; | |
| // Return the type definition of this value. | |
| const PropType* GetPropType() const { return type_.get(); } | |
| // Compares two values and returns true if they are equal. | |
| virtual bool IsEqual(const PropValue* value) const = 0; | |
| protected: | |
| // Special out-of-line constructor to help implement PropValue::Clone(). | |
| // That method needs to clone the underlying type but can't do this in this | |
| // header file since PropType is just forward-declared (it needs PropValue | |
| // fully defined in its own inner workings). | |
| explicit PropValue(const PropValue& other); | |
| private: | |
| std::unique_ptr<const PropType> type_; | |
| }; | |
| // A helper template base class for implementing value classes. | |
| template <typename T> | |
| class TypedValueBase : public PropValue { | |
| public: | |
| using PropValue::PropValue; | |
| // Overrides from PropValue base class. | |
| ValueType GetType() const override { return GetValueType<T>(); } | |
| std::unique_ptr<base::Value> ToJson() const override { | |
| return TypedValueToJson(value_); | |
| } | |
| bool IsEqual(const PropValue* value) const override { | |
| if (GetType() != value->GetType()) | |
| return false; | |
| return CompareValue(GetValue(), | |
| static_cast<const TypedValueBase*>(value)->GetValue()); | |
| } | |
| // Helper methods to get and set the C++ representation of the value. | |
| const T& GetValue() const { return value_; } | |
| protected: | |
| explicit TypedValueBase(const TypedValueBase& other) | |
| : PropValue(other), value_(other.value_) {} | |
| TypedValueBase(const PropType& type, T value) | |
| : PropValue(type), value_(value) {} | |
| private: | |
| T value_{}; // The value of the parameter in C++ data representation. | |
| }; | |
| // A helper template base class for implementing value classes. | |
| template <typename Derived, typename T> | |
| class TypedValueWithClone : public TypedValueBase<T> { | |
| public: | |
| using Base = TypedValueWithClone<Derived, T>; | |
| // Expose the custom constructor of the base class. | |
| using TypedValueBase<T>::TypedValueBase; | |
| using PropValue::GetPropType; | |
| std::unique_ptr<PropValue> Clone() const override { | |
| return std::unique_ptr<PropValue>{ | |
| new Derived{*static_cast<const Derived*>(this)}}; | |
| } | |
| static std::unique_ptr<Derived> CreateFromJson(const base::Value& value, | |
| const PropType& type, | |
| ErrorPtr* error) { | |
| T tmp_value; | |
| if (!TypedValueFromJson(&value, &type, &tmp_value, error)) | |
| return nullptr; | |
| // Only place where invalid value can exist. | |
| std::unique_ptr<Derived> result{new Derived{type, tmp_value}}; | |
| if (!result->GetPropType()->ValidateConstraints(*result, error)) | |
| return nullptr; | |
| return result; | |
| } | |
| }; | |
| // Value of type Integer. | |
| class IntValue final : public TypedValueWithClone<IntValue, int> { | |
| public: | |
| using Base::Base; | |
| friend class TypedValueWithClone<IntValue, int>; | |
| IntValue* GetInt() override { return this; } | |
| IntValue const* GetInt() const override { return this; } | |
| }; | |
| // Value of type Number. | |
| class DoubleValue final : public TypedValueWithClone<DoubleValue, double> { | |
| public: | |
| using Base::Base; | |
| friend class TypedValueWithClone<DoubleValue, double>; | |
| DoubleValue* GetDouble() override { return this; } | |
| DoubleValue const* GetDouble() const override { return this; } | |
| }; | |
| // Value of type String. | |
| class StringValue final : public TypedValueWithClone<StringValue, std::string> { | |
| public: | |
| using Base::Base; | |
| friend class TypedValueWithClone<StringValue, std::string>; | |
| StringValue* GetString() override { return this; } | |
| StringValue const* GetString() const override { return this; } | |
| }; | |
| // Value of type Boolean. | |
| class BooleanValue final : public TypedValueWithClone<BooleanValue, bool> { | |
| public: | |
| using Base::Base; | |
| friend class TypedValueWithClone<BooleanValue, bool>; | |
| BooleanValue* GetBoolean() override { return this; } | |
| BooleanValue const* GetBoolean() const override { return this; } | |
| }; | |
| // Value of type Object. | |
| class ObjectValue final : public TypedValueWithClone<ObjectValue, ValueMap> { | |
| public: | |
| using Base::Base; | |
| friend class TypedValueWithClone<ObjectValue, ValueMap>; | |
| ObjectValue* GetObject() override { return this; } | |
| ObjectValue const* GetObject() const override { return this; } | |
| }; | |
| // Value of type Array. | |
| class ArrayValue final : public TypedValueWithClone<ArrayValue, ValueVector> { | |
| public: | |
| using Base::Base; | |
| friend class TypedValueWithClone<ArrayValue, ValueVector>; | |
| ArrayValue* GetArray() override { return this; } | |
| ArrayValue const* GetArray() const override { return this; } | |
| }; | |
| } // namespace weave | |
| #endif // LIBWEAVE_SRC_COMMANDS_PROP_VALUES_H_ |