diff --git a/include/ircd/json.h b/include/ircd/json.h index 636e58b35..eac1702fa 100644 --- a/include/ircd/json.h +++ b/include/ircd/json.h @@ -65,16 +65,34 @@ namespace ircd::json template string_view stringify(const mutable_buffer &&mb, T&&... t); template size_t print(char *const &buf, const size_t &max, T&&... t); template size_t print(const mutable_buffer &buf, T&&... t); - template std::string string(T&&... t); template struct buffer; + struct strung; size_t serialized(const string_view &); + struct string; using members = std::initializer_list; } +/// Strong type representing quoted strings in JSON (which may be unquoted +/// automatically when this type is encountered in a tuple etc) +struct ircd::json::string +:string_view +{ + using string_view::string_view; +}; + #include "json/array.h" #include "json/object.h" + +/// Convenience template to allocate std::string and print() arguments to it. +/// +struct ircd::json::strung +:std::string +{ + template strung(T&&... t); +}; + #include "json/value.h" #include "json/member.h" #include "json/property.h" @@ -153,13 +171,9 @@ ircd::json::print(char *const &buf, return sv.size(); } -/// -/// Convenience template using the syntax string(...) which returns -/// an std::string of the printed JSON -/// template -std::string -ircd::json::string(T&&... t) +ircd::json::strung::strung(T&&... t) +:std::string{[&]() -> std::string { const auto size { @@ -181,6 +195,8 @@ ircd::json::string(T&&... t) assert(printed == ret.size()); return ret; +}()} +{ } inline std::ostream & diff --git a/include/ircd/json/object.h b/include/ircd/json/object.h index 684d24382..4b47a8a8c 100644 --- a/include/ircd/json/object.h +++ b/include/ircd/json/object.h @@ -214,7 +214,7 @@ const try catch(const bad_lex_cast &e) { throw type_error("'%s' must cast to type %s", - string(path), + ircd::string(path), typeid(T).name()); } diff --git a/include/ircd/json/tuple.h b/include/ircd/json/tuple.h index f247ed49c..68fd342ef 100644 --- a/include/ircd/json/tuple.h +++ b/include/ircd/json/tuple.h @@ -625,7 +625,21 @@ template typename std::enable_if < - std::is_convertible::value, + std::is_base_of() && + std::is_convertible(), +void>::type +_assign(dst &d, + src&& s) +{ + d = unquote(string_view{std::forward(s)}); +} + +template +typename std::enable_if +< + !std::is_base_of() && + std::is_convertible(), void>::type _assign(dst &d, src&& s) @@ -914,7 +928,7 @@ template typename std::enable_if(), bool>::type defined(T&& t) { - return t != T{0}; + return t != typename std::remove_reference::type {0}; } template @@ -977,7 +991,7 @@ template std::ostream & operator<<(std::ostream &s, const tuple &t) { - s << json::string(t); + s << json::strung(t); return s; } diff --git a/ircd/json.cc b/ircd/json.cc index dac7fd889..399cb1ca4 100644 --- a/ircd/json.cc +++ b/ircd/json.cc @@ -315,7 +315,7 @@ ircd::json::printer::list_protocol(mutable_buffer &buffer, std::ostream & ircd::json::operator<<(std::ostream &s, const iov &iov) { - s << json::string(iov); + s << json::strung(iov); return s; } @@ -514,7 +514,7 @@ ircd::json::serialized(const member &member) std::ostream & ircd::json::operator<<(std::ostream &s, const object::member &member) { - s << json::string(member); + s << json::strung(member); return s; } @@ -538,7 +538,7 @@ ircd::json::serialized(const object::member &member) std::ostream & ircd::json::operator<<(std::ostream &s, const object &object) { - s << json::string(object); + s << json::strung(object); return s; } @@ -612,7 +612,7 @@ catch(const qi::expectation_failure &e) ircd::json::object::operator std::string() const { - return json::string(*this); + return json::strung(*this); } ircd::json::object::const_iterator @@ -730,7 +730,7 @@ ircd::json::array::stringify(mutable_buffer &buf, std::ostream & ircd::json::operator<<(std::ostream &s, const array &a) { - s << json::string(a); + s << json::strung(a); return s; } @@ -761,7 +761,7 @@ catch(const qi::expectation_failure &e) ircd::json::array::operator std::string() const { - return json::string(*this); + return json::strung(*this); } ircd::json::array::const_iterator @@ -817,7 +817,7 @@ const ircd::string_view ircd::json::value::empty_array {"[]"}; std::ostream & ircd::json::operator<<(std::ostream &s, const value &v) { - s << json::string(v); + s << json::strung(v); return s; } @@ -1104,7 +1104,7 @@ noexcept ircd::json::value::operator std::string() const { - return json::string(*this); + return json::strung(*this); } ircd::json::value::operator string_view() diff --git a/ircd/matrix.cc b/ircd/matrix.cc index a8c94a88b..fbeeee253 100644 --- a/ircd/matrix.cc +++ b/ircd/matrix.cc @@ -220,7 +220,7 @@ try modules.emplace("root.so"s, "root.so"s); - const auto options{json::string(json::members + const auto options{json::strung(json::members { { "name", "Chat Matrix" }, { "host", "0.0.0.0" }, diff --git a/modules/client/sync.cc b/modules/client/sync.cc index ec2ec317e..ca93596f5 100644 --- a/modules/client/sync.cc +++ b/modules/client/sync.cc @@ -379,20 +379,20 @@ update_sync_room(client &client, { std::vector state; if(defined(json::get<"state_key"_>(event))) - state.emplace_back(json::string(event)); + state.emplace_back(json::strung(event)); const auto state_serial { - json::string(state.data(), state.data() + state.size()) + json::strung(state.data(), state.data() + state.size()) }; std::vector timeline; if(!defined(json::get<"state_key"_>(event))) - timeline.emplace_back(json::string(event)); + timeline.emplace_back(json::strung(event)); const auto timeline_serial { - json::string(timeline.data(), timeline.data() + timeline.size()) + json::strung(timeline.data(), timeline.data() + timeline.size()) }; const json::members body @@ -401,7 +401,7 @@ update_sync_room(client &client, { "timeline", json::member { "events", timeline_serial } } }; - return json::string(body); + return json::strung(body); } std::string @@ -417,10 +417,10 @@ update_sync_rooms(client &client, r[0].emplace_back(update_sync_room(client, room, since, event)); m[0].emplace_back(room.room_id, r[0].back()); - const std::string join{json::string(m[0].data(), m[0].data() + m[0].size())}; - const std::string leave{json::string(m[1].data(), m[1].data() + m[1].size())}; - const std::string invite{json::string(m[2].data(), m[2].data() + m[2].size())}; - return json::string(json::members + const std::string join{json::strung(m[0].data(), m[0].data() + m[0].size())}; + const std::string leave{json::strung(m[1].data(), m[1].data() + m[1].size())}; + const std::string invite{json::strung(m[2].data(), m[2].data() + m[2].size())}; + return json::strung(json::members { { "join", join }, { "leave", leave }, @@ -481,19 +481,19 @@ initial_sync_room(client &client, { const m::event::query state_query { - { "room_id", room.room_id }, - { "state_key", "" }, + { "room_id", room.room_id }, + { "is_state", true }, }; m::events::for_each(state_query, [&state](const auto &event) { - state.emplace_back(json::string(event)); + state.emplace_back(json::strung(event)); }); } const auto state_serial { - json::string(state.data(), state.data() + state.size()) + json::strung(state.data(), state.data() + state.size()) }; std::vector timeline; @@ -509,7 +509,7 @@ initial_sync_room(client &client, return true; if(!defined(json::get<"state_key"_>(event))) - timeline.emplace_back(json::string(event)); + timeline.emplace_back(json::strung(event)); return false; }); @@ -517,7 +517,7 @@ initial_sync_room(client &client, const auto timeline_serial { - json::string(timeline.data(), timeline.data() + timeline.size()) + json::strung(timeline.data(), timeline.data() + timeline.size()) }; const json::members body @@ -526,7 +526,7 @@ initial_sync_room(client &client, { "timeline", json::member { "events", timeline_serial } } }; - return json::string(body); + return json::strung(body); } std::string @@ -560,10 +560,10 @@ initial_sync_rooms(client &client, m.at(i).emplace_back(room_id, r.at(i).back()); }); - const std::string join{json::string(m[0].data(), m[0].data() + m[0].size())}; - const std::string leave{json::string(m[1].data(), m[1].data() + m[1].size())}; - const std::string invite{json::string(m[2].data(), m[2].data() + m[2].size())}; - return json::string(json::members + const std::string join{json::strung(m[0].data(), m[0].data() + m[0].size())}; + const std::string leave{json::strung(m[1].data(), m[1].data() + m[1].size())}; + const std::string invite{json::strung(m[2].data(), m[2].data() + m[2].size())}; + return json::strung(json::members { { "join", join }, { "leave", leave },