summaryrefslogtreecommitdiff
path: root/c++/tools/c_gen_iface.hpp
diff options
context:
space:
mode:
authorClaudius "keldu" Holeksa <mail@keldu.de>2023-11-26 22:04:04 +0100
committerClaudius "keldu" Holeksa <mail@keldu.de>2023-11-26 22:04:04 +0100
commit5c34e8ae67998c53c1d4016d5b9f4c02917f0ecf (patch)
tree521f55ead53f6618721afc67986665b0bc53fb42 /c++/tools/c_gen_iface.hpp
parent348d6734b34d69c3ebd9982320281a7329ad8730 (diff)
core,codec,tools: Working on c binding generation
Diffstat (limited to 'c++/tools/c_gen_iface.hpp')
-rw-r--r--c++/tools/c_gen_iface.hpp323
1 files changed, 276 insertions, 47 deletions
diff --git a/c++/tools/c_gen_iface.hpp b/c++/tools/c_gen_iface.hpp
index 3209505..7e2e396 100644
--- a/c++/tools/c_gen_iface.hpp
+++ b/c++/tools/c_gen_iface.hpp
@@ -8,9 +8,72 @@
#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;
+ };
+
+ struct c_param {
+ std::string key;
+ std::string name;
+ bool is_primitive;
+ };
+
+ struct c_struct {
+ std::string def;
+ std::string cpp_schema;
+ std::vector<c_member> member_keys;
+ std::string translate_to_c_source;
+ std::string translate_to_cpp_source;
+ };
+
+ struct c_response {
+ std::string key;
+ bool is_primitive;
+ };
+
+ struct c_func {
+ std::string def;
+ std::string cpp_schema;
+ c_response response;
+ std::vector<c_param> requests;
+ std::string source;
+ std::string cpp_name;
+ };
+
+ 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 encoding;
+ };
+};
+
+/**
+ * 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 {
@@ -74,8 +137,11 @@ struct c_data_translater {
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(std::map<std::string,std::string>& map_str, std::string& str, const std::string& prefix){
+
+ 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{};
}
@@ -83,12 +149,15 @@ struct c_data_translater<schema::Primitive<T,N>> {
template<typename T, size_t Dim>
struct c_data_translater<schema::Array<T,Dim>> {
- static error_or<void> generate(std::map<std::string, std::string>& map_str, std::string& type_str, const std::string& prefix){
- type_str = prefix + "_";
+ 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 = c_state.prefix + "_";
type_str += "array_";
std::string inner_type_str;
- auto eov = impl::c_data_translater<T>::generate(map_str, inner_type_str, prefix);
+ auto eov = impl::c_data_translater<T>::generate(c_state, inner_type_str);
if(eov.is_error()){
return eov;
}
@@ -101,77 +170,199 @@ struct c_data_translater<schema::Array<T,Dim>> {
type_str += "d";
}
- if(map_str.find(type_str) != map_str.end()){
+ if(c_state.struct_map.find(type_str) != c_state.struct_map.end()){
return void_t{};
}
- std::string str = "struct ";
- str += type_str;
+ 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>();
+ }
+
+ {
+ c_types::c_member memb;
+ memb.key = inner_type_str;
+ memb.name = "data";
+ memb.is_primitive
+ fn.members.emplace_back(std::move(memb));
+ }
- str += " {\n";
+ str.def = "struct ";
+ str.def += type_str;
- str += "\t" + inner_type_str + "* data;\n";
- str += "\tsize_t size;\n";
+ str.def += " {\n";
+
+ str.def += "\t" + inner_type_str + "* data;\n";
+ str.def += "\tsize_t size;\n";
if( Dim > 1 ){
- str += "\tsize_t dims["+std::to_string(Dim)+"];\n";
+ str.def += "\tsize_t dims["+std::to_string(Dim)+"];\n";
}
- str += "};\n";
+ str.def += "};\n";
- map_str.insert(std::make_pair(std::move(type_str), std::move(str)));
+ c_state.struct_map.emplace(std::make_pair(type_str, std::move(str)));
return void_t{};
}
};
template<typename Interface>
-struct c_rpc_translater {
+struct c_iface_translater {
static_assert(always_false<Interface>,"Not supported");
};
-template<class Request, class Response>
-struct c_rpc_translater<schema::Function<Request, Response>> {
- using Map = std::map<std::string, std::string>;
+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;
+ }
- static error_or<void> generate(const std::string& prefix, Map& type_map, Map& func_map){
+ 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_rpc_translater<schema::Interface<schema::Member<schema::Function<Requests, Responses>, Names>...>> {
- using Map = std::map<std::string, std::string>;
+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(const std::string& prefix, Map& type_map, Map& func_map){
+ 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;
- std::string func_name{lit.view()};
- if(func_map.find(func_name) != func_map.end()){
+ 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_rpc_translater<schema::Function<Req, Resp>>::generate(prefix, type_map, func_map);
+ 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>(prefix, type_map, func_map);
+ return generate_member<i+1>(c_state);
}
return void_t{};
}
- static error_or<void> generate(const std::string& prefix){
- Map type_map, func_map;
-
+ static error_or<void> generate(c_types::state& c_state){
if constexpr ( sizeof...(Requests) > 0 ){
- return generate_member<0>(prefix, type_map, func_map);
+ return generate_member<0>(c_state);
}
return void_t{};
@@ -180,59 +371,97 @@ struct c_rpc_translater<schema::Interface<schema::Member<schema::Function<Reques
}
template<typename Interface>
-error_or<std::string> generate_c_rpc_interface(){
- std::stringstream iss;
- auto eov = impl::c_rpc_translater<Interface>::generate(iss, "c_saw");
+error_or<void> generate_c_interface(typename impl::c_types::state& state){
+ auto eov = impl::c_iface_translater<Interface>::generate(state);
+ return eov;
+}
- if(eov.is_error()){
- return std::move(eov.get_error());
+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;
- try {
- return iss.str();
- }catch(const std::exception& e){
- // Do nothing for now
+ 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;
}
- return make_error<err::out_of_memory>();
+ 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 Schema = schema::Array<schema::Int32,2>;
+ 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";
- std::map<std::string,std::string> map_str;
+ impl::c_types::state c_state;
+ c_state.prefix = prefix;
{
std::string type_str;
- auto eov = impl::c_data_translater<Schema>::generate(map_str, type_str, prefix);
+ 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(map_str, type_str, prefix);
+ 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(map_str, type_str, prefix);
+ auto eov = impl::c_data_translater<Schema3>::generate(c_state, type_str);
if(eov.is_error()){
return eov;
}
}
- std::cout<<"Prefix: "<<prefix<<std::endl;
+ std::cout<<"Prefix: "<<c_state.prefix<<std::endl;
- for(auto& iter : map_str){
+ for(auto& iter : c_state.struct_map){
std::cout<<"\nType: \""<<iter.first<<"\""<<std::endl;
std::cout<<"Definition:\n\"\"\"\n";
- std::cout<<iter.second;
+ std::cout<<iter.second.def;
std::cout<<"\"\"\""<<std::endl;
}