blob: f784eb69083b7c0afed82b168dfeeec4b60b5dbe [file] [log] [blame]
// 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_TYPES_H_
#define LIBWEAVE_SRC_COMMANDS_PROP_TYPES_H_
#include <limits>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include <weave/error.h>
#include "src/commands/prop_constraints.h"
#include "src/commands/prop_values.h"
namespace weave {
class IntPropType;
class DoublePropType;
class StringPropType;
class BooleanPropType;
class ObjectPropType;
class ArrayPropType;
// PropType is a base class for all parameter type definition objects.
// Property definitions of a particular type will derive from this class and
// provide type-specific implementations.
class PropType {
public:
// ConstraintMap is a type alias for a map containing parameter
// constraints. It is implemented as a map for fast look-ups of constraints
// of particular type. Also it is expected to have at most one constraint
// of each type (e.g. it makes no sense to impose two "minimum" constraints
// onto a numeric parameter).
using ConstraintMap = std::map<ConstraintType, std::unique_ptr<Constraint>>;
PropType();
virtual ~PropType();
// Gets the parameter type as an enumeration.
virtual ValueType GetType() const = 0;
// Gets the parameter type as a string.
std::string GetTypeAsString() const;
// Returns true if this parameter definition inherits a type
// definition from a base object schema.
bool IsBasedOnSchema() const { return based_on_schema_; }
// Returns a default value specified for the type, or nullptr if no default
// is available.
const PropValue* GetDefaultValue() const { return default_.value.get(); }
// Gets the constraints specified for the parameter, if any.
const ConstraintMap& GetConstraints() const { return constraints_; }
// Returns true if this value is required. Properties are marked as required
// by using "isRequired" attribute or listed in "required" array.
bool IsRequired() const;
// Sets the required attribute to the value of |required| and marks it as
// overridden (not-inherited).
void MakeRequired(bool required);
// Checks if any of the type attributes were overridden from the base
// schema definition. If this type does not inherit from a base schema,
// this method returns true.
// An attribute could be the value of any of the constraints, default
// value of a parameter or any other data that may be specified in
// parameter type definition in and can be inherited from the base schema.
virtual bool HasOverriddenAttributes() const;
// Type conversion methods. Used in lieu of RTTI and dynamic_cast<>.
virtual IntPropType* GetInt() { return nullptr; }
virtual IntPropType const* GetInt() const { return nullptr; }
virtual DoublePropType* GetDouble() { return nullptr; }
virtual DoublePropType const* GetDouble() const { return nullptr; }
virtual StringPropType* GetString() { return nullptr; }
virtual StringPropType const* GetString() const { return nullptr; }
virtual BooleanPropType* GetBoolean() { return nullptr; }
virtual BooleanPropType const* GetBoolean() const { return nullptr; }
virtual ObjectPropType* GetObject() { return nullptr; }
virtual ObjectPropType const* GetObject() const { return nullptr; }
virtual ArrayPropType* GetArray() { return nullptr; }
virtual ArrayPropType const* GetArray() const { return nullptr; }
// Makes a full copy of this type definition.
virtual std::unique_ptr<PropType> Clone() const;
// Creates an instance of associated value object.
virtual std::unique_ptr<PropValue> CreatePropValue(const base::Value& value,
ErrorPtr* error) const = 0;
// Saves the parameter type definition as a JSON object.
// If |full_schema| is set to true, the full type definition is saved,
// otherwise only the overridden properties and attributes from the base
// schema is saved. That is, inherited properties and attributes are not
// saved.
// If it fails, returns "nullptr" and fills in the |error| with additional
// error information.
// |in_command_def| is set to true if the property type describes a
// GCD command parameter, otherwise it is for an object property.
// Command definitions handle required parameters differently (using
// "isRequired" property as opposed to "required" list for object properties).
virtual std::unique_ptr<base::Value> ToJson(bool full_schema,
bool in_command_def) const;
// Parses an JSON parameter type definition. Optional |base_schema| may
// specify the base schema type definition this type should be based upon.
// If not specified (nullptr), the parameter type is assumed to be a full
// definition and any omitted required properties are treated as an error.
// Returns true on success, otherwise fills in the |error| with additional
// error information.
virtual bool FromJson(const base::DictionaryValue* value,
const PropType* base_schema,
ErrorPtr* error);
// Helper function to load object schema from JSON.
virtual bool ObjectSchemaFromJson(const base::DictionaryValue* value,
const PropType* base_schema,
std::set<std::string>* processed_keys,
ErrorPtr* error) {
return true;
}
// Helper function to load type-specific constraints from JSON.
virtual bool ConstraintsFromJson(const base::DictionaryValue* value,
std::set<std::string>* processed_keys,
ErrorPtr* error) {
return true;
}
// Additional helper static methods to help with converting a type enum
// value into a string and back.
using TypeMap = std::vector<std::pair<ValueType, std::string>>;
// Returns a list of value types and corresponding type names.
static const TypeMap& GetTypeMap();
// Gets the type name string for the given type.
static std::string GetTypeStringFromType(ValueType type);
// Finds the type for the given type name. Returns true on success.
static bool GetTypeFromTypeString(const std::string& name, ValueType* type);
// Creates an instance of PropType-derived class for the specified
// parameter type.
static std::unique_ptr<PropType> Create(ValueType type);
// Adds a constraint to the type definition.
void AddConstraint(std::unique_ptr<Constraint> constraint);
// Removes a constraint of given type, if it exists.
void RemoveConstraint(ConstraintType constraint_type);
// Removes all constraints.
void RemoveAllConstraints();
// Finds a constraint of given type. Returns nullptr if not found.
const Constraint* GetConstraint(ConstraintType constraint_type) const;
Constraint* GetConstraint(ConstraintType constraint_type);
// Validates the given value against all the constraints.
bool ValidateConstraints(const PropValue& value, ErrorPtr* error) const;
protected:
friend class StatePackage;
virtual std::unique_ptr<PropValue> CreateDefaultValue() const = 0;
// Specifies if this parameter definition is derived from a base
// object schema.
bool based_on_schema_ = false;
// A list of constraints specified for the parameter.
ConstraintMap constraints_;
// The default value specified for the parameter, if any. If the default
// value is present, the parameter is treated as optional and the default
// value is used if the parameter value is omitted when sending a command.
// Otherwise the parameter is treated as required and, if it is omitted,
// this is treated as an error.
InheritableAttribute<std::unique_ptr<PropValue>> default_;
// Specifies whether the parameter/property is required and must be specified
// (either directly, or by the default value being provided in the schema).
// Non-required parameters can be omitted completely and their values will not
// be present in the object instance.
InheritableAttribute<bool> required_;
};
// Base class for all the derived concrete implementations of property
// type classes. Provides implementations for common methods of PropType base.
template <class Derived, class Value, typename T>
class PropTypeBase : public PropType {
public:
// Overrides from PropType.
ValueType GetType() const override { return GetValueType<T>(); }
std::unique_ptr<PropValue> CreatePropValue(const base::Value& value,
ErrorPtr* error) const override {
return CreateValue(value, error);
}
std::unique_ptr<Value> CreateValue(const base::Value& value,
ErrorPtr* error) const {
return Value::CreateFromJson(value, *this, error);
}
bool ConstraintsFromJson(const base::DictionaryValue* value,
std::set<std::string>* processed_keys,
ErrorPtr* error) override;
protected:
std::unique_ptr<PropValue> CreateDefaultValue() const override {
if (GetDefaultValue())
return GetDefaultValue()->Clone();
return std::unique_ptr<PropValue>{new Value{*this}};
}
};
// Helper base class for Int and Double parameter types.
template <class Derived, class Value, typename T>
class NumericPropTypeBase : public PropTypeBase<Derived, Value, T> {
public:
using Base = PropTypeBase<Derived, Value, T>;
bool ConstraintsFromJson(const base::DictionaryValue* value,
std::set<std::string>* processed_keys,
ErrorPtr* error) override;
// Helper method to set and obtain a min/max constraint values.
// Used mostly for unit testing.
void AddMinMaxConstraint(T min_value, T max_value) {
InheritableAttribute<T> min_attr(min_value, false);
InheritableAttribute<T> max_attr(max_value, false);
this->AddConstraint(
std::unique_ptr<ConstraintMin<T>>{new ConstraintMin<T>{min_attr}});
this->AddConstraint(
std::unique_ptr<ConstraintMax<T>>{new ConstraintMax<T>{max_attr}});
}
T GetMinValue() const {
auto mmc = static_cast<const ConstraintMin<T>*>(
this->GetConstraint(ConstraintType::Min));
return mmc ? mmc->limit_.value : std::numeric_limits<T>::lowest();
}
T GetMaxValue() const {
auto mmc = static_cast<const ConstraintMax<T>*>(
this->GetConstraint(ConstraintType::Max));
return mmc ? mmc->limit_.value : (std::numeric_limits<T>::max)();
}
};
// Property definition of Integer type.
class IntPropType : public NumericPropTypeBase<IntPropType, IntValue, int> {
public:
// Overrides from the PropType base class.
IntPropType* GetInt() override { return this; }
IntPropType const* GetInt() const override { return this; }
};
// Property definition of Number type.
class DoublePropType
: public NumericPropTypeBase<DoublePropType, DoubleValue, double> {
public:
// Overrides from the PropType base class.
DoublePropType* GetDouble() override { return this; }
DoublePropType const* GetDouble() const override { return this; }
};
// Property definition of String type.
class StringPropType
: public PropTypeBase<StringPropType, StringValue, std::string> {
public:
using Base = PropTypeBase<StringPropType, StringValue, std::string>;
// Overrides from the PropType base class.
StringPropType* GetString() override { return this; }
StringPropType const* GetString() const override { return this; }
bool ConstraintsFromJson(const base::DictionaryValue* value,
std::set<std::string>* processed_keys,
ErrorPtr* error) override;
// Helper methods to add and inspect simple constraints.
// Used mostly for unit testing.
void AddLengthConstraint(int min_len, int max_len);
int GetMinLength() const;
int GetMaxLength() const;
};
// Property definition of Boolean type.
class BooleanPropType
: public PropTypeBase<BooleanPropType, BooleanValue, bool> {
public:
// Overrides from the PropType base class.
BooleanPropType* GetBoolean() override { return this; }
BooleanPropType const* GetBoolean() const override { return this; }
};
// Parameter definition of Object type.
class ObjectPropType
: public PropTypeBase<ObjectPropType, ObjectValue, ValueMap> {
public:
using Base = PropTypeBase<ObjectPropType, ObjectValue, ValueMap>;
ObjectPropType();
// Overrides from the ParamType base class.
bool HasOverriddenAttributes() const override;
ObjectPropType* GetObject() override { return this; }
ObjectPropType const* GetObject() const override { return this; }
std::unique_ptr<PropType> Clone() const override;
std::unique_ptr<base::Value> ToJson(bool full_schema,
bool in_command_def) const override;
bool ObjectSchemaFromJson(const base::DictionaryValue* value,
const PropType* base_schema,
std::set<std::string>* processed_keys,
ErrorPtr* error) override;
// Returns a schema for Object-type parameter.
inline const ObjectSchema* GetObjectSchemaPtr() const {
return object_schema_.value.get();
}
void SetObjectSchema(std::unique_ptr<const ObjectSchema> schema);
private:
InheritableAttribute<std::unique_ptr<const ObjectSchema>> object_schema_;
};
// Parameter definition of Array type.
class ArrayPropType
: public PropTypeBase<ArrayPropType, ArrayValue, ValueVector> {
public:
using Base = PropTypeBase<ArrayPropType, ArrayValue, ValueVector>;
ArrayPropType();
// Overrides from the ParamType base class.
bool HasOverriddenAttributes() const override;
ArrayPropType* GetArray() override { return this; }
ArrayPropType const* GetArray() const override { return this; }
std::unique_ptr<PropType> Clone() const override;
std::unique_ptr<base::Value> ToJson(bool full_schema,
bool in_command_def) const override;
bool ObjectSchemaFromJson(const base::DictionaryValue* value,
const PropType* base_schema,
std::set<std::string>* processed_keys,
ErrorPtr* error) override;
// Returns a type for Array elements.
inline const PropType* GetItemTypePtr() const {
return item_type_.value.get();
}
void SetItemType(std::unique_ptr<const PropType> item_type);
private:
InheritableAttribute<std::unique_ptr<const PropType>> item_type_;
};
} // namespace weave
#endif // LIBWEAVE_SRC_COMMANDS_PROP_TYPES_H_