Alex Vakulenko | 66ec292 | 2014-06-17 15:30:22 -0700 | [diff] [blame] | 1 | // Copyright 2014 The Chromium OS Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef BUFFET_COMMANDS_SCHEMA_UTILS_H_ |
| 6 | #define BUFFET_COMMANDS_SCHEMA_UTILS_H_ |
| 7 | |
| 8 | #include <limits> |
| 9 | #include <map> |
| 10 | #include <memory> |
| 11 | #include <string> |
| 12 | #include <type_traits> |
| 13 | #include <vector> |
| 14 | |
| 15 | #include <base/values.h> |
| 16 | |
| 17 | #include <buffet/error.h> |
| 18 | |
| 19 | namespace buffet { |
| 20 | |
| 21 | class PropValue; |
| 22 | class ObjectSchema; |
| 23 | |
| 24 | namespace native_types { |
| 25 | // C++ representation of object values. |
| 26 | using Object = std::map<std::string, std::shared_ptr<PropValue>>; |
| 27 | } // namespace native_types |
| 28 | // Converts an object to string. |
| 29 | std::string ToString(const native_types::Object& obj); |
| 30 | |
| 31 | // InheritableAttribute class is used for specifying various command parameter |
| 32 | // attributes that can be inherited from a base (parent) schema. |
| 33 | // The |value| still specifies the actual attribute values, whether it |
| 34 | // is inherited or overridden, while |is_inherited| can be used to identify |
| 35 | // if the attribute was inherited (true) or overridden (false). |
| 36 | template<typename T> |
| 37 | class InheritableAttribute { |
| 38 | public: |
| 39 | InheritableAttribute() = default; |
| 40 | explicit InheritableAttribute(T val) |
| 41 | : value(std::move(val)), is_inherited(true) {} |
| 42 | InheritableAttribute(T val, bool inherited) |
| 43 | : value(std::move(val)), is_inherited(inherited) {} |
| 44 | T value{}; |
| 45 | bool is_inherited{true}; |
| 46 | }; |
| 47 | |
| 48 | // A bunch of helper function to create base::Value for specific C++ classes, |
| 49 | // including vectors of types. These are used in template classes below |
| 50 | // to simplify specialization logic. |
| 51 | std::unique_ptr<base::Value> TypedValueToJson(bool value, ErrorPtr* error); |
| 52 | std::unique_ptr<base::Value> TypedValueToJson(int value, ErrorPtr* error); |
| 53 | std::unique_ptr<base::Value> TypedValueToJson(double value, ErrorPtr* error); |
| 54 | std::unique_ptr<base::Value> TypedValueToJson(const std::string& value, |
| 55 | ErrorPtr* error); |
| 56 | std::unique_ptr<base::Value> TypedValueToJson(const native_types::Object& value, |
| 57 | ErrorPtr* error); |
| 58 | template<typename T> |
| 59 | std::unique_ptr<base::Value> TypedValueToJson(const std::vector<T>& values, |
| 60 | ErrorPtr* error) { |
| 61 | std::unique_ptr<base::ListValue> list(new base::ListValue); |
| 62 | for (const auto& v : values) { |
| 63 | auto json = TypedValueToJson(v, error); |
| 64 | if (!json) |
| 65 | return std::unique_ptr<base::Value>(); |
| 66 | list->Append(json.release()); |
| 67 | } |
| 68 | return std::move(list); |
| 69 | } |
| 70 | |
| 71 | // Similarly to CreateTypedValue() function above, the following overloaded |
| 72 | // helper methods allow to extract specific C++ data types from base::Value. |
| 73 | // Also used in template classes below to simplify specialization logic. |
| 74 | bool TypedValueFromJson(const base::Value* value_in, |
| 75 | const ObjectSchema* object_schema, |
| 76 | bool* value_out, ErrorPtr* error); |
| 77 | bool TypedValueFromJson(const base::Value* value_in, |
| 78 | const ObjectSchema* object_schema, |
| 79 | int* value_out, ErrorPtr* error); |
| 80 | bool TypedValueFromJson(const base::Value* value_in, |
| 81 | const ObjectSchema* object_schema, |
| 82 | double* value_out, ErrorPtr* error); |
| 83 | bool TypedValueFromJson(const base::Value* value_in, |
| 84 | const ObjectSchema* object_schema, |
| 85 | std::string* value_out, ErrorPtr* error); |
| 86 | bool TypedValueFromJson(const base::Value* value_in, |
| 87 | const ObjectSchema* object_schema, |
| 88 | native_types::Object* value_out, ErrorPtr* error); |
| 89 | |
| 90 | bool operator==(const native_types::Object& obj1, |
| 91 | const native_types::Object& obj2); |
| 92 | |
| 93 | // CompareValue is a helper function to help with implementing EqualsTo operator |
| 94 | // for various data types. For most scalar types it is using operator==(), |
| 95 | // however, for floating point values, rounding errors in binary representation |
| 96 | // of IEEE floats/doubles can cause straight == comparison to fail for seemingly |
| 97 | // equivalent values. For these, use approximate comparison with the error |
| 98 | // margin equal to the epsilon value defined for the corresponding data type. |
| 99 | // This is used when looking up values for implementation of OneOf constraints |
| 100 | // which should work reliably for floating points also ("number" type). |
| 101 | |
| 102 | // Compare exact types using ==. |
| 103 | template<typename T> |
| 104 | inline typename std::enable_if<!std::is_floating_point<T>::value, bool>::type |
| 105 | CompareValue(const T& v1, const T& v2) { |
| 106 | return v1 == v2; |
| 107 | } |
| 108 | |
| 109 | // Compare non-exact types (such as double) using precision margin (epsilon). |
| 110 | template<typename T> |
| 111 | inline typename std::enable_if<std::is_floating_point<T>::value, bool>::type |
| 112 | CompareValue(const T& v1, const T& v2) { |
| 113 | return std::abs(v1 - v2) <= std::numeric_limits<T>::epsilon(); |
| 114 | } |
| 115 | |
| 116 | } // namespace buffet |
| 117 | |
| 118 | #endif // BUFFET_COMMANDS_SCHEMA_UTILS_H_ |