blob: 0c1d1b38569cbeea02ce0116b7a87110247de649 [file] [log] [blame]
Vitaly Buka4615e0d2015-10-14 15:35:12 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Alex Vakulenko66ec2922014-06-17 15:30:22 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Vitaly Buka912b6982015-07-06 11:13:03 -07005#ifndef LIBWEAVE_SRC_COMMANDS_SCHEMA_UTILS_H_
6#define LIBWEAVE_SRC_COMMANDS_SCHEMA_UTILS_H_
Alex Vakulenko66ec2922014-06-17 15:30:22 -07007
Taral Joglekar24391f02015-11-04 12:40:35 -08008#include <cmath>
Alex Vakulenko66ec2922014-06-17 15:30:22 -07009#include <limits>
10#include <map>
11#include <memory>
12#include <string>
13#include <type_traits>
14#include <vector>
15
Vitaly Buka0d501072015-08-18 18:09:46 -070016#include <base/logging.h>
Alex Vakulenko66ec2922014-06-17 15:30:22 -070017#include <base/values.h>
Vitaly Buka0801a1f2015-08-14 10:03:46 -070018#include <weave/error.h>
Alex Vakulenko66ec2922014-06-17 15:30:22 -070019
Vitaly Bukab6f015a2015-07-09 14:59:23 -070020namespace weave {
Alex Vakulenko66ec2922014-06-17 15:30:22 -070021
Alex Vakulenkoa32d83a2014-09-19 15:05:24 -070022class PropType;
Alex Vakulenko66ec2922014-06-17 15:30:22 -070023class PropValue;
24class ObjectSchema;
Anton Muhincfde8692014-11-25 03:36:59 +040025class ObjectValue;
Alex Vakulenko66ec2922014-06-17 15:30:22 -070026
Alex Vakulenko66ec2922014-06-17 15:30:22 -070027// C++ representation of object values.
Vitaly Buka774cdf52015-07-21 13:55:00 -070028using ValueMap = std::map<std::string, std::shared_ptr<const PropValue>>;
29
Alex Vakulenko29e64442015-03-20 13:59:19 -070030// C++ representation of array of values.
Vitaly Buka774cdf52015-07-21 13:55:00 -070031using ValueVector = std::vector<std::shared_ptr<const PropValue>>;
Alex Vakulenko29e64442015-03-20 13:59:19 -070032
Alex Vakulenko66ec2922014-06-17 15:30:22 -070033// Converts an object to string.
Vitaly Buka774cdf52015-07-21 13:55:00 -070034std::string ToString(const ValueMap& obj);
Alex Vakulenko66ec2922014-06-17 15:30:22 -070035
Alex Vakulenko29e64442015-03-20 13:59:19 -070036// Converts an array to string.
Vitaly Buka774cdf52015-07-21 13:55:00 -070037std::string ToString(const ValueVector& arr);
Alex Vakulenko29e64442015-03-20 13:59:19 -070038
Alex Vakulenko66ec2922014-06-17 15:30:22 -070039// InheritableAttribute class is used for specifying various command parameter
40// attributes that can be inherited from a base (parent) schema.
41// The |value| still specifies the actual attribute values, whether it
42// is inherited or overridden, while |is_inherited| can be used to identify
43// if the attribute was inherited (true) or overridden (false).
Vitaly Bukaa647c852015-07-06 14:51:01 -070044template <typename T>
Alex Vakulenko534a3122015-05-22 15:48:53 -070045class InheritableAttribute final {
Alex Vakulenko66ec2922014-06-17 15:30:22 -070046 public:
47 InheritableAttribute() = default;
48 explicit InheritableAttribute(T val)
49 : value(std::move(val)), is_inherited(true) {}
50 InheritableAttribute(T val, bool inherited)
51 : value(std::move(val)), is_inherited(inherited) {}
52 T value{};
53 bool is_inherited{true};
54};
55
56// A bunch of helper function to create base::Value for specific C++ classes,
57// including vectors of types. These are used in template classes below
58// to simplify specialization logic.
Vitaly Buka6942e1f2015-07-28 15:33:55 -070059std::unique_ptr<base::FundamentalValue> TypedValueToJson(bool value);
60std::unique_ptr<base::FundamentalValue> TypedValueToJson(int value);
61std::unique_ptr<base::FundamentalValue> TypedValueToJson(double value);
62std::unique_ptr<base::StringValue> TypedValueToJson(const std::string& value);
63std::unique_ptr<base::DictionaryValue> TypedValueToJson(const ValueMap& value);
64std::unique_ptr<base::ListValue> TypedValueToJson(const ValueVector& value);
Vitaly Bukaa647c852015-07-06 14:51:01 -070065template <typename T>
Vitaly Buka6942e1f2015-07-28 15:33:55 -070066std::unique_ptr<base::ListValue> TypedValueToJson(
67 const std::vector<T>& values) {
Alex Vakulenko66ec2922014-06-17 15:30:22 -070068 std::unique_ptr<base::ListValue> list(new base::ListValue);
69 for (const auto& v : values) {
Vitaly Buka6942e1f2015-07-28 15:33:55 -070070 auto json = TypedValueToJson(v);
71 CHECK(json);
Alex Vakulenko66ec2922014-06-17 15:30:22 -070072 list->Append(json.release());
73 }
Vitaly Buka39ef1952015-07-21 20:32:11 -070074 return list;
Alex Vakulenko66ec2922014-06-17 15:30:22 -070075}
76
Alex Vakulenkoa32d83a2014-09-19 15:05:24 -070077// Similarly to TypedValueToJson() function above, the following overloaded
Alex Vakulenko66ec2922014-06-17 15:30:22 -070078// helper methods allow to extract specific C++ data types from base::Value.
79// Also used in template classes below to simplify specialization logic.
Vitaly Bukad7be9052015-07-28 19:22:55 -070080// TODO(vitalybuka): Fix this. Interface is misleading. Seeing PropType internal
81// type validation is expected. In reality only ValueMap and ValueVector do
82// validation.
Alex Vakulenko66ec2922014-06-17 15:30:22 -070083bool TypedValueFromJson(const base::Value* value_in,
Alex Vakulenkod94656e2015-03-18 09:54:37 -070084 const PropType* type,
85 bool* value_out,
Vitaly Buka0801a1f2015-08-14 10:03:46 -070086 ErrorPtr* error);
Alex Vakulenko66ec2922014-06-17 15:30:22 -070087bool TypedValueFromJson(const base::Value* value_in,
Alex Vakulenkod94656e2015-03-18 09:54:37 -070088 const PropType* type,
89 int* value_out,
Vitaly Buka0801a1f2015-08-14 10:03:46 -070090 ErrorPtr* error);
Alex Vakulenko66ec2922014-06-17 15:30:22 -070091bool TypedValueFromJson(const base::Value* value_in,
Alex Vakulenkod94656e2015-03-18 09:54:37 -070092 const PropType* type,
93 double* value_out,
Vitaly Buka0801a1f2015-08-14 10:03:46 -070094 ErrorPtr* error);
Alex Vakulenko66ec2922014-06-17 15:30:22 -070095bool TypedValueFromJson(const base::Value* value_in,
Alex Vakulenkod94656e2015-03-18 09:54:37 -070096 const PropType* type,
97 std::string* value_out,
Vitaly Buka0801a1f2015-08-14 10:03:46 -070098 ErrorPtr* error);
Alex Vakulenko66ec2922014-06-17 15:30:22 -070099bool TypedValueFromJson(const base::Value* value_in,
Alex Vakulenkod94656e2015-03-18 09:54:37 -0700100 const PropType* type,
Vitaly Buka774cdf52015-07-21 13:55:00 -0700101 ValueMap* value_out,
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700102 ErrorPtr* error);
Alex Vakulenko29e64442015-03-20 13:59:19 -0700103bool TypedValueFromJson(const base::Value* value_in,
104 const PropType* type,
Vitaly Buka774cdf52015-07-21 13:55:00 -0700105 ValueVector* value_out,
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700106 ErrorPtr* error);
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700107
Vitaly Buka774cdf52015-07-21 13:55:00 -0700108bool operator==(const ValueMap& obj1, const ValueMap& obj2);
109bool operator==(const ValueVector& arr1, const ValueVector& arr2);
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700110
111// CompareValue is a helper function to help with implementing EqualsTo operator
112// for various data types. For most scalar types it is using operator==(),
113// however, for floating point values, rounding errors in binary representation
114// of IEEE floats/doubles can cause straight == comparison to fail for seemingly
115// equivalent values. For these, use approximate comparison with the error
116// margin equal to the epsilon value defined for the corresponding data type.
117// This is used when looking up values for implementation of OneOf constraints
118// which should work reliably for floating points also ("number" type).
119
120// Compare exact types using ==.
Vitaly Bukaa647c852015-07-06 14:51:01 -0700121template <typename T>
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700122inline typename std::enable_if<!std::is_floating_point<T>::value, bool>::type
123CompareValue(const T& v1, const T& v2) {
124 return v1 == v2;
125}
126
127// Compare non-exact types (such as double) using precision margin (epsilon).
Vitaly Bukaa647c852015-07-06 14:51:01 -0700128template <typename T>
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700129inline typename std::enable_if<std::is_floating_point<T>::value, bool>::type
130CompareValue(const T& v1, const T& v2) {
131 return std::abs(v1 - v2) <= std::numeric_limits<T>::epsilon();
132}
133
Vitaly Bukab6f015a2015-07-09 14:59:23 -0700134} // namespace weave
Alex Vakulenko66ec2922014-06-17 15:30:22 -0700135
Vitaly Buka912b6982015-07-06 11:13:03 -0700136#endif // LIBWEAVE_SRC_COMMANDS_SCHEMA_UTILS_H_