diff options
author | Claudius "keldu" Holeksa <mail@keldu.de> | 2024-02-14 11:06:11 +0100 |
---|---|---|
committer | Claudius "keldu" Holeksa <mail@keldu.de> | 2024-02-14 11:06:11 +0100 |
commit | d6380ea2911800882e1470e4ce1172bbeabf5dd2 (patch) | |
tree | a45e451d9f8c2e676a4f44e7f6e822e50893fb55 /modules/codec-json | |
parent | d1d40903a582099762db04feeec451d7f0a617a8 (diff) |
codec-json: Prettified tuple encoding
Diffstat (limited to 'modules/codec-json')
-rw-r--r-- | modules/codec-json/c++/json.hpp | 26 | ||||
-rw-r--r-- | modules/codec-json/c++/json.tmpl.hpp | 120 | ||||
-rw-r--r-- | modules/codec-json/tests/codec-json.cpp | 32 |
3 files changed, 124 insertions, 54 deletions
diff --git a/modules/codec-json/c++/json.hpp b/modules/codec-json/c++/json.hpp index ad29acb..20342e3 100644 --- a/modules/codec-json/c++/json.hpp +++ b/modules/codec-json/c++/json.hpp @@ -59,6 +59,20 @@ public: return buffer_.read(i); } }; + +template<typename Encoding> +struct codec_config; + +template<> +struct codec_config<encode::Json> { + uint64_t depth = 16u; + uint64_t length = 4096u; + bool pretty = false; + + bool is_within(uint64_t bytes, uint64_t d){ + return bytes <= length && d <= depth; + } +}; } #include "json.tmpl.hpp" @@ -70,14 +84,8 @@ namespace saw { */ template<typename Schema> class codec<Schema, encode::Json> { -public: - struct config { - size_t depth = 16; - size_t length = 4096; - bool pretty = false; - }; private: - config cfg_; + codec_config<encode::Json> cfg_; public: /** * Default constructor @@ -87,7 +95,7 @@ public: /** * Constructor */ - codec(config cfg__):cfg_{std::move(cfg__)}{} + codec(const codec_config<encode::Json>& cfg__):cfg_{cfg_}{} SAW_FORBID_COPY(codec); SAW_DEFAULT_MOVE(codec); @@ -96,7 +104,7 @@ public: error_or<void> encode(const data<Schema, FromEncoding>& from_encode, data<Schema, encode::Json>& to_encode){ // To Be encoded buffer_view buff_v{to_encode.get_buffer()}; - auto eov = impl::json_encode<Schema, FromEncoding>::encode(from_encode, buff_v); + auto eov = impl::json_encode<Schema, FromEncoding>::encode(from_encode, buff_v, 0, cfg_.pretty); if(eov.is_error()){ return std::move(eov.get_error()); } diff --git a/modules/codec-json/c++/json.tmpl.hpp b/modules/codec-json/c++/json.tmpl.hpp index 11eba49..748f2c2 100644 --- a/modules/codec-json/c++/json.tmpl.hpp +++ b/modules/codec-json/c++/json.tmpl.hpp @@ -7,6 +7,34 @@ namespace saw { namespace impl { +struct json_helper { + static bool is_whitespace(int8_t ch) { + return ch == '\t' || ch == ' ' || ch == '\r' || ch == '\n'; + } + + static void skip_whitespace(buffer_view& buff) { + while(buff.read_composite_length() > 0 && json_helper::is_whitespace(buff.read())) { + buff.read_advance(1); + } + } + + static error_or<void> print_pretty_indent(buffer& to, uint64_t depth){ + { + auto eov = to.push(*reinterpret_cast<const uint8_t*>("\r\n"), 2); + if(!eov.template is_type<err::no_error>()){ + return eov; + } + } + for(uint64_t ind = 0; ind < depth; ++ind){ + auto eov_ele = to.push('\t'); + if(!eov_ele.template is_type<err::no_error>()){ + return eov_ele; + } + } + return void_t{}; + } +}; + template<typename Schema, typename FromEncode> class json_encode { static_assert(always_false<Schema, FromEncode>, "This schema type is not being handled by the json encoding."); @@ -16,7 +44,7 @@ template<typename T, size_t N, typename FromEncode> struct json_encode<schema::Primitive<T,N>, FromEncode> { using Schema = schema::Primitive<T,N>; - static error_or<void> encode(const data<Schema, FromEncode>& from, buffer& to) { + static error_or<void> encode(const data<Schema, FromEncode>& from, buffer& to, uint64_t, bool) { auto val = from.get(); std::array<uint8_t, 256> data; auto tc_result = std::to_chars(reinterpret_cast<char*>(data.data()), reinterpret_cast<char*>(data.data())+data.size(), val); @@ -49,7 +77,7 @@ template<typename FromEncode> struct json_encode<schema::String, FromEncode> { using Schema = schema::String; - static error_or<void> encode(const data<schema::String, FromEncode>& from, buffer& to) { + static error_or<void> encode(const data<schema::String, FromEncode>& from, buffer& to, uint64_t, bool) { { auto err = to.push('"'); if(!err.template is_type<err::no_error>()){ @@ -78,11 +106,19 @@ struct json_encode<schema::Tuple<T...>, FromEncode> { using Schema = schema::Tuple<T...>; template<size_t i> - static error_or<void> encode_element(const data<schema::Tuple<T...>, FromEncode>& from, buffer& to){ - auto eov = json_encode<typename parameter_pack_type<i, T...>::type, FromEncode>::encode(from.template get<i>(), to); + static error_or<void> encode_element(const data<schema::Tuple<T...>, FromEncode>& from, buffer& to, uint64_t depth, bool pretty){ + if(pretty){ + auto eov = json_helper::print_pretty_indent(to, depth); + if(eov.is_error()){ + return eov; + } + } + { + auto eov = json_encode<typename parameter_pack_type<i, T...>::type, FromEncode>::encode(from.template get<i>(), to, depth, pretty); - if(eov.is_error()){ - return eov; + if(eov.is_error()){ + return eov; + } } if constexpr ( (i+1) < sizeof...(T)){ @@ -93,26 +129,31 @@ struct json_encode<schema::Tuple<T...>, FromEncode> { } } { - auto eov_ele = encode_element<i+1>(from, to); + auto eov_ele = encode_element<i+1>(from, to, depth, pretty); if(eov_ele.is_error()){ return eov_ele; } } - - } return void_t{}; } - static error_or<void> encode(const data<Schema, FromEncode>& from, buffer& to) { + static error_or<void> encode(const data<Schema, FromEncode>& from, buffer& to, uint64_t depth, bool pretty) { { + auto err = to.push('['); if(!err.template is_type<err::no_error>()){ return err; } } if constexpr ( sizeof...(T) > 0 ){ - auto eov = encode_element<0>(from, to); + auto eov = encode_element<0>(from, to, depth+1u, pretty); + if(eov.is_error()){ + return eov; + } + } + if(pretty){ + auto eov = json_helper::print_pretty_indent(to, depth); if(eov.is_error()){ return eov; } @@ -133,9 +174,9 @@ struct json_encode<schema::Array<T,D>, FromEncode> { using Schema = schema::Array<T,D>; template<size_t Level> - static error_or<void> encode_level(const data<Schema, FromEncode>& from, buffer& to, std::array<std::size_t, D>& index){ + static error_or<void> encode_level(const data<Schema, FromEncode>& from, buffer& to, std::array<std::size_t, D>& index, uint64_t depth, bool pretty){ if constexpr (Level == D){ - auto eov = json_encode<T, FromEncode>::encode(from.at(index), to); + auto eov = json_encode<T, FromEncode>::encode(from.at(index), to, depth, pretty); if(eov.is_error()){ return eov; } @@ -155,7 +196,7 @@ struct json_encode<schema::Array<T,D>, FromEncode> { } { index[Level] = i; - auto eov = encode_level<Level+1>(from, to, index); + auto eov = encode_level<Level+1>(from, to, index, depth, pretty); if(eov.is_error()){ return eov; } @@ -171,9 +212,9 @@ struct json_encode<schema::Array<T,D>, FromEncode> { return void_t{}; } - static error_or<void> encode(const data<Schema, FromEncode>& from, buffer& to) { + static error_or<void> encode(const data<Schema, FromEncode>& from, buffer& to, uint64_t depth, bool pretty) { std::array<std::size_t, D> index; - return encode_level<0>(from, to, index); + return encode_level<0>(from, to, index, depth, pretty); } }; @@ -181,8 +222,8 @@ template<typename T, size_t... D, typename FromEncode> struct json_encode<schema::FixedArray<T,D...>, FromEncode> { using Schema = schema::FixedArray<T,D...>; - static error_or<void> encode_at(const data<Schema, FromEncode>& from, buffer& to, std::array<std::size_t, sizeof...(D)>& index){ - auto eov = json_encode<T, FromEncode>::encode(from.at(index), to); + static error_or<void> encode_at(const data<Schema, FromEncode>& from, buffer& to, std::array<std::size_t, sizeof...(D)>& index, uint64_t depth, bool pretty){ + auto eov = json_encode<T, FromEncode>::encode(from.at(index), to, depth, pretty); if(eov.is_error()){ return eov; } @@ -190,7 +231,7 @@ struct json_encode<schema::FixedArray<T,D...>, FromEncode> { } template<size_t Level, size_t Dim, size_t... DimPack> - static error_or<void> encode_level(const data<Schema, FromEncode>& from, buffer& to, std::array<std::size_t, sizeof...(D)>& index){ + static error_or<void> encode_level(const data<Schema, FromEncode>& from, buffer& to, std::array<std::size_t, sizeof...(D)>& index, uint64_t depth, bool pretty){ { auto err = to.push('['); if(!err.template is_type<err::no_error>()){ @@ -207,12 +248,12 @@ struct json_encode<schema::FixedArray<T,D...>, FromEncode> { { index[Level] = i; if constexpr (sizeof...(DimPack) > 0){ - auto eov = encode_level<Level+1, DimPack...>(from, to, index); + auto eov = encode_level<Level+1, DimPack...>(from, to, index, depth, pretty); if(eov.is_error()){ return eov; } }else{ - auto eov = encode_at(from,to,index); + auto eov = encode_at(from,to,index,depth,pretty); if(eov.is_error()){ return eov; } @@ -228,10 +269,10 @@ struct json_encode<schema::FixedArray<T,D...>, FromEncode> { return void_t{}; } - static error_or<void> encode(const data<Schema, FromEncode>& from, buffer& to) { + static error_or<void> encode(const data<Schema, FromEncode>& from, buffer& to, uint64_t depth, bool pretty) { if constexpr (sizeof...(D) > 0){ std::array<std::size_t, sizeof...(D)> index; - return encode_level<0,D...>(from, to, index); + return encode_level<0,D...>(from, to, index, depth+1u, pretty); } return void_t{}; } @@ -242,7 +283,7 @@ struct json_encode<schema::Struct<schema::Member<T,Key>...>, FromEncode> { using Schema = schema::Struct<schema::Member<T,Key>...>; template<size_t i> - static error_or<void> encode_element(const data<Schema, FromEncode>& from, buffer& to){ + static error_or<void> encode_element(const data<Schema, FromEncode>& from, buffer& to, uint64_t depth, bool pretty){ // Encode the name { std::string_view view = parameter_key_pack_type<i, Key...>::literal.view(); @@ -268,7 +309,7 @@ struct json_encode<schema::Struct<schema::Member<T,Key>...>, FromEncode> { } // Encode the value - auto eov = json_encode<typename parameter_pack_type<i, T...>::type, FromEncode>::encode(from.template get<parameter_key_pack_type<i, Key...>::literal>(), to); + auto eov = json_encode<typename parameter_pack_type<i, T...>::type, FromEncode>::encode(from.template get<parameter_key_pack_type<i, Key...>::literal>(), to, depth, pretty); // Go to the next element if constexpr ( (i+1) < sizeof...(T)){ @@ -279,7 +320,7 @@ struct json_encode<schema::Struct<schema::Member<T,Key>...>, FromEncode> { } } { - auto eov_ele = encode_element<i+1>(from, to); + auto eov_ele = encode_element<i+1>(from, to, depth, pretty); if(eov_ele.is_error()){ return eov_ele; } @@ -290,7 +331,7 @@ struct json_encode<schema::Struct<schema::Member<T,Key>...>, FromEncode> { return void_t{}; } - static error_or<void> encode(const data<Schema, FromEncode>& from, buffer& to) { + static error_or<void> encode(const data<Schema, FromEncode>& from, buffer& to, uint64_t depth, bool pretty) { { auto err = to.push('{'); if(!err.template is_type<err::no_error>()){ @@ -298,7 +339,7 @@ struct json_encode<schema::Struct<schema::Member<T,Key>...>, FromEncode> { } } if constexpr ( sizeof...(T) > 0 ){ - auto eov = encode_element<0>(from, to); + auto eov = encode_element<0>(from, to, depth, pretty); if(eov.is_error()){ return eov; } @@ -319,7 +360,7 @@ struct json_encode<schema::Union<schema::Member<T,Key>...>, FromEncode> { using Schema = schema::Union<schema::Member<T,Key>...>; template<size_t i> - static error_or<void> encode_element(const data<Schema, FromEncode>& from, buffer& to){ + static error_or<void> encode_element(const data<Schema, FromEncode>& from, buffer& to, uint64_t depth, bool pretty){ if(from.template holds_alternative<parameter_key_pack_type<i, Key...>::literal>()){ // Encode the name { @@ -346,12 +387,12 @@ struct json_encode<schema::Union<schema::Member<T,Key>...>, FromEncode> { } // Encode the value - auto eov = json_encode<typename parameter_pack_type<i, T...>::type, FromEncode>::encode(from.template get<parameter_key_pack_type<i, Key...>::literal>(), to); + auto eov = json_encode<typename parameter_pack_type<i, T...>::type, FromEncode>::encode(from.template get<parameter_key_pack_type<i, Key...>::literal>(), to, depth, pretty); } // Go to the next element if constexpr ( (i+1) < sizeof...(T)){ { - auto eov_ele = encode_element<i+1>(from, to); + auto eov_ele = encode_element<i+1>(from, to, depth, pretty); if(eov_ele.is_error()){ return eov_ele; } @@ -362,7 +403,7 @@ struct json_encode<schema::Union<schema::Member<T,Key>...>, FromEncode> { return void_t{}; } - static error_or<void> encode(const data<Schema, FromEncode>& from, buffer& to) { + static error_or<void> encode(const data<Schema, FromEncode>& from, buffer& to, uint64_t depth, bool pretty) { { auto err = to.push('{'); if(!err.template is_type<err::no_error>()){ @@ -370,7 +411,7 @@ struct json_encode<schema::Union<schema::Member<T,Key>...>, FromEncode> { } } if constexpr ( sizeof...(T) > 0 ){ - auto eov = encode_element<0>(from, to); + auto eov = encode_element<0>(from, to, depth, pretty); if(eov.is_error()){ return eov; } @@ -386,18 +427,6 @@ struct json_encode<schema::Union<schema::Member<T,Key>...>, FromEncode> { } }; -struct json_helper { - static bool is_whitespace(int8_t ch) { - return ch == '\t' || ch == ' ' || ch == '\r' || ch == '\n'; - } - - static void skip_whitespace(buffer_view& buff) { - while(buff.read_composite_length() > 0 && json_helper::is_whitespace(buff.read())) { - buff.read_advance(1); - } - } -}; - template<typename Schema, typename ToDecode> struct json_decode; @@ -667,6 +696,7 @@ struct json_decode<schema::Tuple<T...>, ToDecode> { return make_error<err::invalid_state>(); } buff.read_advance(1); + json_helper::skip_whitespace(buff); if(buff.read_composite_length() == 0){ return make_error<err::buffer_exhausted>(); } diff --git a/modules/codec-json/tests/codec-json.cpp b/modules/codec-json/tests/codec-json.cpp index 375d543..723e78c 100644 --- a/modules/codec-json/tests/codec-json.cpp +++ b/modules/codec-json/tests/codec-json.cpp @@ -352,4 +352,36 @@ SAW_TEST("Int64 read"){ typename native_data_type<schema::Int64>::type dec_val = -453; SAW_EXPECT( dec_val == native_int.get(), std::string{"Value is not being encoded correctly. Encoded: "} + std::to_string(static_cast<int>(native_int.get()))); } + +SAW_TEST("Tuple Pretty Encode and Decode"){ + using namespace saw; + data<schema::TestTuple, encode::Native> native_tup; + data<schema::TestTuple, encode::Json> json_tup; + + auto& nat_zero = native_tup.template get<0>(); + auto& nat_one = native_tup.template get<1>(); + + nat_zero.set("bar"); + nat_one.set(34); + + codec_config<encode::Json> json_config; + json_config.pretty = true; + codec<schema::TestTuple, encode::Json> json_codec{json_config}; + + error_or<void> eov = json_codec.encode(native_tup, json_tup); + SAW_EXPECT(eov.is_value(), "Encoding error"); + + std::string_view str_v = "[\r\n\t\"bar\",\r\n\t34\r\n]"; + std::string enc_val = convert_to_string(json_tup.get_buffer()); + + SAW_EXPECT(enc_val == str_v, std::string{"Tuple not encoded correctly. Encoded: "} + enc_val + std::string{" Expected: "} + std::string{str_v}); + native_tup = {}; + + eov = json_codec.decode(json_tup, native_tup); + SAW_EXPECT(eov.is_value(), "Decoding error"); + + SAW_EXPECT(native_tup.template get<0>() == "bar", "Invalid Value 0"); + SAW_EXPECT(native_tup.template get<1>().get() == 34, "Invalid Value 1"); + +} } |