blob: 0c1d1b38569cbeea02ce0116b7a87110247de649 [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_SCHEMA_UTILS_H_
#define LIBWEAVE_SRC_COMMANDS_SCHEMA_UTILS_H_
#include <cmath>
#include <limits>
#include <map>
#include <memory>
#include <string>
#include <type_traits>
#include <vector>
#include <base/logging.h>
#include <base/values.h>
#include <weave/error.h>
namespace weave {
class PropType;
class PropValue;
class ObjectSchema;
class ObjectValue;
// C++ representation of object values.
using ValueMap = std::map<std::string, std::shared_ptr<const PropValue>>;
// C++ representation of array of values.
using ValueVector = std::vector<std::shared_ptr<const PropValue>>;
// Converts an object to string.
std::string ToString(const ValueMap& obj);
// Converts an array to string.
std::string ToString(const ValueVector& arr);
// InheritableAttribute class is used for specifying various command parameter
// attributes that can be inherited from a base (parent) schema.
// The |value| still specifies the actual attribute values, whether it
// is inherited or overridden, while |is_inherited| can be used to identify
// if the attribute was inherited (true) or overridden (false).
template <typename T>
class InheritableAttribute final {
public:
InheritableAttribute() = default;
explicit InheritableAttribute(T val)
: value(std::move(val)), is_inherited(true) {}
InheritableAttribute(T val, bool inherited)
: value(std::move(val)), is_inherited(inherited) {}
T value{};
bool is_inherited{true};
};
// A bunch of helper function to create base::Value for specific C++ classes,
// including vectors of types. These are used in template classes below
// to simplify specialization logic.
std::unique_ptr<base::FundamentalValue> TypedValueToJson(bool value);
std::unique_ptr<base::FundamentalValue> TypedValueToJson(int value);
std::unique_ptr<base::FundamentalValue> TypedValueToJson(double value);
std::unique_ptr<base::StringValue> TypedValueToJson(const std::string& value);
std::unique_ptr<base::DictionaryValue> TypedValueToJson(const ValueMap& value);
std::unique_ptr<base::ListValue> TypedValueToJson(const ValueVector& value);
template <typename T>
std::unique_ptr<base::ListValue> TypedValueToJson(
const std::vector<T>& values) {
std::unique_ptr<base::ListValue> list(new base::ListValue);
for (const auto& v : values) {
auto json = TypedValueToJson(v);
CHECK(json);
list->Append(json.release());
}
return list;
}
// Similarly to TypedValueToJson() function above, the following overloaded
// helper methods allow to extract specific C++ data types from base::Value.
// Also used in template classes below to simplify specialization logic.
// TODO(vitalybuka): Fix this. Interface is misleading. Seeing PropType internal
// type validation is expected. In reality only ValueMap and ValueVector do
// validation.
bool TypedValueFromJson(const base::Value* value_in,
const PropType* type,
bool* value_out,
ErrorPtr* error);
bool TypedValueFromJson(const base::Value* value_in,
const PropType* type,
int* value_out,
ErrorPtr* error);
bool TypedValueFromJson(const base::Value* value_in,
const PropType* type,
double* value_out,
ErrorPtr* error);
bool TypedValueFromJson(const base::Value* value_in,
const PropType* type,
std::string* value_out,
ErrorPtr* error);
bool TypedValueFromJson(const base::Value* value_in,
const PropType* type,
ValueMap* value_out,
ErrorPtr* error);
bool TypedValueFromJson(const base::Value* value_in,
const PropType* type,
ValueVector* value_out,
ErrorPtr* error);
bool operator==(const ValueMap& obj1, const ValueMap& obj2);
bool operator==(const ValueVector& arr1, const ValueVector& arr2);
// CompareValue is a helper function to help with implementing EqualsTo operator
// for various data types. For most scalar types it is using operator==(),
// however, for floating point values, rounding errors in binary representation
// of IEEE floats/doubles can cause straight == comparison to fail for seemingly
// equivalent values. For these, use approximate comparison with the error
// margin equal to the epsilon value defined for the corresponding data type.
// This is used when looking up values for implementation of OneOf constraints
// which should work reliably for floating points also ("number" type).
// Compare exact types using ==.
template <typename T>
inline typename std::enable_if<!std::is_floating_point<T>::value, bool>::type
CompareValue(const T& v1, const T& v2) {
return v1 == v2;
}
// Compare non-exact types (such as double) using precision margin (epsilon).
template <typename T>
inline typename std::enable_if<std::is_floating_point<T>::value, bool>::type
CompareValue(const T& v1, const T& v2) {
return std::abs(v1 - v2) <= std::numeric_limits<T>::epsilon();
}
} // namespace weave
#endif // LIBWEAVE_SRC_COMMANDS_SCHEMA_UTILS_H_