summaryrefslogtreecommitdiff
path: root/modules/tools/c_gen_iface.hpp
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/tools/c_gen_iface.hpp
parent84ecdcbca9e55b1f57fbb832e12ff4fdbb86e7c9 (diff)
meta: Renamed folder containing source
Diffstat (limited to 'modules/tools/c_gen_iface.hpp')
-rw-r--r--modules/tools/c_gen_iface.hpp535
1 files changed, 535 insertions, 0 deletions
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{};
+}
+}