summaryrefslogtreecommitdiff
path: root/modules/tools
diff options
context:
space:
mode:
Diffstat (limited to 'modules/tools')
-rw-r--r--modules/tools/.nix/derivation.nix31
-rw-r--r--modules/tools/SConscript32
-rw-r--r--modules/tools/SConstruct71
-rw-r--r--modules/tools/c_gen_iface.cpp11
-rw-r--r--modules/tools/c_gen_iface.hpp535
-rw-r--r--modules/tools/cli_analyzer.hpp114
6 files changed, 794 insertions, 0 deletions
diff --git a/modules/tools/.nix/derivation.nix b/modules/tools/.nix/derivation.nix
new file mode 100644
index 0000000..6e3fbe1
--- /dev/null
+++ b/modules/tools/.nix/derivation.nix
@@ -0,0 +1,31 @@
+{ lib
+, stdenv
+, scons
+, clang-tools
+, version
+, forstio
+}:
+
+let
+
+in stdenv.mkDerivation {
+ pname = "forstio-tools";
+ inherit version;
+ src = ./..;
+
+ enableParallelBuilding = true;
+
+ nativeBuildInputs = [
+ scons
+ clang-tools
+ ];
+
+ buildInputs = [
+ forstio.core
+ forstio.async
+ forstio.io
+ forstio.codec
+ ];
+
+ outputs = ["out" "dev"];
+}
diff --git a/modules/tools/SConscript b/modules/tools/SConscript
new file mode 100644
index 0000000..7c9efd7
--- /dev/null
+++ b/modules/tools/SConscript
@@ -0,0 +1,32 @@
+#!/bin/false
+
+import os
+import os.path
+import glob
+
+
+Import('env')
+
+dir_path = Dir('.').abspath
+
+# Environment for base library
+tools_env = env.Clone();
+
+tools_env.sources = sorted(glob.glob(dir_path + "/*.cpp"))
+tools_env.headers = sorted(glob.glob(dir_path + "/*.h"))
+
+env.sources += tools_env.sources;
+env.headers += tools_env.headers;
+
+## Static lib
+objects_static = []
+tools_env.add_source_files(objects_static, tools_env.sources, shared=False);
+tools_env.c_array_example = tools_env.Program('#build/forstio-c-array-example', [objects_static]);
+
+# Set Alias
+env.Alias('tools_c_array_example', [tools_env.c_array_example]);
+
+env.targets += ['tools_c_array_example'];
+
+# Install
+env.Install('$prefix/bin/', [tools_env.c_array_example]);
diff --git a/modules/tools/SConstruct b/modules/tools/SConstruct
new file mode 100644
index 0000000..9a02291
--- /dev/null
+++ b/modules/tools/SConstruct
@@ -0,0 +1,71 @@
+#!/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-core',
+ 'forstio-async',
+ '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/tools/c_gen_iface.cpp b/modules/tools/c_gen_iface.cpp
new file mode 100644
index 0000000..996f3c3
--- /dev/null
+++ b/modules/tools/c_gen_iface.cpp
@@ -0,0 +1,11 @@
+#include "c_gen_iface.hpp"
+
+int main(){
+ // saw::generate_array_example();
+
+ auto eov = saw::generate_iface_example();
+ if(eov.is_error()){
+ return -1;
+ }
+ return 0;
+}
diff --git a/modules/tools/c_gen_iface.hpp b/modules/tools/c_gen_iface.hpp
new file mode 100644
index 0000000..e79e27f
--- /dev/null
+++ b/modules/tools/c_gen_iface.hpp
@@ -0,0 +1,535 @@
+#include <forstio/core/error.h>
+#include <forstio/core/templates.h>
+#include <forstio/codec/schema.h>
+
+#include <string>
+#include <sstream>
+#include <map>
+
+#include <iostream>
+
+#include <forstio/codec/schema_stringify.h>
+
+namespace saw {
+
+namespace impl {
+/**
+ * Type meant to provide future help if I decide to introduce more maps
+ */
+struct c_types {
+ struct c_member {
+ std::string key;
+ std::string name;
+ bool is_primitive;
+ };
+
+ struct c_struct {
+ std::string kind;
+ std::string type;
+ std::string cpp_schema;
+ std::vector<c_member> members;
+ };
+
+ struct c_response {
+ std::string key;
+ bool is_primitive;
+ };
+
+ struct c_func {
+ std::string cpp_schema;
+ std::string cpp_name;
+ c_response response;
+ std::vector<c_member> requests;
+ };
+
+ using c_struct_map = std::map<std::string, c_struct>;
+ using c_func_map = std::map<std::string, c_func>;
+
+ struct state {
+ std::string interface_schema;
+ c_struct_map struct_map;
+ c_func_map func_map;
+ std::string prefix;
+ std::string postfix;
+ std::string encoding;
+ };
+};
+
+namespace schema {
+using namespace saw::schema;
+/**
+Pseudo flattened
+using Foo = Struct<
+ Member<Array<Int32>, "a">
+ Member<Array<Float32>, "b">
+>;
+
+Needs to be flattened to
+
+template<typename InnerSchema>
+using FlattenedSchemaElement = Struct<
+ Member<Array<String>, "path">,
+ Member<InnerSchema, "inner_schema">
+>;
+
+// Illegal, but doable with more lines of code
+// Just use typename... T and
+// "T..." for
+// "Member<FlattenedSchemaElement<Ele>,Names>...>"
+// and specialize somewhere else
+template<typename... Ele, string_literal... Names>
+using FlattenedSchema = Struct<
+ Member<String, "top_schema">,
+ Member<FlattenedSchemaElement<Ele>, Names>...
+>;
+ */
+template<typename T>
+struct schema_flattener {
+ static_assert(always_false<T>, "Not supported");
+};
+
+template<typename... T, string_literal... Names>
+struct schema_flattener<schema::Struct<schema::Member<T,Names>...>> {
+
+};
+
+>;
+
+using StructBindingSchema = Struct<
+ Member<String, "kind">,
+ Member<String, "key">,
+ Member<String, "cpp_schema">,
+ Member<Array<String>, "members">
+>;
+
+using FunctionBindingSchema = Struct<
+ Member<String, "cpp_schema">,
+ Member<String, "name">,
+ Member<String, "foo">
+>;
+
+using BindingSchema = Struct<
+ Member<String, "interface_schema">,
+ Member<String, "prefix">,
+ Member<String, "postfix">,
+ Member<String, "encoding">,
+ Member<Array<StructBindingSchema>, "structs">,
+ Member<Array<FunctionBindingSchema>, "functions">
+>;
+}
+
+/**
+ * Helper to determine if we are dealing with primitive types
+ */
+template<typename Schema>
+struct c_is_primitive {
+ static constexpr bool value = false;
+};
+
+template<typename T, size_t N>
+struct c_is_primitive<schema::Primitive<T,N>> {
+ static constexpr bool value = true;
+};
+
+template<typename Schema>
+struct c_primitive_string {
+ static_assert(always_false<Schema>, "Not supported");
+};
+
+template<>
+struct c_primitive_string<schema::Int8> {
+ static constexpr std::string_view value = "int8_t";
+};
+
+template<>
+struct c_primitive_string<schema::Int16> {
+ static constexpr std::string_view value = "int16_t";
+};
+
+template<>
+struct c_primitive_string<schema::Int32> {
+ static constexpr std::string_view value = "int32_t";
+};
+
+template<>
+struct c_primitive_string<schema::Int64> {
+ static constexpr std::string_view value = "int64_t";
+};
+
+template<>
+struct c_primitive_string<schema::UInt8> {
+ static constexpr std::string_view value = "uint8_t";
+};
+
+template<>
+struct c_primitive_string<schema::UInt16> {
+ static constexpr std::string_view value = "uint16_t";
+};
+
+template<>
+struct c_primitive_string<schema::UInt32> {
+ static constexpr std::string_view value = "uint32_t";
+};
+
+template<>
+struct c_primitive_string<schema::UInt64> {
+ static constexpr std::string_view value = "uint64_t";
+};
+
+template<>
+struct c_primitive_string<schema::Float32> {
+ static constexpr std::string_view value = "float";
+};
+
+template<>
+struct c_primitive_string<schema::Float64> {
+ static constexpr std::string_view value = "double";
+};
+
+template<typename Schema>
+struct c_data_translater {
+ static_assert(always_false<Schema>, "Not supported");
+};
+
+template<typename T, size_t N>
+struct c_data_translater<schema::Primitive<T,N>> {
+ using StructMap = typename c_types::c_struct_map;
+ using Schema = schema::Primitive<T,N>;
+
+ static error_or<void> generate(c_types::state& c_state, std::string& str){
+ (void) c_state;
+ str += c_primitive_string<Schema>::value;
+ return void_t{};
+ }
+};
+
+template<typename T, size_t Dim>
+struct c_data_translater<schema::Array<T,Dim>> {
+ using Schema = schema::Array<T,Dim>;
+ using StructMap = typename c_types::c_struct_map;
+
+ static error_or<void> generate(c_types::state& c_state, std::string& type_str){
+ type_str = "array_";
+
+ std::string inner_type_str;
+ auto eov = impl::c_data_translater<T>::generate(c_state, inner_type_str);
+ if(eov.is_error()){
+ return eov;
+ }
+
+ type_str += inner_type_str;
+
+ if(Dim > 1){
+ type_str += "_";
+ type_str += std::to_string(Dim);
+ type_str += "d";
+ }
+
+ if(c_state.struct_map.find(type_str) != c_state.struct_map.end()){
+ return void_t{};
+ }
+
+ c_types::c_struct str;
+
+ try {
+ std::stringstream iss;
+ schema_stringify<Schema>::apply(iss);
+ str.cpp_schema = iss.str();
+ }catch(const std::exception& e){
+ return make_error<err::critical>();
+ }
+
+ /**
+ * Adding heap alloc data ptr
+ */
+ {
+ c_types::c_member memb;
+ memb.key = inner_type_str;
+ memb.name = "data";
+ memb.is_primitive = c_is_primitive<T>::value;
+ // fn.members.emplace_back(std::move(memb));
+
+ str.members.emplace_back(std::move(memb));
+ }
+ {
+ c_types::c_member memb;
+ memb.key
+ }
+
+
+ str.def = "struct ";
+ str.def += type_str;
+
+ str.def += " {\n";
+
+ str.def += "\t" + inner_type_str + "* data;\n";
+ str.def += "\tsize_t size;\n";
+ if( Dim > 1 ){
+ str.def += "\tsize_t dims["+std::to_string(Dim)+"];\n";
+ }
+
+ str.def += "};\n";
+
+ c_state.struct_map.emplace(std::make_pair(type_str, std::move(str)));
+ return void_t{};
+ }
+};
+
+template<typename Interface>
+struct c_iface_translater {
+ static_assert(always_false<Interface>,"Not supported");
+};
+
+template<class... Request, class Response, string_literal... Lits>
+struct c_iface_translater<schema::Function<schema::Struct<schema::Member<Request, Lits>...>, Response>> {
+ using StructMap = typename c_types::c_struct_map;
+ using FuncMap = typename c_types::c_func_map;
+
+ template<size_t i>
+ static error_or<void> generate_request_member(c_types::state& c_state, std::array<std::string, sizeof...(Request)>& type_arr){
+ using Type = typename parameter_pack_type<i, Request...>::type;
+ // constexpr string_literal lit = parameter_key_pack_type<i, Lits...>::literal;
+
+ auto eov = c_data_translater<Type>::generate(c_state, type_arr.at(i));
+ if(eov.is_error()){
+ return eov;
+ }
+
+ if constexpr ((i+1) < sizeof...(Request)){
+ auto eov = generate_request_member<i+1>(c_state, type_arr);
+ return eov;
+ }
+
+ return void_t{};
+ }
+
+ template<size_t i>
+ static error_or<void> generate_parameter(std::string& param_use, const std::array<std::string, sizeof...(Request)>& req_type_arr){
+ using Type = typename parameter_pack_type<i, Request...>::type;
+ constexpr string_literal lit = parameter_key_pack_type<i, Lits...>::literal;
+
+ std::string used_param;
+ if constexpr (c_is_primitive<Type>::value){
+ used_param += req_type_arr.at(i);
+ } else {
+ used_param += "const " + req_type_arr.at(i) + "*";
+ }
+ param_use += used_param + " " + std::string{lit.view()};
+
+ if constexpr ( (i+1) < sizeof...(Request) ){
+ param_use += ", ";
+ return generate_parameter<i+1>(param_use, req_type_arr);
+ }
+
+ return void_t{};
+ }
+
+ static error_or<void> generate(c_types::state& c_state, const std::string& func_name){
+ std::array<std::string, sizeof...(Request)> request_type_arr;
+
+ if constexpr (sizeof...(Request) > 0){
+ auto eov = generate_request_member<0>(c_state, request_type_arr);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ std::string response_type_str;
+ {
+ auto eov = c_data_translater<Response>::generate(c_state, response_type_str);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ std::string c_func_name = c_state.prefix + "_" + func_name;
+
+ c_types::c_func fn;
+ fn.cpp_name = func_name;
+ fn.def = "int";
+ std::string iface_ctx = c_state.prefix + "_iface_context* ctx";
+ fn.def += " " + c_func_name + "(" + iface_ctx;
+ fn.def += ", " + response_type_str + "* out";
+ if constexpr ( sizeof...(Request) > 0 ){
+ fn.def += ", ";
+ auto eov = generate_parameter<0>(fn.def, request_type_arr);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ fn.def += ")";
+
+ fn.source = "{\n";
+ // Check necessary pointers
+ fn.source += "\tassert(ctx);\n";
+ fn.source += "\tif(!ctx){return -1;}\n\n";
+ fn.source += "\tauto rmt = reinterpret_cast<interface<IfaceSchema, ";
+ fn.source += c_state.encoding;
+ fn.source += ">*>(ctx);\n";
+
+ // translate the input data
+ if constexpr (sizeof...(Request) > 0){
+ // I need a recursive search for the types
+ }
+
+ // Call the remote interface
+ fn.source += "\tauto eov = rmt->template call<\"" + fn.cpp_name + "\">(std::move(input));";
+ fn.source += ");\n";
+
+ // translate the output data
+ fn.source += "";
+
+ // Close the brace
+
+ fn.source += "}\n";
+
+ c_state.func_map.emplace(std::make_pair(c_func_name, std::move(fn)));
+
+ return void_t{};
+ }
+};
+
+template<class... Requests, class... Responses, string_literal... Names>
+struct c_iface_translater<schema::Interface<schema::Member<schema::Function<Requests, Responses>, Names>...>> {
+ using Schema = schema::Interface<schema::Member<schema::Function<Requests, Responses>, Names>...>;
+
+ template<size_t i>
+ static error_or<void> generate_member(c_types::state& c_state){
+ using Req = typename parameter_pack_type<i,Requests...>::type;
+ using Resp = typename parameter_pack_type<i,Responses...>::type;
+ constexpr string_literal lit = parameter_key_pack_type<i, Names...>::literal;
+
+ try{
+ std::stringstream iss;
+ schema_stringify<Schema>::apply(iss);
+ c_state.interface_schema = iss.str();
+ }catch(const std::exception& e){
+ (void) e;
+ return make_error<err::critical>();
+ }
+
+ std::string c_func_name = c_state.prefix + "_" + std::string{lit.view()};
+ if(c_state.func_map.find(c_func_name) != c_state.func_map.end()){
+ return make_error<err::already_exists>();
+ }
+
+ {
+ std::string type_str;
+ auto eov = c_iface_translater<schema::Function<Req, Resp>>::generate(c_state, std::string{lit.view()});
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+
+ if constexpr ((i+1) < sizeof...(Requests) ){
+ return generate_member<i+1>(c_state);
+ }
+ return void_t{};
+ }
+
+ static error_or<void> generate(c_types::state& c_state){
+ if constexpr ( sizeof...(Requests) > 0 ){
+ return generate_member<0>(c_state);
+ }
+
+ return void_t{};
+ }
+};
+}
+
+template<typename Interface>
+error_or<void> generate_c_interface(typename impl::c_types::state& state){
+ auto eov = impl::c_iface_translater<Interface>::generate(state);
+ return eov;
+}
+
+error_or<void> generate_iface_example(){
+ using Request1 = schema::Struct<
+ schema::Member<schema::Int32, "foo">,
+ schema::Member<schema::Float64, "bar">,
+ schema::Member<schema::Array<schema::Float32,1>, "baz">
+ >;
+ using Response1 = schema::Int32;
+
+ using Func1 = schema::Function<Request1, Response1>;
+
+ using Iface = schema::Interface<
+ schema::Member<Func1, "func_one">
+ >;
+
+ impl::c_types::state c_state;
+ c_state.prefix = "c_saw";
+ c_state.encoding = "saw::encode::Native";
+
+ typename impl::c_types::c_struct_map& type_map = c_state.struct_map;
+ typename impl::c_types::c_func_map& func_map = c_state.func_map;
+ auto eov = generate_c_interface<Iface>(c_state);
+ if(eov.is_error()){
+ return eov;
+ }
+ std::cout<<"Interface: "<<c_state.interface_schema<<std::endl;
+ std::cout<<"Prefix: "<<c_state.prefix<<std::endl;
+ std::cout<<"\nTypes: "<<std::endl;
+
+ for(auto& iter : type_map){
+ std::cout<<"\nType: \""<<iter.first<<"\""<<std::endl;
+ std::cout<<"Definition:\n\"\"\"\n";
+ std::cout<<iter.second.def;
+ std::cout<<"\"\"\""<<std::endl;
+ std::cout<<"Schema: "<<iter.second.cpp_schema<<std::endl;
+ }
+ std::cout<<"\nFunctions: "<<std::endl;
+
+ for(auto& iter : func_map){
+ std::cout<<"\nSymbol: \""<<iter.first<<"\""<<std::endl;
+ std::cout<<"Definition:\n\"\"\"\n";
+ std::cout<<iter.second.def<<";\n";
+ std::cout<<"\"\"\""<<std::endl;
+ std::cout<<"\nSource:\n"<<iter.second.source<<std::endl;
+ }
+
+ return eov;
+}
+
+error_or<void> generate_array_example(){
+ using Schema1 = schema::Array<schema::Int32,2>;
+
+ using Schema2 = schema::Array<schema::Float64,5>;
+
+ using Schema3 = schema::Array<schema::UInt16,1>;
+
+ std::string prefix = "c_saw";
+ impl::c_types::state c_state;
+ c_state.prefix = prefix;
+ {
+ std::string type_str;
+ auto eov = impl::c_data_translater<Schema1>::generate(c_state, type_str);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ {
+ std::string type_str;
+ auto eov = impl::c_data_translater<Schema2>::generate(c_state, type_str);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ {
+ std::string type_str;
+ auto eov = impl::c_data_translater<Schema3>::generate(c_state, type_str);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+
+ std::cout<<"Prefix: "<<c_state.prefix<<std::endl;
+
+ for(auto& iter : c_state.struct_map){
+ std::cout<<"\nType: \""<<iter.first<<"\""<<std::endl;
+ std::cout<<"Definition:\n\"\"\"\n";
+ std::cout<<iter.second.def;
+ std::cout<<"\"\"\""<<std::endl;
+ }
+
+ return void_t{};
+}
+}
diff --git a/modules/tools/cli_analyzer.hpp b/modules/tools/cli_analyzer.hpp
new file mode 100644
index 0000000..295ddf6
--- /dev/null
+++ b/modules/tools/cli_analyzer.hpp
@@ -0,0 +1,114 @@
+#pragma once
+
+#include <forstio/codec/schema.h>
+
+#include <iostream>
+
+namespace saw {
+namespace impl {
+struct cli_mode {
+ struct read {};
+ struct write {};
+};
+
+template<typename T, typename Encoding>
+struct cli_traverser {
+ static_assert(always_false<T,Encoding>, "Not supported");
+};
+
+template<typename Schema, typename Encoding>
+struct cli_modifier {
+ codec<Schema, encode::Json> json;
+ codec<Schema, Encoding> encoded;
+
+ error_or<void> read(data<Schema, Encoding>& enc_data, std::deque<std::string>& sch_path, std::string& json_data_str){
+ data<Schema, encode::Native> native;
+ {
+ auto eov = encoded.decode<encode::Native>(enc_data, native);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ {
+ data<Schema, encode::Json> json_data;
+ auto eov = json.encode<encode::Native>(native, json_data);
+ if(eov.is_error()){
+ return eov;
+ }
+
+ json_data_str = convert_to_string(json_data.get_buffer());
+ }
+
+ return void_t{};
+ }
+
+ error_or<void> write(data<Schema, Encoding>& enc_data, std::deque<std::string>& sch_path, std::string& json_data_str){
+ data<Schema, encode::Native> native;
+ {
+ /// @todo string to data
+ data<Schema, encode::Json> json_data{ std::string_view{json_data_str} };
+ auto eov = json.decode<encode::Native>(json_data, native);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ {
+ auto eov = encoded.encode<encode::Native>(native, enc_data);
+ if(eov.is_error()){
+ return eov;
+ }
+ }i
+
+ return void_t{};
+
+ }
+};
+
+template<typename... T, string_literal... Lits, typename Encoding>
+struct cli_traverser<schema::Struct<schema::Member<T,Lits>...>, Encoding> {
+ using Schema = schema::Struct<schema::Member<T,Lits>...>;
+
+ template<typename Traversal>
+ static error_or<void> traverse(std::deque<std::string>& sch_path, std::string& json_data){
+ if(sch_path.empty()){
+ cli_modifier<Schema, Encoding> mod;
+ if constexpr (std::is_same_v<Traversal, cli_mode::read>){
+ return mod.read(sch_path, json_data);
+ } else if constexpr (std::is_same_v<Traversal, cli_mode::write>) {
+ return mod.write(sch_path, json_data);
+ } else {
+ return make_error<err::invalid_state>();
+ }
+ } else {
+
+ }
+
+ return void_t{};
+ }
+};
+}
+
+template<typename Schema, typename Encoding>
+int modify_data_on_cli(int argc, char** argv){
+
+ /// @todo parse cli data
+ bool read_mode = true;
+
+ std::deque<std::string> sch_path;
+ std::string json_data;
+
+ if (read_mode) {
+ auto eov = impl::cli_modifier<Schema, Encoding>::traverse<impl::cli_mode::read>(sch_path, json_data);
+ if(eov.is_error()){
+ return -1;
+ }
+ } else {
+ auto eov = impl::cli_modifier<Schema, Encoding>::traverse<impl::cli_mode::write>(sch_path, json_data);
+ if(eov.is_error()){
+ return -1;
+ }
+ }
+
+ return 0;
+}
+}