// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2018 Jason Volk // // 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 is present in all copies. The // full license for this software is available in the LICENSE file. #pragma once #define HAVE_IRCD_JSON_TUPLE_H #include "property.h" namespace ircd { namespace json { //TODO: sort template struct keys; /// All tuple templates inherit from this non-template type for tagging. struct tuple_base { // EBO tag }; /// A compile-time construct to describe a JSON object's members and types. /// /// Member access by name is O(1) because of recursive constexpr function /// inlining when translating a name to the index number which is then used /// as the template argument to std::get() for the value. /// /// Here we represent a JSON object with a named tuple, allowing the programmer /// to create a structure specifying all of the potentially valid members of the /// object. Thus at runtime, the tuple carries around its values like a /// `struct`. Unlike a `struct`, the tuple is abstractly iterable and we have /// implemented logic operating on all JSON tuples regardless of their makeup /// without any effort from a developer when creating a new tuple. /// /// The member structure for the tuple is called `property` because json::member /// is already used to pair together runtime oriented json::values. /// /// Create and use a tuple to efficiently extract members from a json::object. /// The tuple will populate its own members during a single-pass iteration of /// the JSON input. /// /// But remember, the tuple carries very little information for you at runtime /// which may make it difficult to represent all JS phenomena like "undefined" /// and "null". /// template struct tuple :std::tuple ,tuple_base { using tuple_type = std::tuple; using super_type = tuple; static constexpr size_t size() noexcept; operator json::value() const; operator crh::sha256::buf() const; /// For json::object constructions, the source JSON (string_view) is /// carried with the instance. This is important to convey additional /// keys not enumerated in the tuple. This will be default-initialized /// for other constructions when no source JSON buffer is available. json::object source; template constexpr decltype(auto) get(name&&) const noexcept; template constexpr decltype(auto) get(name&&) noexcept; template constexpr decltype(auto) at(name&&) const; template constexpr decltype(auto) at(name&&); template R get(name&&, R def = {}) const noexcept; template const R &at(name&&) const; template R &at(name&&); template explicit tuple(const tuple &); template explicit tuple(const json::object &, const json::keys &); template explicit tuple(const tuple &, const json::keys &); tuple(const json::object &); tuple(const json::iov &); tuple(const json::members &); tuple() = default; }; template constexpr bool is_tuple() noexcept { return std::is_base_of::value; } template using enable_if_tuple = typename std::enable_if(), R>::type; template using enable_if_tuple_and = typename std::enable_if() && test(), R>::type; template using tuple_type = typename tuple::tuple_type; template using tuple_size = std::tuple_size>; template using tuple_element = typename std::tuple_element>::type; template using tuple_value_type = typename tuple_element::value_type; template inline auto & stdcast(const tuple &o) { return static_cast(o); } template inline auto & stdcast(tuple &o) { return static_cast(o); } template constexpr enable_if_tuple size() noexcept { return tuple_size::value; } } // namespace json } // namespace ircd #include "key.h" #include "indexof.h" namespace ircd { namespace json { template inline enable_if_tuple &> val(tuple &t) noexcept { return static_cast &>(std::get(t)); } template inline enable_if_tuple &> val(const tuple &t) noexcept { return static_cast &>(std::get(t)); } template constexpr bool key_exists(const string_view &key) { return indexof(key) < size(); } } // namespace json } // namespace ircd #include "for_each.h" #include "until.h" #include "get.h" #include "at.h" #include "set.h" namespace ircd { namespace json { template template tuple::tuple(const json::object &object, const json::keys &keys) :source { object } { for(const auto &[key, val] : object) if(keys.has(key)) set(*this, key, val); } template tuple::tuple(const json::object &object) :source { object } { for(const auto &[key, val] : object) set(*this, key, val); } template tuple::tuple(const json::iov &iov) { for(const auto &[key, val] : iov) set(*this, key, val); } template tuple::tuple(const json::members &members) { for(const auto &[key, val] : members) set(*this, key, val); } template template tuple::tuple(const tuple &t, const keys &keys) :source { t.source } { for_each(t, [this, &keys] (const auto &key, const auto &val) { if(keys.has(key)) set(*this, key, val); }); } template template tuple::tuple(const tuple &t) :source { t.source } { for_each(t, [this] (const auto &key, const auto &val) { set(*this, key, val); }); } template template constexpr decltype(auto) tuple::at(name&& n) { constexpr const size_t hash { name_hash(n) }; return json::at(*this); } template template constexpr decltype(auto) tuple::at(name&& n) const { constexpr const size_t hash { name_hash(n) }; return json::at(*this); } template template constexpr decltype(auto) tuple::get(name&& n) noexcept { constexpr const size_t hash { name_hash(n) }; return json::get(*this); } template template constexpr decltype(auto) tuple::get(name&& n) const noexcept { constexpr const size_t hash { name_hash(n) }; return json::get(*this); } template template inline R tuple::get(name&& n, R ret) const noexcept { return json::get(*this, n, ret); } template template inline const R & tuple::at(name&& n) const { return json::at(*this, n); } template template inline R & tuple::at(name&& n) { return json::at(*this, n); } template constexpr size_t tuple::size() noexcept { return std::tuple_size(); } } // namespace json } // namespace ircd #include "_key_transform.h" #include "keys.h" #include "_member_transform.h" #include "tool.h" template ircd::json::tuple::operator crh::sha256::buf() const { //TODO: XXX const auto preimage { json::strung(*this) }; return crh::sha256::buf { [&preimage](auto &buf) { sha256{buf, const_buffer{preimage}}; } }; } template ircd::json::tuple::operator json::value() const { json::value ret; ret.type = OBJECT; ret.create_string(serialized(*this), [this] (mutable_buffer buffer) { stringify(buffer, *this); }); return ret; }