Mercurial > code
view cpp/json_util/json_util.hpp @ 655:a0239cca29fa
json_util: use std::string_view and pet doxygen
author | David Demelier <markand@malikania.fr> |
---|---|
date | Mon, 21 Jan 2019 20:39:31 +0100 |
parents | 87e1f4c7da76 |
children | 734ce3a26a58 |
line wrap: on
line source
/* * json_util.hpp -- utilities for JSON * * Copyright (c) 2019 David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef JSON_UTIL_HPP #define JSON_UTIL_HPP /** * \file json_util.hpp * \brief Utilities for JSON. */ #include <cstdint> #include <optional> #include <string> #include <json.hpp> /** * \brief Utilities for JSON. */ namespace json_util { /** * \brief Describe how to convert a JSON value. * * This traits must be specialized for every type you want to convert from JSON * to its native type. * * You only need to implement the get function with the following signature: * * ```cpp * static std::optional<T> get(const nlohmann::json& value); * ``` * * The implementation should not throw an exception but return a null optional * instead. * * This traits is already specialized for the given types: * * - bool * - double * - std::uint(8, 16, 32, 64)_t * - std::string */ template <typename T> struct type_traits; /** * \brief Specialization for `bool`. */ template <> struct type_traits<bool> { /** * Convert the JSON value to bool. * * \param value the value * \return the bool or empty if not a boolean type */ static auto get(const nlohmann::json& value) noexcept -> std::optional<bool>; }; /** * \brief Specialization for `double`. */ template <> struct type_traits<double> { /** * Convert the JSON value to bool. * * \param value the value * \return the double or empty if not a double type */ static auto get(const nlohmann::json& value) noexcept -> std::optional<double>; }; /** * \brief Specialization for `std::string`. */ template <> struct type_traits<std::string> { /** * Convert the JSON value to std::string. * * \param value the value * \return the string or empty if not a string type */ static auto get(const nlohmann::json& value) -> std::optional<std::string>; }; /** * \brief Specialization for `std::int8_t`. */ template <> struct type_traits<std::int8_t> { /** * Convert the JSON value to std::int8_t. * * \param value the value * \return the value or empty if value does not fit between the range */ static auto get(const nlohmann::json& value) -> std::optional<std::int8_t>; }; /** * \brief Specialization for `std::int16_t`. */ template <> struct type_traits<std::int16_t> { /** * Convert the JSON value to std::int16_t. * * \param value the value * \return the value or empty if value does not fit between the range */ static auto get(const nlohmann::json& value) -> std::optional<std::int16_t>; }; /** * \brief Specialization for `std::int32_t`. */ template <> struct type_traits<std::int32_t> { /** * Convert the JSON value to std::int32_t. * * \param value the value * \return the value or empty if value does not fit between the range */ static auto get(const nlohmann::json& value) -> std::optional<std::int32_t>; }; /** * \brief Specialization for `std::int64_t`. */ template <> struct type_traits<std::int64_t> { /** * Convert the JSON value to std::int64_t. * * \param value the value * \return the int or empty if not a int type */ static auto get(const nlohmann::json& value) noexcept -> std::optional<std::int64_t>; }; /** * \brief Specialization for `std::uint8_t`. */ template <> struct type_traits<std::uint8_t> { /** * Convert the JSON value to std::uint8_t. * * \param value the value * \return the value or empty if value does not fit between the range */ static auto get(const nlohmann::json& value) -> std::optional<std::uint8_t>; }; /** * \brief Specialization for `std::uint16_t`. */ template <> struct type_traits<std::uint16_t> { /** * Convert the JSON value to std::uint16_t. * * \param value the value * \return the value or empty if value does not fit between the range */ static auto get(const nlohmann::json& value) -> std::optional<std::uint16_t>; }; /** * \brief Specialization for `std::int32_t`. */ template <> struct type_traits<std::uint32_t> { /** * Convert the JSON value to std::uint32_t. * * \param value the value * \return the value or empty if value does not fit between the range */ static auto get(const nlohmann::json& value) -> std::optional<std::uint32_t>; }; /** * \brief Specialization for `std::uint64_t`. */ template <> struct type_traits<std::uint64_t> { /** * Convert the JSON value to std::uint64_t. * * \param value the value * \return the int or empty if not a int type */ static auto get(const nlohmann::json& value) noexcept -> std::optional<std::uint64_t>; }; /** * \brief Convenient JSON object parser * * This class helps destructuring insecure JSON input by returning optional * values if they are not present or invalid. */ class deserializer : public nlohmann::json { public: /** * Inherited constructor. */ using nlohmann::json::json; /** * Get a value from the document object. * * \param key the property key * \return the value or std::nullopt if not found or not convertible */ template <typename Type> auto get(std::string_view key) const noexcept -> std::optional<Type> { const auto it = find(key); if (it == end()) return std::nullopt; return type_traits<Type>::get(*it); } /** * Get a value from the document object or return def if: * * - Key is absent from the document * - Object property is not the same type * * \param key the property key * \param def the default value * \return the object or def * \throw any exception from nlohmann::json constructor */ template <typename Type, typename DefaultValue> auto get_or(std::string_view key, DefaultValue&& def) const -> Type { const auto it = find(key); if (it == end()) return std::forward<DefaultValue>(def); if (nlohmann::json(std::forward<DefaultValue>(def)).type() != it->type()) return std::forward<DefaultValue>(def); return it->get<Type>(); } /** * Get an optional value from the document object. * * If the value is undefined, the default value is returned. Otherwise, if * the value is not in the given type, std::nullopt is returned. * * \param key the property key * \param def the default value if property is undefined * \return the value, std::nullopt or def */ template <typename Type, typename DefaultValue> auto optional(std::string_view key, DefaultValue&& def) const noexcept -> std::optional<Type> { const auto it = find(key); if (it == end()) return std::optional<Type>(std::forward<DefaultValue>(def)); return type_traits<Type>::get(*it); } }; /** * Print the value as human readable. * * \note This only works on flat objects. * \param value the value * \param indent the optional indent for objects/arrays * \return the string */ auto pretty(const nlohmann::json& value, int indent = 4) -> std::string; } // !json_util #endif // !JSON_UTIL_HPP