#include #include #include #include #include #include #include #include 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 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 requests; }; using c_struct_map = std::map; using c_func_map = std::map; 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, "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>... >; */ template struct schema_flattener { static_assert(always_false, "Not supported"); }; template struct schema_flattener,schema::Member...>, Res> { }; using StructBindingSchema = Struct< Member, Member, Member, Member, "members"> >; using FunctionBindingSchema = Struct< Member, Member, Member >; using BindingSchema = Struct< Member, Member, Member, Member, Member, "structs">, Member, "functions"> >; } /** * Helper to determine if we are dealing with primitive types */ template struct c_is_primitive { static constexpr bool value = false; }; template struct c_is_primitive> { static constexpr bool value = true; }; template struct c_primitive_string { static_assert(always_false, "Not supported"); }; template<> struct c_primitive_string { static constexpr std::string_view value = "int8_t"; }; template<> struct c_primitive_string { static constexpr std::string_view value = "int16_t"; }; template<> struct c_primitive_string { static constexpr std::string_view value = "int32_t"; }; template<> struct c_primitive_string { static constexpr std::string_view value = "int64_t"; }; template<> struct c_primitive_string { static constexpr std::string_view value = "uint8_t"; }; template<> struct c_primitive_string { static constexpr std::string_view value = "uint16_t"; }; template<> struct c_primitive_string { static constexpr std::string_view value = "uint32_t"; }; template<> struct c_primitive_string { static constexpr std::string_view value = "uint64_t"; }; template<> struct c_primitive_string { static constexpr std::string_view value = "float"; }; template<> struct c_primitive_string { static constexpr std::string_view value = "double"; }; template struct c_data_translater { static_assert(always_false, "Not supported"); }; template struct c_data_translater> { using StructMap = typename c_types::c_struct_map; using Schema = schema::Primitive; static error_or generate(c_types::state& c_state, std::string& str){ (void) c_state; str += c_primitive_string::value; return void_t{}; } }; template struct c_data_translater> { using Schema = schema::Array; using StructMap = typename c_types::c_struct_map; static error_or generate(c_types::state& c_state, std::string& type_str){ type_str = "array_"; std::string inner_type_str; auto eov = impl::c_data_translater::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::apply(iss); str.cpp_schema = iss.str(); }catch(const std::exception& e){ return make_error(); } /** * Adding heap alloc data ptr */ { c_types::c_member memb; memb.key = inner_type_str; memb.name = "data"; memb.is_primitive = c_is_primitive::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 struct c_iface_translater { static_assert(always_false,"Not supported"); }; template struct c_iface_translater...>, Response>> { using StructMap = typename c_types::c_struct_map; using FuncMap = typename c_types::c_func_map; template static error_or generate_request_member(c_types::state& c_state, std::array& type_arr){ using Type = typename parameter_pack_type::type; // constexpr string_literal lit = parameter_key_pack_type::literal; auto eov = c_data_translater::generate(c_state, type_arr.at(i)); if(eov.is_error()){ return eov; } if constexpr ((i+1) < sizeof...(Request)){ auto eov = generate_request_member(c_state, type_arr); return eov; } return void_t{}; } template static error_or generate_parameter(std::string& param_use, const std::array& req_type_arr){ using Type = typename parameter_pack_type::type; constexpr string_literal lit = parameter_key_pack_type::literal; std::string used_param; if constexpr (c_is_primitive::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(param_use, req_type_arr); } return void_t{}; } static error_or generate(c_types::state& c_state, const std::string& func_name){ std::array 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::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 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 struct c_iface_translater, Names>...>> { using Schema = schema::Interface, Names>...>; template static error_or generate_member(c_types::state& c_state){ using Req = typename parameter_pack_type::type; using Resp = typename parameter_pack_type::type; constexpr string_literal lit = parameter_key_pack_type::literal; try{ std::stringstream iss; schema_stringify::apply(iss); c_state.interface_schema = iss.str(); }catch(const std::exception& e){ (void) e; return make_error(); } 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(); } { std::string type_str; auto eov = c_iface_translater>::generate(c_state, std::string{lit.view()}); if(eov.is_error()){ return eov; } } if constexpr ((i+1) < sizeof...(Requests) ){ return generate_member(c_state); } return void_t{}; } static error_or generate(c_types::state& c_state){ if constexpr ( sizeof...(Requests) > 0 ){ return generate_member<0>(c_state); } return void_t{}; } }; } template error_or generate_c_interface(typename impl::c_types::state& state){ auto eov = impl::c_iface_translater::generate(state); return eov; } error_or generate_iface_example(){ using Request1 = schema::Struct< schema::Member, schema::Member, schema::Member, "baz"> >; using Response1 = schema::Int32; using Func1 = schema::Function; using Iface = schema::Interface< schema::Member >; 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(c_state); if(eov.is_error()){ return eov; } std::cout<<"Interface: "< generate_array_example(){ using Schema1 = schema::Array; using Schema2 = schema::Array; using Schema3 = schema::Array; 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::generate(c_state, type_str); if(eov.is_error()){ return eov; } } { std::string type_str; auto eov = impl::c_data_translater::generate(c_state, type_str); if(eov.is_error()){ return eov; } } { std::string type_str; auto eov = impl::c_data_translater::generate(c_state, type_str); if(eov.is_error()){ return eov; } } std::cout<<"Prefix: "<