From f8c6ec7a18b33deba530b15a5779556233e8057b Mon Sep 17 00:00:00 2001 From: "Claudius \"keldu\" Holeksa" Date: Fri, 8 Mar 2024 21:54:31 +0100 Subject: codec,tools: Working on better c iface generation --- modules/codec/c++/schema.hpp | 3 + modules/tools/c++/c_gen_iface.hpp | 474 ++++++++++--------------------- modules/tools/python/c_generate_iface.py | 24 -- modules/tools/tests/c_iface.cpp | 20 +- 4 files changed, 153 insertions(+), 368 deletions(-) delete mode 100755 modules/tools/python/c_generate_iface.py (limited to 'modules') diff --git a/modules/codec/c++/schema.hpp b/modules/codec/c++/schema.hpp index 1feb951..5348cfe 100644 --- a/modules/codec/c++/schema.hpp +++ b/modules/codec/c++/schema.hpp @@ -8,6 +8,9 @@ namespace schema { // NOLINTBEGIN template struct Member { static constexpr string_literal name = "Member"; + + using ValueType = T; + static constexpr string_literal KeyLiteral = Literal; }; template struct Struct { diff --git a/modules/tools/c++/c_gen_iface.hpp b/modules/tools/c++/c_gen_iface.hpp index b55816c..2dfa36f 100644 --- a/modules/tools/c++/c_gen_iface.hpp +++ b/modules/tools/c++/c_gen_iface.hpp @@ -12,81 +12,9 @@ #include namespace saw { - -namespace schema { - -using CVar = Struct< - Member, - Member, - Member, - Member, - Member, - Member ->; - -using CStruct = Struct< - Member, - Member, - Member, - Member, "members"> ->; - -using CFunction = Struct< - Member, - Member, - Member, - Member, "params">, - Member ->; - -using CIface = Struct< - Member, - Member, - Member,"structs">, - Member,"functions"> ->; -} -/** - * Type meant to provide future help if I decide to introduce more maps - */ -/** -namespace schema { -using namespace saw::schema; -Pseudo flattened -using Foo = Struct< - Member, "a"> - Member, "b"> ->; - -Needs to be flattened to - -template -using FlattenedSchemaElement = Struct< - Member, "path">, - Member ->; - -// Illegal, but doable with more lines of code -// Just use typename... T and -// "T..." for -// "Member,Names>...>" -// and specialize somewhere else -template -using FlattenedSchema = Struct< - Member, - Member, Names>... ->; +namespace binding { +struct C {}; } -*/ - -template -struct schema_flattener { - static_assert(always_false, "Not supported"); -}; - -template -struct schema_flattener,schema::Member...>, Res> { -}; /** * Helper to determine if we are dealing with primitive types @@ -166,336 +94,222 @@ struct c_primitive_string { static constexpr string_literal value = "double"; }; -error_or> c_interface_find_struct_by_crc32(const data& state, const data& id){ - const auto& strs = state.template get<"structs">(); - for(uint64_t i = 0; i < strs.size(); ++i){ - const auto& str = strs.at(i); - if(str.template get<"crc32">() == id){ - return data{i}; - } - } - return make_error(); -} - -error_or c_interface_add_struct(data& state, data&& val){ - auto& strs = state.template get<"structs">(); - auto eov = strs.add(std::move(val)); - if(eov.is_error()){ - return std::move(eov.get_error()); - } - return void_t{}; -} - -bool c_interface_function_exists(data& state, const std::string_view& name){ - auto& funcs = state.template get<"functions">(); - for(uint64_t i = 0; i < funcs.size(); ++i){ - if(funcs.at(i).get<"name">() == name){ - return true; - } - } - return false; -} +struct language_binding_config { + std::string prefix; +}; -template -struct c_data_translater { +namespace impl { +template +struct lang_bind { static_assert(always_false, "Not supported"); }; -template -struct c_data_translater> { - using Schema = schema::Primitive; - static constexpr string_literal c_type_name = c_primitive_string::name; - static constexpr string_literal c_type = c_primitive_string::value; - - static error_or generate(data& state, data& prim){ - try{ - std::stringstream iss; - schema_stringify::apply(iss); - prim.template get<"schema">().set(iss.str()); - prim.template get<"crc32">().set(schema_hash::apply()); - prim.template get<"is_primitive">().set(1); - prim.template get<"type">().set(std::string{c_primitive_string::value.view()}); - }catch(const std::exception&){ - return make_error(); +struct language_binding_state { + struct info { + std::string type; + }; + std::map hashes; +}; + +struct lang_bind_helper { + static error_or append_string(buffer& buff, const std::string_view& str){ + for(uint64_t i = 0; i < str.size(); ++i){ + auto err = buff.push(static_cast(str[i])); + if(!err.template is_type()){ + return err; + } } + return void_t{}; + } + static error_or append_hashed_type(buffer& buff, const std::string_view& prefix, uint32_t hash){ + { + auto eov = append_string(buff, prefix); + if(eov.is_error()){ + return eov; + } + } + { + auto eov = append_string(buff, "_"); + if(eov.is_error()){ + return eov; + } + } + { + auto eov = append_string(buff, std::to_string(hash)); + if(eov.is_error()){ + return eov; + } + } + { + auto eov = append_string(buff, "_t"); + if(eov.is_error()){ + return eov; + } + } return void_t{}; } }; -template -struct c_data_translater> { - static_assert(N==1, "Doesn't support more than one dimension currently"); - - using Schema = schema::Array; - static constexpr string_literal c_type_name = "array_"_sl + c_data_translater::c_type_name + "_1d"_sl; - static constexpr string_literal c_type = c_type_name + "_t"_sl; - - static error_or generate(data& state, data& arr){ - try{ - { - std::stringstream iss; - schema_stringify::apply(iss); - arr.template get<"schema">().set(iss.str()); - arr.template get<"crc32">().set(schema_hash::apply()); - arr.template get<"is_primitive">().set(0); - } +template +struct lang_bind, binding::C> { + using Schema = schema::Primitive; - /// @todo change this !!!!! - { - auto eov = c_interface_find_struct_by_crc32(state, arr.template get<"crc32">()); - if(eov.is_error()){ - if(false){ - return std::move(eov.get_error()); + static error_or generate(buffer& buff, const language_binding_config& cfg, language_binding_state& state){ + constexpr uint64_t hash = schema_hash::apply(); + + { + std::string hash_type_str = cfg.prefix + "_" + std::to_string(hash) + "_t"; + auto emp = state.hashes.emplace(std::make_pair(hash, hash_type_str)); + if(emp.second){ + { + auto eov = lang_bind_helper::append_string(buff, "typedef "); + if(eov.is_error()){ + return eov; } - data str; - str.template get<"schema">() = arr.template get<"schema">(); - str.template get<"crc32">() = arr.template get<"crc32">(); - str.template get<"type">().set(std::string{c_type.view()}); - auto& membs = str.template get<"members">(); - { - data c_var; - std::stringstream iss; - schema_stringify::apply(iss); - c_var.template get<"schema">().set(iss.str()); - c_var.template get<"crc32">().set(schema_hash::apply()); - if constexpr (is_primitive::value){ - c_var.template get<"type">().set(std::string{c_primitive_string::value.view()} + "*"); - c_var.template get<"name">().set(std::string{"data"}); - c_var.template get<"is_primitive">().set(1); - }else{ - return make_error(); - } - - auto eov_add = membs.add(std::move(c_var)); - if(eov_add.is_error()){ - return std::move(eov_add.get_error()); - } + } + { + auto eov = lang_bind_helper::append_string(buff, c_primitive_string::value.view()); + if(eov.is_error()){ + return eov; } - { - data c_var; - std::stringstream iss; - schema_stringify::apply(iss); - c_var.template get<"schema">().set(iss.str()); - c_var.template get<"crc32">().set(schema_hash::apply()); - if constexpr (is_primitive::value){ - c_var.template get<"type">().set(std::string{c_primitive_string::value.view()}); - c_var.template get<"name">().set(std::string{"size"}); - c_var.template get<"is_primitive">().set(1); - }else{ - return make_error(); - } - - auto eov_add = membs.add(std::move(c_var)); - if(eov_add.is_error()){ - return std::move(eov_add.get_error()); - } + } + { + auto eov = lang_bind_helper::append_string(buff, " "); + if(eov.is_error()){ + return eov; } - - /** - * Add the struct to the struct array - */ - { - auto eov_add = c_interface_add_struct(state, std::move(str)); - if(eov_add.is_error()){ - return std::move(eov_add.get_error()); - } + } + { + auto eov = lang_bind_helper::append_string(buff, hash_type_str); + if(eov.is_error()){ + return eov; + } + } + { + auto eov = lang_bind_helper::append_string(buff, ";\n"); + if(eov.is_error()){ + return eov; } } } - arr.template get<"type">().set(std::string{c_type.view()}); - }catch(const std::exception&){ - return make_error(); } return void_t{}; } }; -/* -template -struct c_data_translater> { - using Schema = schema::Struct; - - static error_or generate(data& state){ - return void_t{}; - } -}; -*/ - -template -struct c_parameter_translater { - static_assert(always_false, "Type not supported"); -}; - -template -struct c_parameter_translater...>> { - template - static error_or generate_ele(data& state, data>& params){ - using Type = typename parameter_pack_type::type; - constexpr string_literal Literal = parameter_key_pack_type::literal; +template +struct lang_bind, binding::C> { + static error_or generate(buffer& buff, const language_binding_config& cfg, language_binding_state& state){ + constexpr uint64_t input_hash = schema_hash::apply(); + constexpr uint64_t output_hash = schema_hash::apply(); { - auto c_var = data{}; - c_var.template get<"name">().set(std::string{Literal.view()}); - { - auto eov = c_data_translater::generate(state,c_var); + auto eov = lang_bind::generate(buff, cfg, state); if(eov.is_error()){ return eov; } - } - { - auto eov = params.add(std::move(c_var)); + } + { + auto eov = lang_bind::generate(buff, cfg, state); if(eov.is_error()){ return eov; } - } } - if constexpr ( (i+1) < sizeof...(V) ) { - return generate_ele(state, params); - } - return void_t{}; - } - - static error_or generate(data& state, data>& params){ - if constexpr ( sizeof...(V) > 0){ - return generate_ele<0>(state, params); - } return void_t{}; } }; -template -struct c_data_translater> { - using Schema = schema::Function; - - static error_or generate_struct_params(data& state, data>& params){ - return c_parameter_translater::generate(state, params); - } +template +struct lang_bind, binding::C> { + template + static error_or generate_element(buffer& buff, const language_binding_config& cfg, language_binding_state& state){ + using Member = typename parameter_pack_type::type; + using MValue = typename Member::ValueType; + static constexpr string_literal MKey = Member::KeyLiteral; - static error_or generate(data& state, const std::string_view& func_name){ - if(c_interface_function_exists(state, func_name)){ - return make_error("Function already exists"); + { + auto eov = lang_bind::generate(buff, cfg, state); + if(eov.is_error()){ + return eov; + } } - auto& funcs = state.template get<"functions">(); - data function; - function.template get<"name">().set(std::string{func_name}); - - try{ - std::stringstream iss; - schema_stringify::apply(iss); - function.template get<"schema">().set(iss.str()); - function.template get<"crc32">().set(schema_hash::apply()); - }catch(const std::exception&){ - return make_error(); + { + auto eov = lang_bind_helper::append_string(buff, cfg.prefix); + if(eov.is_error()){ + return eov; + } } - - // Return value { - auto& c_var = function.template get<"return">(); - c_var.template get<"name">().set("ret_val"); - auto eov = c_data_translater::generate(state, c_var); + auto eov = lang_bind_helper::append_string(buff, "_"); if(eov.is_error()){ return eov; } } - - // Request values - auto& params = function.template get<"params">(); - if constexpr (is_primitive::value){ - auto c_var = data{}; - c_var.template get<"name">().set("req_val"); - { - auto eov = c_data_translater::generate(state, c_var); - if(eov.is_error()){ - return eov; - } + { + auto eov = lang_bind_helper::append_string(buff, MKey.view()); + if(eov.is_error()){ + return eov; } - { - auto eov = params.add(std::move(c_var)); - if(eov.is_error()){ - return eov; - } + } + { + auto eov = lang_bind_helper::append_string(buff, "("); + if(eov.is_error()){ + return eov; } - } else { - auto eov = generate_struct_params(state, params); + } + { + auto eov = lang_bind_helper::append_hashed_type(buff, cfg.prefix, schema_hash::apply()); if(eov.is_error()){ return eov; } } - { - auto eov = funcs.add(std::move(function)); + auto eov = lang_bind_helper::append_string(buff, ","); if(eov.is_error()){ return eov; } } - - return void_t{}; - } -}; - -template -struct c_data_translater...>> { - using Schema = schema::Interface...>; - - template - static error_or generate_ele(data& state){ - using InnerSchema = typename parameter_pack_type::type; - constexpr string_literal Literal = parameter_key_pack_type::literal; { - auto eov = c_data_translater::generate(state, Literal.view()); + auto eov = lang_bind_helper::append_string(buff, ");"); if(eov.is_error()){ return eov; } } - /** - * Continue if elements remain or finish - */ - if constexpr ( (i+1) < sizeof...(Funcs) ){ - return generate_ele(state); + if constexpr ((i+1) < sizeof...(M) ){ + return generate_element(buff, cfg, state); } return void_t{}; } - static error_or generate(data& state){ - try{ - std::stringstream iss; - schema_stringify::apply(iss); - state.template get<"schema">().set(iss.str()); - state.template get<"crc32">().set(schema_hash::apply()); - }catch(const std::exception&){ - return make_error(); + static error_or generate(buffer& buff, const language_binding_config& cfg){ + if(cfg.prefix.size() == 0){ + return make_error("C interfaces need a prefix."); } - - if constexpr (sizeof...(Funcs) > 0){ - return generate_ele<0>(state); + language_binding_state state; + + if constexpr (sizeof...(M) > 0){ + return generate_element<0>(buff, cfg, state); } + return void_t{}; } }; - -template -error_or generate_c_interface(data& state){ - auto eov = c_data_translater::generate(state); - return eov; -} -/* -namespace lang { -struct C {}; } -template -class binding; +template +struct language_binding { + static_assert(always_false, "Case not supported."); +}; -template -class binding { -public: - static constexpr string_literal header; - static constexpr string_literal source; +template +struct language_binding { + static error_or generate(buffer& buff, const language_binding_config& cfg){ + return impl::lang_bind::generate(buff, cfg); + } }; -*/ } diff --git a/modules/tools/python/c_generate_iface.py b/modules/tools/python/c_generate_iface.py deleted file mode 100755 index d234482..0000000 --- a/modules/tools/python/c_generate_iface.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python3 - -import argparse; -import jinja2; - - -def parse_args(): - parser = argparse.ArgumentParser( - description = "Generates bindings for the Interface schema" - ); - parser.add_argument( - '-t', '--template', - required=True, - help = "Path to the template directory" - ); - - return parser.parse_args(); - -def main(): - return 0; - -if __name__ == "__main__": - rc = main(); - exit(rc); diff --git a/modules/tools/tests/c_iface.cpp b/modules/tools/tests/c_iface.cpp index 4f1b744..79d2344 100644 --- a/modules/tools/tests/c_iface.cpp +++ b/modules/tools/tests/c_iface.cpp @@ -41,23 +41,14 @@ template void test_generate(std::string& res){ using namespace saw; - data c_iface; - { - auto eov = generate_c_interface(c_iface); - SAW_EXPECT(eov.is_value(), "Couldn't generate interface info"); - } - - data j_data; - codec_config j_config; - j_config.pretty = true; - codec j_codec{j_config}; + ring_buffer r_buff{4u * 1024u * 1024u}; { - auto eov = j_codec.encode(c_iface, j_data); - SAW_EXPECT(eov.is_value(), "Couldn't encode data"); + auto eov = language_binding::generate(r_buff, {"kel"}); + SAW_EXPECT(eov.is_value(), std::string{"Couldn't generate interface info: "} + std::string{eov.get_error().get_message()}); } - res = convert_to_string(j_data.get_buffer()); + res = convert_to_string(r_buff); } SAW_TEST("CIface Empty Interface"){ @@ -76,7 +67,7 @@ SAW_TEST("CIface One Function Interface"){ test_generate(res); std::cout<<"\n"<(res); std::cout<<"\n"<