| // 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_CONSTRAINTS_H_ |
| #define LIBWEAVE_SRC_COMMANDS_PROP_CONSTRAINTS_H_ |
| |
| #include <string> |
| #include <type_traits> |
| #include <vector> |
| |
| #include <base/macros.h> |
| #include <base/values.h> |
| #include <weave/error.h> |
| |
| #include "src/commands/prop_values.h" |
| #include "src/commands/schema_constants.h" |
| #include "src/commands/schema_utils.h" |
| #include "src/string_utils.h" |
| |
| namespace weave { |
| |
| enum class ConstraintType { Min, Max, StringLengthMin, StringLengthMax, OneOf }; |
| |
| // Abstract base class for all parameter constraints. Many constraints are |
| // type-dependent. Thus, a numeric parameter could have "minimum" and/or |
| // "maximum" constraints specified. Some constraints, such as "OneOf" apply to |
| // any data type. |
| class Constraint { |
| public: |
| Constraint() = default; |
| virtual ~Constraint(); |
| |
| // Gets the constraint type. |
| virtual ConstraintType GetType() const = 0; |
| |
| // Checks if any of the constraint properties/attributes are overridden |
| // from their base schema definition. If the constraint is inherited, then |
| // it will not be written to JSON when saving partial schema. |
| virtual bool HasOverriddenAttributes() const = 0; |
| |
| // Validates a parameter against the constraint. Returns true if parameter |
| // value satisfies the constraint, otherwise fills the optional |error| with |
| // the details for the failure. |
| virtual bool Validate(const PropValue& value, ErrorPtr* error) const = 0; |
| |
| // Makes a full copy of this Constraint instance. |
| virtual std::unique_ptr<Constraint> Clone() const = 0; |
| |
| // Makes a copy of the constraint object, marking all the attributes |
| // as inherited from the original definition. |
| virtual std::unique_ptr<Constraint> CloneAsInherited() const = 0; |
| |
| // Saves the constraint into the specified JSON |dict| object, representing |
| // the object schema. If |overridden_only| is set to true, then the |
| // inherited constraints will not be added to the schema object. |
| virtual void AddToJsonDict(base::DictionaryValue* dict, |
| bool overridden_only) const; |
| |
| // Saves the value of constraint to JSON value. E.g., if the numeric |
| // constraint was defined as {"minimum":20} this will create a JSON value |
| // of 20. The current design implies that each constraint has one value |
| // only. If this assumption changes, this interface needs to be updated |
| // accordingly. |
| virtual std::unique_ptr<base::Value> ToJson() const = 0; |
| |
| // Overloaded by the concrete class implementation, it should return the |
| // JSON object property name to store the constraint's value as. |
| // E.g., if the numeric constraint was defined as {"minimum":20} this |
| // method should return "minimum". |
| virtual const char* GetDictKey() const = 0; |
| |
| protected: |
| // Static helper methods to format common constraint validation errors. |
| // They fill the |error| object with specific error message. |
| // Since these functions could be used by constraint objects for various |
| // data types, the values used in validation are expected to be |
| // send as strings already. |
| static bool ReportErrorLessThan(ErrorPtr* error, |
| const std::string& val, |
| const std::string& limit); |
| static bool ReportErrorGreaterThan(ErrorPtr* error, |
| const std::string& val, |
| const std::string& limit); |
| |
| static bool ReportErrorNotOneOf(ErrorPtr* error, |
| const std::string& val, |
| const std::vector<std::string>& values); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(Constraint); |
| }; |
| |
| // ConstraintMinMaxBase is a base class for numeric Minimum and Maximum |
| // constraints. |
| template <typename T> |
| class ConstraintMinMaxBase : public Constraint { |
| public: |
| explicit ConstraintMinMaxBase(const InheritableAttribute<T>& limit) |
| : limit_(limit) {} |
| explicit ConstraintMinMaxBase(const T& limit) : limit_(limit) {} |
| |
| // Implementation of Constraint::HasOverriddenAttributes(). |
| bool HasOverriddenAttributes() const override { return !limit_.is_inherited; } |
| |
| // Implementation of Constraint::ToJson(). |
| std::unique_ptr<base::Value> ToJson() const override { |
| return TypedValueToJson(limit_.value); |
| } |
| |
| // Stores the upper/lower value limit for maximum/minimum constraint. |
| // |limit_.is_inherited| indicates whether the constraint is inherited |
| // from base schema or overridden. |
| InheritableAttribute<T> limit_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConstraintMinMaxBase); |
| }; |
| |
| // Implementation of Minimum value constraint for Integer/Double types. |
| template <typename T> |
| class ConstraintMin : public ConstraintMinMaxBase<T> { |
| public: |
| explicit ConstraintMin(const InheritableAttribute<T>& limit) |
| : ConstraintMinMaxBase<T>(limit) {} |
| explicit ConstraintMin(const T& limit) : ConstraintMinMaxBase<T>(limit) {} |
| |
| // Implementation of Constraint::GetType(). |
| ConstraintType GetType() const override { return ConstraintType::Min; } |
| |
| // Implementation of Constraint::Validate(). |
| bool Validate(const PropValue& value, ErrorPtr* error) const override { |
| const T& v = static_cast<const TypedValueBase<T>&>(value).GetValue(); |
| if (v < this->limit_.value) { |
| return this->ReportErrorLessThan(error, std::to_string(v), |
| std::to_string(this->limit_.value)); |
| } |
| return true; |
| } |
| |
| // Implementation of Constraint::Clone(). |
| std::unique_ptr<Constraint> Clone() const override { |
| return std::unique_ptr<Constraint>{new ConstraintMin{this->limit_}}; |
| } |
| |
| // Implementation of Constraint::CloneAsInherited(). |
| std::unique_ptr<Constraint> CloneAsInherited() const override { |
| return std::unique_ptr<Constraint>{new ConstraintMin{this->limit_.value}}; |
| } |
| |
| // Implementation of Constraint::GetDictKey(). |
| const char* GetDictKey() const override { |
| return commands::attributes::kNumeric_Min; |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConstraintMin); |
| }; |
| |
| // Implementation of Maximum value constraint for Integer/Double types. |
| template <typename T> |
| class ConstraintMax : public ConstraintMinMaxBase<T> { |
| public: |
| explicit ConstraintMax(const InheritableAttribute<T>& limit) |
| : ConstraintMinMaxBase<T>(limit) {} |
| explicit ConstraintMax(const T& limit) : ConstraintMinMaxBase<T>(limit) {} |
| |
| // Implementation of Constraint::GetType(). |
| ConstraintType GetType() const override { return ConstraintType::Max; } |
| |
| // Implementation of Constraint::Validate(). |
| bool Validate(const PropValue& value, ErrorPtr* error) const override { |
| const T& v = static_cast<const TypedValueBase<T>&>(value).GetValue(); |
| if (v > this->limit_.value) |
| return this->ReportErrorGreaterThan(error, std::to_string(v), |
| std::to_string(this->limit_.value)); |
| return true; |
| } |
| |
| // Implementation of Constraint::Clone(). |
| std::unique_ptr<Constraint> Clone() const override { |
| return std::unique_ptr<Constraint>{new ConstraintMax{this->limit_}}; |
| } |
| |
| // Implementation of Constraint::CloneAsInherited(). |
| std::unique_ptr<Constraint> CloneAsInherited() const override { |
| return std::unique_ptr<Constraint>{new ConstraintMax{this->limit_.value}}; |
| } |
| |
| // Implementation of Constraint::GetDictKey(). |
| const char* GetDictKey() const override { |
| return commands::attributes::kNumeric_Max; |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConstraintMax); |
| }; |
| |
| // ConstraintStringLength is a base class for Minimum/Maximum string length |
| // constraints, similar to ConstraintMinMaxBase of numeric types. |
| class ConstraintStringLength : public Constraint { |
| public: |
| explicit ConstraintStringLength(const InheritableAttribute<int>& limit); |
| explicit ConstraintStringLength(int limit); |
| |
| // Implementation of Constraint::HasOverriddenAttributes(). |
| bool HasOverriddenAttributes() const override; |
| // Implementation of Constraint::ToJson(). |
| std::unique_ptr<base::Value> ToJson() const override; |
| |
| // Stores the upper/lower value limit for string length constraint. |
| // |limit_.is_inherited| indicates whether the constraint is inherited |
| // from base schema or overridden. |
| InheritableAttribute<int> limit_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConstraintStringLength); |
| }; |
| |
| // Implementation of Minimum string length constraint. |
| class ConstraintStringLengthMin : public ConstraintStringLength { |
| public: |
| explicit ConstraintStringLengthMin(const InheritableAttribute<int>& limit); |
| explicit ConstraintStringLengthMin(int limit); |
| |
| // Implementation of Constraint::GetType(). |
| ConstraintType GetType() const override { |
| return ConstraintType::StringLengthMin; |
| } |
| |
| // Implementation of Constraint::Validate(). |
| bool Validate(const PropValue& value, ErrorPtr* error) const override; |
| |
| // Implementation of Constraint::Clone(). |
| std::unique_ptr<Constraint> Clone() const override; |
| |
| // Implementation of Constraint::CloneAsInherited(). |
| std::unique_ptr<Constraint> CloneAsInherited() const override; |
| // Implementation of Constraint::GetDictKey(). |
| const char* GetDictKey() const override { |
| return commands::attributes::kString_MinLength; |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConstraintStringLengthMin); |
| }; |
| |
| // Implementation of Maximum string length constraint. |
| class ConstraintStringLengthMax : public ConstraintStringLength { |
| public: |
| explicit ConstraintStringLengthMax(const InheritableAttribute<int>& limit); |
| explicit ConstraintStringLengthMax(int limit); |
| |
| // Implementation of Constraint::GetType(). |
| ConstraintType GetType() const override { |
| return ConstraintType::StringLengthMax; |
| } |
| |
| // Implementation of Constraint::Validate(). |
| bool Validate(const PropValue& value, ErrorPtr* error) const override; |
| |
| // Implementation of Constraint::Clone(). |
| std::unique_ptr<Constraint> Clone() const override; |
| |
| // Implementation of Constraint::CloneAsInherited(). |
| std::unique_ptr<Constraint> CloneAsInherited() const override; |
| |
| // Implementation of Constraint::GetDictKey(). |
| const char* GetDictKey() const override { |
| return commands::attributes::kString_MaxLength; |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConstraintStringLengthMax); |
| }; |
| |
| // Implementation of OneOf constraint for different data types. |
| class ConstraintOneOf : public Constraint { |
| public: |
| explicit ConstraintOneOf(InheritableAttribute<ValueVector> set); |
| explicit ConstraintOneOf(ValueVector set); |
| |
| // Implementation of Constraint::GetType(). |
| ConstraintType GetType() const override { return ConstraintType::OneOf; } |
| |
| // Implementation of Constraint::HasOverriddenAttributes(). |
| bool HasOverriddenAttributes() const override { return !set_.is_inherited; } |
| |
| // Implementation of Constraint::Validate(). |
| bool Validate(const PropValue& value, ErrorPtr* error) const override; |
| |
| // Implementation of Constraint::Clone(). |
| std::unique_ptr<Constraint> Clone() const override; |
| |
| // Implementation of Constraint::CloneAsInherited(). |
| std::unique_ptr<Constraint> CloneAsInherited() const override; |
| |
| // Implementation of Constraint::ToJson(). |
| std::unique_ptr<base::Value> ToJson() const override; |
| |
| // Implementation of Constraint::GetDictKey(). |
| const char* GetDictKey() const override; |
| |
| // Stores the list of acceptable values for the parameter. |
| // |set_.is_inherited| indicates whether the constraint is inherited |
| // from base schema or overridden. |
| InheritableAttribute<ValueVector> set_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConstraintOneOf); |
| }; |
| |
| } // namespace weave |
| |
| #endif // LIBWEAVE_SRC_COMMANDS_PROP_CONSTRAINTS_H_ |