summaryrefslogtreecommitdiff
path: root/modules/codec-json
diff options
context:
space:
mode:
authorClaudius "keldu" Holeksa <mail@keldu.de>2023-12-04 12:18:14 +0100
committerClaudius "keldu" Holeksa <mail@keldu.de>2023-12-04 12:18:14 +0100
commita14896f9ed209dd3f9597722e5a5697bd7dbf531 (patch)
tree089ca5cbbd206d1921f8f6b53292f5bc1902ca5c /modules/codec-json
parent84ecdcbca9e55b1f57fbb832e12ff4fdbb86e7c9 (diff)
meta: Renamed folder containing source
Diffstat (limited to 'modules/codec-json')
-rw-r--r--modules/codec-json/.nix/derivation.nix30
-rw-r--r--modules/codec-json/SConscript38
-rw-r--r--modules/codec-json/SConstruct66
-rw-r--r--modules/codec-json/json.h120
-rw-r--r--modules/codec-json/json.tmpl.h734
5 files changed, 988 insertions, 0 deletions
diff --git a/modules/codec-json/.nix/derivation.nix b/modules/codec-json/.nix/derivation.nix
new file mode 100644
index 0000000..3738e43
--- /dev/null
+++ b/modules/codec-json/.nix/derivation.nix
@@ -0,0 +1,30 @@
+{ lib
+, stdenv
+, scons
+, clang-tools
+, version
+, forstio
+}:
+
+let
+
+in stdenv.mkDerivation {
+ pname = "forstio-codec-json";
+ inherit version;
+ src = ./..;
+
+ enableParallelBuilding = true;
+
+ nativeBuildInputs = [
+ scons
+ clang-tools
+ ];
+
+ buildInputs = [
+ forstio.core
+ forstio.async
+ forstio.codec
+ ];
+
+ outputs = ["out" "dev"];
+}
diff --git a/modules/codec-json/SConscript b/modules/codec-json/SConscript
new file mode 100644
index 0000000..772ac0b
--- /dev/null
+++ b/modules/codec-json/SConscript
@@ -0,0 +1,38 @@
+#!/bin/false
+
+import os
+import os.path
+import glob
+
+
+Import('env')
+
+dir_path = Dir('.').abspath
+
+# Environment for base library
+codec_json_env = env.Clone();
+
+codec_json_env.sources = sorted(glob.glob(dir_path + "/*.cpp"))
+codec_json_env.headers = sorted(glob.glob(dir_path + "/*.h"))
+
+env.sources += codec_json_env.sources;
+env.headers += codec_json_env.headers;
+
+## Shared lib
+objects_shared = []
+codec_json_env.add_source_files(objects_shared, codec_json_env.sources, shared=True);
+codec_json_env.library_shared = codec_json_env.SharedLibrary('#build/forstio-codec-json', [objects_shared]);
+
+## Static lib
+objects_static = []
+codec_json_env.add_source_files(objects_static, codec_json_env.sources, shared=False);
+codec_json_env.library_static = codec_json_env.StaticLibrary('#build/forstio-codec-json', [objects_static]);
+
+# Set Alias
+env.Alias('library_codec_json', [codec_json_env.library_shared, codec_json_env.library_static]);
+
+env.targets += ['library_codec_json'];
+
+# Install
+env.Install('$prefix/lib/', [codec_json_env.library_shared, codec_json_env.library_static]);
+env.Install('$prefix/include/forstio/codec/json/', [codec_json_env.headers]);
diff --git a/modules/codec-json/SConstruct b/modules/codec-json/SConstruct
new file mode 100644
index 0000000..edd5f57
--- /dev/null
+++ b/modules/codec-json/SConstruct
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+
+import sys
+import os
+import os.path
+import glob
+import re
+
+
+if sys.version_info < (3,):
+ def isbasestring(s):
+ return isinstance(s,basestring)
+else:
+ def isbasestring(s):
+ return isinstance(s, (str,bytes))
+
+def add_kel_source_files(self, sources, filetype, lib_env=None, shared=False, target_post=""):
+
+ if isbasestring(filetype):
+ dir_path = self.Dir('.').abspath
+ filetype = sorted(glob.glob(dir_path+"/"+filetype))
+
+ for path in filetype:
+ target_name = re.sub( r'(.*?)(\.cpp|\.c\+\+)', r'\1' + target_post, path )
+ if shared:
+ target_name+='.os'
+ sources.append( self.SharedObject( target=target_name, source=path ) )
+ else:
+ target_name+='.o'
+ sources.append( self.StaticObject( target=target_name, source=path ) )
+ pass
+
+def isAbsolutePath(key, dirname, env):
+ assert os.path.isabs(dirname), "%r must have absolute path syntax" % (key,)
+
+env_vars = Variables(
+ args=ARGUMENTS
+)
+
+env_vars.Add('prefix',
+ help='Installation target location of build results and headers',
+ default='/usr/local/',
+ validator=isAbsolutePath
+)
+
+env=Environment(ENV=os.environ, variables=env_vars, CPPPATH=[],
+ CPPDEFINES=['SAW_UNIX'],
+ CXXFLAGS=['-std=c++20','-g','-Wall','-Wextra'],
+ LIBS=['forstio-codec'])
+env.__class__.add_source_files = add_kel_source_files
+env.Tool('compilation_db');
+env.cdb = env.CompilationDatabase('compile_commands.json');
+
+env.objects = [];
+env.sources = [];
+env.headers = [];
+env.targets = [];
+
+Export('env')
+SConscript('SConscript')
+
+env.Alias('cdb', env.cdb);
+env.Alias('all', [env.targets]);
+env.Default('all');
+
+env.Alias('install', '$prefix')
diff --git a/modules/codec-json/json.h b/modules/codec-json/json.h
new file mode 100644
index 0000000..56cadc0
--- /dev/null
+++ b/modules/codec-json/json.h
@@ -0,0 +1,120 @@
+#pragma once
+
+#include <forstio/core/buffer.h>
+#include <forstio/core/common.h>
+#include <forstio/codec/data.h>
+
+#include <algorithm>
+
+namespace saw {
+namespace encode {
+struct Json {};
+}
+
+template<typename Schema>
+class data<Schema, encode::Json> {
+private:
+ ring_buffer buffer_;
+public:
+ data():buffer_{}{}
+
+ data(std::size_t ring_size_):buffer_{ring_size_}{}
+
+ data(ring_buffer buff_):
+ buffer_{std::move(buff_)}
+ {}
+
+ data(const std::string_view& view__):
+ buffer_{view__.size()}
+ {
+ auto ptr = reinterpret_cast<const uint8_t*>(view__.data());
+ if(!ptr){
+ return;
+ }
+ buffer_.push(*ptr, view__.size());
+ }
+
+ buffer& get_buffer(){
+ return buffer_;
+ }
+
+ const buffer& get_buffer() const {
+ return buffer_;
+ }
+
+ error push(uint8_t val){
+ return buffer_.push(val);
+ }
+
+ std::size_t get_size() const {
+ return buffer_.read_composite_length();
+ }
+
+ uint8_t& at(std::size_t i){
+ return buffer_.read(i);
+ }
+
+ const uint8_t& at(std::size_t i) const {
+ return buffer_.read(i);
+ }
+};
+}
+
+#include "json.tmpl.h"
+
+namespace saw {
+
+/**
+ * Codec class for json
+ */
+template<typename Schema>
+class codec<Schema, encode::Json> {
+public:
+ struct config {
+ size_t depth = 16;
+ size_t length = 1024;
+ };
+private:
+ config cfg_;
+public:
+ /**
+ * Default constructor
+ */
+ codec(){}
+
+ /**
+ * Constructor
+ */
+ codec(config cfg__):cfg_{std::move(cfg__)}{}
+
+ SAW_FORBID_COPY(codec);
+ SAW_DEFAULT_MOVE(codec);
+
+ template <typename FromEncoding>
+ 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, Schema, FromEncoding>::encode(from_encode, buff_v);
+ if(eov.is_error()){
+ return std::move(eov.get_error());
+ }
+ to_encode.get_buffer().write_advance(buff_v.write_offset());
+
+ return void_t{};
+ }
+
+ template <typename ToEncoding>
+ error_or<void> decode(data<Schema, encode::Json>& from_decode, data<Schema, ToEncoding>& to_decode){
+ buffer_view buff_v{from_decode.get_buffer()};
+
+ auto eov = impl::json_decode<Schema, Schema, ToEncoding>::decode(buff_v, to_decode);
+ if(eov.is_error()){
+ return std::move(eov.get_error());
+ }
+ from_decode.get_buffer().read_advance(buff_v.read_offset());
+
+ return void_t {};
+ }
+};
+}
+
diff --git a/modules/codec-json/json.tmpl.h b/modules/codec-json/json.tmpl.h
new file mode 100644
index 0000000..4b3a1a2
--- /dev/null
+++ b/modules/codec-json/json.tmpl.h
@@ -0,0 +1,734 @@
+#pragma once
+
+#include <charconv>
+#include <sstream>
+
+#include <iostream>
+
+namespace saw {
+namespace impl {
+template<typename Schema, typename RootSchema, typename FromEncode>
+class json_encode {
+ static_assert(always_false<Schema, RootSchema, FromEncode>, "This schema type is not being handled by the json encoding.");
+};
+
+template<typename T, size_t N, typename RootSchema, typename FromEncode>
+struct json_encode<schema::Primitive<T,N>, RootSchema, FromEncode> {
+ static error_or<void> encode(const data<schema::Primitive<T,N>, FromEncode>& from, buffer& to) {
+ 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);
+
+ if(tc_result.ec != std::errc{}){
+ return make_error<err::critical>();
+ }
+
+ size_t bytes_written = 0;
+ for(char* ptr = reinterpret_cast<char*>(data.data()); ptr != tc_result.ptr; ++ptr){
+ ++bytes_written;
+ }
+
+ auto& buff = to;
+ error err = buff.write_require_length(bytes_written);
+ if(!err.template is_type<err::no_error>()){
+ return std::move(err);
+ }
+
+ for(char* ptr = reinterpret_cast<char*>(data.data()); ptr != tc_result.ptr; ++ptr){
+ uint8_t* un_ptr = reinterpret_cast<uint8_t*>(ptr);
+ buff.push(un_ptr[0]);
+ }
+
+ return void_t{};
+ }
+};
+
+template<typename RootSchema, typename FromEncode>
+struct json_encode<schema::String, RootSchema, FromEncode> {
+ static error_or<void> encode(const data<schema::String, FromEncode>& from, buffer& to) {
+ {
+ auto err = to.push('"');
+ if(!err.template is_type<err::no_error>()){
+ return err;
+ }
+ }
+ for(std::size_t i = 0; i < from.size(); ++i){
+ auto err = to.push(from.get_at(i));
+ if(!err.template is_type<err::no_error>()){
+ return err;
+ }
+ }
+ {
+ auto err = to.push('"');
+ if(!err.template is_type<err::no_error>()){
+ return err;
+ }
+ }
+
+ return void_t{};
+ }
+};
+
+template<typename... T, typename RootSchema, typename FromEncode>
+struct json_encode<schema::Tuple<T...>, RootSchema, FromEncode> {
+ 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, RootSchema, FromEncode>::encode(from.template get<i>(), to);
+
+ if(eov.is_error()){
+ return eov;
+ }
+
+ if constexpr ( (i+1) < sizeof...(T)){
+ {
+ auto eov_ele = to.push(',');
+ if(!eov_ele.template is_type<err::no_error>()){
+ return eov_ele;
+ }
+ }
+ {
+ auto eov_ele = encode_element<i+1>(from, to);
+ if(eov_ele.is_error()){
+ return eov_ele;
+ }
+ }
+
+
+ }
+ return void_t{};
+ }
+
+ static error_or<void> encode(const data<schema::Tuple<T...>, FromEncode>& from, buffer& to) {
+ {
+ 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);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ {
+ auto err = to.push(']');
+ if(!err.template is_type<err::no_error>()){
+ return err;
+ }
+ }
+
+ return void_t{};
+ }
+};
+
+template<typename T, size_t D, typename RootSchema, typename FromEncode>
+struct json_encode<schema::Array<T,D>, RootSchema, FromEncode> {
+ template<size_t Level>
+ static error_or<void> encode_level(const data<schema::Array<T,D>, FromEncode>& from, buffer& to, std::array<std::size_t, D>& index){
+ if constexpr (Level == D){
+ auto eov = json_encode<T, RootSchema, FromEncode>::encode(from.at(index), to);
+ if(eov.is_error()){
+ return eov;
+ }
+ } else {
+ {
+ auto err = to.push('[');
+ if(!err.template is_type<err::no_error>()){
+ return err;
+ }
+ }
+ for(std::size_t i = 0; i < from.get_dim_size(Level); ++i){
+ if( i > 0 ){
+ auto err = to.push(',');
+ if(!err.template is_type<err::no_error>()){
+ return err;
+ }
+ }
+ {
+ index[Level] = i;
+ auto eov = encode_level<Level+1>(from, to, index);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ }
+ {
+ auto err = to.push(']');
+ if(!err.template is_type<err::no_error>()){
+ return err;
+ }
+ }
+ }
+ return void_t{};
+ }
+
+ static error_or<void> encode(const data<schema::Array<T,D>, FromEncode>& from, buffer& to) {
+ std::array<std::size_t, D> index;
+ return encode_level<0>(from, to, index);
+ }
+};
+
+template<typename... T, string_literal... Key, typename RootSchema, typename FromEncode>
+struct json_encode<schema::Struct<schema::Member<T,Key>...>, RootSchema, FromEncode> {
+
+ template<size_t i>
+ static error_or<void> encode_element(const data<schema::Struct<schema::Member<T,Key>...>, FromEncode>& from, buffer& to){
+ // Encode the name
+ {
+ std::string_view view = parameter_key_pack_type<i, Key...>::literal.view();
+ error err = to.push('"');
+ if(!err.template is_type<err::no_error>()){
+ return err;
+ }
+ err = to.push(*reinterpret_cast<const uint8_t *>(view.data()), view.size());
+ if(!err.template is_type<err::no_error>()){
+ return err;
+ }
+ err = to.push('"');
+ if(!err.template is_type<err::no_error>()){
+ return err;
+ }
+ }
+ // Add the separator
+ {
+ auto eov_ele = to.push(':');
+ if(!eov_ele.template is_type<err::no_error>()){
+ return eov_ele;
+ }
+ }
+
+ // Encode the value
+ auto eov = json_encode<typename parameter_pack_type<i, T...>::type, RootSchema, FromEncode>::encode(from.template get<parameter_key_pack_type<i, Key...>::literal>(), to);
+
+ // Go to the next element
+ if constexpr ( (i+1) < sizeof...(T)){
+ {
+ auto eov_ele = to.push(',');
+ if(!eov_ele.template is_type<err::no_error>()){
+ return eov_ele;
+ }
+ }
+ {
+ auto eov_ele = encode_element<i+1>(from, to);
+ if(eov_ele.is_error()){
+ return eov_ele;
+ }
+ }
+
+
+ }
+
+ return void_t{};
+ }
+ static error_or<void> encode(const data<schema::Struct<schema::Member<T,Key>...>, FromEncode>& from, buffer& to) {
+ {
+ 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);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ {
+ auto err = to.push('}');
+ if(!err.template is_type<err::no_error>()){
+ return err;
+ }
+ }
+
+ return void_t{};
+ }
+};
+
+template<typename... T, string_literal... Key, typename RootSchema, typename FromEncode>
+struct json_encode<schema::Union<schema::Member<T,Key>...>, RootSchema, FromEncode> {
+
+ template<size_t i>
+ static error_or<void> encode_element(const data<schema::Union<schema::Member<T,Key>...>, FromEncode>& from, buffer& to){
+ if(from.template holds_alternative<typename parameter_key_pack_type<i, Key...>::literal>()){
+ // Encode the name
+ {
+ std::string_view view = parameter_key_pack_type<i, Key...>::literal.view();
+ error err = to.push('"');
+ if(!err.template is_type<err::no_error>()){
+ return err;
+ }
+ err = to.push(*reinterpret_cast<const uint8_t *>(view.data()), view.size());
+ if(!err.template is_type<err::no_error>()){
+ return err;
+ }
+ err = to.push('"');
+ if(!err.template is_type<err::no_error>()){
+ return err;
+ }
+ }
+ // Add the separator
+ {
+ auto eov_ele = to.push(':');
+ if(!eov_ele.template is_type<err::no_error>()){
+ return eov_ele;
+ }
+ }
+
+ // Encode the value
+ auto eov = json_encode<typename parameter_pack_type<i, T...>::type, RootSchema, FromEncode>::encode(from.template get<parameter_key_pack_type<i, Key...>::literal>(), to);
+ }
+ // Go to the next element
+ if constexpr ( (i+1) < sizeof...(T)){
+ {
+ auto eov_ele = encode_element<i+1>(from, to);
+ if(eov_ele.is_error()){
+ return eov_ele;
+ }
+ }
+
+
+ }
+
+ return void_t{};
+ }
+ static error_or<void> encode(const data<schema::Union<schema::Member<T,Key>...>, FromEncode>& from, buffer& to) {
+ {
+ 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);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ {
+ auto err = to.push('}');
+ if(!err.template is_type<err::no_error>()){
+ return err;
+ }
+ }
+
+ return void_t{};
+ }
+};
+
+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 RootSchema, typename ToDecode>
+struct json_decode;
+
+template<typename T, size_t N, typename RootSchema, typename ToDecode>
+struct json_decode<schema::Primitive<T,N>, RootSchema, ToDecode> {
+ static error_or<void> decode(buffer_view& buff, data<schema::Primitive<T,N>, ToDecode>& to) {
+ assert(
+ ( buff.read() >= '0' && buff.read() <= '9')
+ || ( buff.read() == '+' || buff.read() == '-')
+ );
+
+ std::size_t offset = 0;
+
+ if (buff.read() == '-'){
+ ++offset;
+ } else if (buff.read() == '+'){
+ return make_error<err::not_supported>();
+ }
+ if (offset >= buff.read_composite_length()) {
+ return make_error<err::buffer_exhausted>();
+ }
+ if (buff.read(offset) >= '1' && buff.read(offset) <= '9') {
+ ++offset;
+
+ if(offset >= buff.read_composite_length()) {
+ return make_error<err::buffer_exhausted>();
+ }
+
+ while(1){
+ if (buff.read(offset) >= '0' && buff.read(offset) <= '9') {
+ ++offset;
+
+ if(offset >= buff.read_composite_length()) {
+ break;
+ }
+ continue;
+ }
+ break;
+ }
+ } else if (buff.read(offset) == '0' ) {
+ ++offset;
+ } else {
+ return make_error<err::buffer_exhausted>();
+ }
+
+ {
+ std::string_view num_view{reinterpret_cast<char*>(&buff.read()), offset};
+ typename native_data_type<schema::Primitive<T,N>>::type result;
+ auto fc_result = std::from_chars(num_view.data(), num_view.data() + num_view.size(), result);
+ if(fc_result.ec != std::errc{}){
+ return make_error<err::invalid_state>();
+ }
+
+ to.set(result);
+ }
+ buff.read_advance(offset);
+
+ return void_t{};
+ }
+};
+
+template<typename RootSchema, typename ToDecode>
+struct json_decode<schema::String, RootSchema, ToDecode> {
+ static error_or<void> decode(buffer_view& buff, data<schema::String, ToDecode>& to){
+ assert(buff.read() == '"');
+ buff.read_advance(1);
+
+ std::stringstream iss;
+ bool string_done = false;
+ while(!string_done){
+ if(buff.read_composite_length() == 0){
+ return make_error<err::buffer_exhausted>();
+ }
+
+ switch(buff.read()){
+ case '\\':{
+ buff.read_advance(1);
+ if(buff.read_composite_length() == 0){
+ return make_error<err::buffer_exhausted>();
+ }
+ switch(buff.read()){
+ case '\\':
+ case '/':
+ case '"':
+ iss<< buff.read();
+ break;
+ case 'b':
+ iss<<'\b';
+ break;
+ case 'f':
+ iss<<'\f';
+ break;
+ case 'n':
+ iss<<'\n';
+ break;
+ case 'r':
+ iss<<'\r';
+ break;
+ case 't':
+ iss<<'\t';
+ break;
+ case 'u': {
+ buff.read_advance(1);
+ if(buff.read_composite_length() < 4){
+ return make_error<err::buffer_exhausted>();
+ }
+ iss<<'?';
+ iss<<'?';
+ iss<<'?';
+ iss<<'?';
+
+ buff.read_advance(3);
+ } break;
+ }
+ } break;
+ case '"':
+ string_done = true;
+ break;
+ default:{
+ // Avoids Control sequences
+ if(buff.read() >= ' ' && buff.read() <= '~'){
+ iss<<buff.read();
+ }
+ // Avoid Unicode
+ else if (buff.read() < 0) {
+ do {
+ buff.read_advance(1);
+ if(buff.read_composite_length() == 0){
+ return make_error<err::buffer_exhausted>();
+ }
+ } while( buff.read() < 0 );
+ iss<<'?';
+ }
+ break;
+ }
+ }
+ buff.read_advance(1);
+ }
+
+ std::string raw = iss.str();
+ to.set(std::move(raw));
+
+ return void_t{};
+ }
+};
+
+template<typename... T, string_literal... Lits, typename RootSchema, typename ToDecode>
+struct json_decode<schema::Struct<schema::Member<T,Lits>...>, RootSchema, ToDecode> {
+ template<std::size_t i>
+ static error_or<void> decode_field_search(buffer_view& buff, data<schema::Struct<schema::Member<T,Lits>...>, ToDecode>& to, std::array<bool, sizeof...(T)>& fields, const data<schema::String,ToDecode>& search_name){
+ if constexpr ( i < sizeof...(T)){
+ using Type = typename parameter_pack_type<i, T...>::type;
+ constexpr static string_literal Literal = parameter_key_pack_type<i, Lits...>::literal;
+ if(search_name == Literal.view()){
+ if(fields[i]){
+ return make_error<err::invalid_state>();
+ }
+ fields[i] = true;
+ auto eov = json_decode<Type, RootSchema, ToDecode>::decode(buff, to.template get<Literal>());
+ if(eov.is_error()){
+ return eov;
+ }
+ }else {
+ decode_field_search<i+1>(buff, to, fields, search_name);
+ }
+ }else {
+ return make_error<err::invalid_state>();
+ }
+ return void_t{};
+ }
+
+ static error_or<void> decode_fields(buffer_view& buff, data<schema::Struct<schema::Member<T,Lits>...>, ToDecode>& to, std::array<bool, sizeof...(T)>& fields){
+ for(;;){
+ data<schema::String, ToDecode> name;
+ auto eov = json_decode<schema::String, RootSchema, ToDecode>::decode(buff, name);
+ if(eov.is_error()){
+ return eov;
+ }
+ json_helper::skip_whitespace(buff);
+ if(buff.read_composite_length() == 0){
+ return make_error<err::buffer_exhausted>();
+ }
+ if(buff.read() != ':'){
+ 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>();
+ }
+ {
+ auto eov = decode_field_search<0>(buff, to, fields, name);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ json_helper::skip_whitespace(buff);
+ if(buff.read_composite_length() == 0){
+ return make_error<err::buffer_exhausted>();
+ }
+ if(buff.read() == ','){
+ buff.read_advance(1);
+ }else if(buff.read() == '}'){
+ // If not all fields are set, the dataset is incomplete
+ for(auto& iter : fields){
+ if(!iter){
+ return make_error<err::invalid_state>();
+ }
+ }
+ buff.read_advance(1);
+ return void_t{};
+ }else{
+ return make_error<err::invalid_state>();
+ }
+ json_helper::skip_whitespace(buff);
+ if(buff.read_composite_length() == 0){
+ return make_error<err::buffer_exhausted>();
+ }
+ }
+ return void_t{};
+ }
+
+ static error_or<void> decode(buffer_view& buff, data<schema::Struct<schema::Member<T,Lits>...>, ToDecode>& to){
+ std::array<bool, sizeof...(T)> found_fields;
+ std::fill(found_fields.begin(), found_fields.end(), false);
+
+ assert(buff.read() == '{');
+ buff.read_advance(1);
+ json_helper::skip_whitespace(buff);
+ if(buff.read_composite_length() == 0){
+ return make_error<err::buffer_exhausted>();
+ }
+
+ // Check if there are no elements present in the JSON Struct
+ if(buff.read() == '}'){
+ if(sizeof...(T) > 0){
+ return make_error<err::invalid_state>();
+ }
+ buff.read_advance(1);
+ return void_t{};
+ }
+
+ auto eov = decode_fields(buff, to, found_fields);
+ if(eov.is_error()){
+ return eov;
+ }
+
+ return void_t{};
+ }
+};
+
+template<typename... T, typename RootSchema, typename ToDecode>
+struct json_decode<schema::Tuple<T...>, RootSchema, ToDecode> {
+ template<std::size_t i>
+ static error_or<void> decode_element(buffer_view& buff, data<schema::Tuple<T...>, ToDecode>& to){
+ if constexpr (i < sizeof...(T)){
+ if constexpr ( i > 0 ){
+ if(buff.read() != ','){
+ return make_error<err::invalid_state>();
+ }
+ buff.read_advance(1);
+ if(buff.read_composite_length() == 0){
+ return make_error<err::buffer_exhausted>();
+ }
+ }
+ using Type = typename parameter_pack_type<i, T...>::type;
+
+ auto eov = json_decode<Type, RootSchema, ToDecode>::decode(buff, to.template get<i>());
+ if(eov.is_error()){
+ return eov;
+ }
+ json_helper::skip_whitespace(buff);
+ if(buff.read_composite_length() == 0){
+ return make_error<err::buffer_exhausted>();
+ }
+
+ eov = decode_element<i+1>(buff, to);
+ if(eov.is_error()){
+ return eov;
+ }
+ }else{
+ if(buff.read() != ']'){
+ return make_error<err::invalid_state>();
+ }
+ buff.read_advance(1);
+ }
+ return void_t{};
+ }
+
+ static error_or<void> decode(buffer_view& buff, data<schema::Tuple<T...>, ToDecode>& to){
+ assert(buff.read() == '[');
+ buff.read_advance(1);
+
+ json_helper::skip_whitespace(buff);
+ if(buff.read_composite_length() == 0){
+ return make_error<err::buffer_exhausted>();
+ }
+
+ auto eov = decode_element<0>(buff, to);
+ if(eov.is_error()){
+ return eov;
+ }
+
+ return void_t{};
+ }
+};
+
+// The whole std::vector approach is hacky af. ToDo change it maybe?
+template<typename T, size_t D, typename RootSchema, typename ToDecode>
+struct json_decode<schema::Array<T,D>, RootSchema, ToDecode> {
+ template<size_t Level>
+ static error_or<void> decode_flat_level(buffer_view& buff, std::vector<data<T, encode::Native>>& to, std::array<std::size_t, D>& index, std::array<std::size_t, D>& dims, bool log_dim){
+ if constexpr (Level == D) {
+ json_helper::skip_whitespace(buff);
+ try {
+ to.push_back({});
+ }catch(std::exception& e){
+ return make_error<err::out_of_memory>();
+ }
+ auto eov = json_decode<T, RootSchema, ToDecode>::decode(buff, to.back());
+ if(eov.is_error()){
+ return eov;
+ }
+ } else {
+ assert(buff.read() == '[');
+ buff.read_advance(1);
+
+ json_helper::skip_whitespace(buff);
+ if ( buff.read_composite_length() == 0 ){
+ return make_error<err::buffer_exhausted>();
+ }
+
+ index[Level] = 0;
+ for(;;){
+ // We should have an element right now
+ auto eov = decode_flat_level<Level+1>(buff,to,index,dims, index[Level] == 0 && log_dim);
+ if(eov.is_error()){
+ return eov;
+ }
+ json_helper::skip_whitespace(buff);
+ if ( buff.read_composite_length() == 0 ){
+ return make_error<err::buffer_exhausted>();
+ }
+
+ ++index[Level];
+ if(buff.read() == ','){
+ buff.read_advance(1);
+ } else if(buff.read() == ']'){
+ buff.read_advance(1);
+ break;
+ } else {
+ return make_error<err::invalid_state>();
+ }
+ json_helper::skip_whitespace(buff);
+ if ( buff.read_composite_length() == 0 ){
+ return make_error<err::buffer_exhausted>();
+ }
+ }
+ if(log_dim){
+ dims[Level] = index[Level];
+ }else if (dims[Level] != index[Level]){
+ return make_error<err::invalid_state>();
+ }
+ }
+ return void_t{};
+ }
+
+ template<std::size_t Level>
+ static error_or<void> decode_unflat_level(std::vector<data<T,encode::Native>>& flat, data<schema::Array<T,D>, ToDecode>& to, std::array<std::size_t, D>& index, std::size_t& flat_index) {
+ if constexpr ( Level == D ){
+ auto& flat_data = flat.at(flat_index);
+ to.at(index) = std::move(flat_data);
+ ++flat_index;
+ }else {
+ const std::size_t dim_size = to.get_dim_size(Level);
+ for(index[Level] = 0; index[Level] < dim_size; ++index[Level]){
+
+ auto eov = decode_unflat_level<Level+1>(flat, to, index, flat_index);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ }
+ return void_t{};
+ }
+
+ static error_or<void> decode(buffer_view& buff, data<schema::Array<T,D>, ToDecode>& to){
+ std::array<std::size_t, D> index;
+ std::array<std::size_t, D> dims;
+ std::fill(dims.begin(), dims.end(), 0);
+ std::vector<data<T,encode::Native>> flat_array;
+ auto eov = decode_flat_level<0>(buff, flat_array, index, dims, true);
+ if(eov.is_error()){
+ return eov;
+ }
+
+ to = {dims};
+ std::size_t flat_index = 0;
+
+ return decode_unflat_level<0>(flat_array, to, index, flat_index);
+ }
+};
+}
+}