#include #include #include #include #include #include #include #include #include #include namespace saw { namespace binding { struct SyncC {}; } /** * 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 string_literal name = "int8"; static constexpr string_literal value = "int8_t"; }; template<> struct c_primitive_string { static constexpr string_literal name = "int16"; static constexpr string_literal value = "int16_t"; }; template<> struct c_primitive_string { static constexpr string_literal name = "int32"; static constexpr string_literal value = "int32_t"; }; template<> struct c_primitive_string { static constexpr string_literal name = "int64"; static constexpr string_literal value = "int64_t"; }; template<> struct c_primitive_string { static constexpr string_literal name = "uint8"; static constexpr string_literal value = "uint8_t"; }; template<> struct c_primitive_string { static constexpr string_literal name = "uint16"; static constexpr string_literal value = "uint16_t"; }; template<> struct c_primitive_string { static constexpr string_literal name = "uint32"; static constexpr string_literal value = "uint32_t"; }; template<> struct c_primitive_string { static constexpr string_literal name = "uint64"; static constexpr string_literal value = "uint64_t"; }; template<> struct c_primitive_string { static constexpr string_literal name = "float32"; static constexpr string_literal value = "float"; }; template<> struct c_primitive_string { static constexpr string_literal name = "float64"; static constexpr string_literal value = "double"; }; struct language_binding_config { std::string prefix; }; namespace impl { template struct lang_bind { static_assert(always_false, "Not supported"); }; 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 lang_bind, binding::SyncC> { using Schema = schema::Primitive; static error_or generate(buffer& buff, buffer& src, 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; } } { auto eov = lang_bind_helper::append_string(buff, c_primitive_string::value.view()); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, " "); if(eov.is_error()){ return eov; } } { 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; } } } } return void_t{}; } }; template struct lang_bind, binding::SyncC> { using Schema = schema::Array; static_assert(is_primitive::value, "Currently only primitive type arrays are supported"); static error_or generate(buffer& buff, buffer& src, 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::generate(buff, src, cfg, state); if(eov.is_error()){ return eov; } } { auto eov = lang_bind::generate(buff, src, cfg, state); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "struct "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_hashed_type(buff, cfg.prefix, hash); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, " {\n\t"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_hashed_type(buff, cfg.prefix, schema_hash::apply()); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "* data;\n\t"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_hashed_type(buff, cfg.prefix, schema_hash::apply()); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, " length;\n};\n"); if(eov.is_error()){ return eov; } } } return void_t{}; } }; template struct lang_bind, binding::SyncC> { static error_or append_function_def(buffer& buff, const language_binding_config& cfg, language_binding_state& state, const std::string_view& f_name){ { auto eov = lang_bind_helper::append_string(buff, "int "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, f_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, " ( "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_context* ctx, const "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, f_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_input_t* input, "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, f_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_output_t* output )"); if(eov.is_error()){ return eov; } } return void_t{}; } static error_or generate(buffer& buff, buffer& src, const language_binding_config& cfg, language_binding_state& state, const std::string_view& f_name){ constexpr uint64_t input_hash = schema_hash::apply(); constexpr uint64_t output_hash = schema_hash::apply(); { auto eov = lang_bind::generate(buff, src, cfg, state); if(eov.is_error()){ return eov; } } { auto eov = lang_bind::generate(buff, src, cfg, state); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "typedef "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_hashed_type(buff, cfg.prefix, schema_hash::apply()); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, " "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, f_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_input_t;\n"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "typedef "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_hashed_type(buff, cfg.prefix, schema_hash::apply()); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, " "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, f_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_output_t;\n"); if(eov.is_error()){ return eov; } } { auto eov = append_function_def(buff, cfg, state, f_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, ";\n\n"); if(eov.is_error()){ return eov; } } return void_t{}; } }; template struct lang_bind, binding::SyncC> { template static error_or generate_element(buffer& buff, buffer& src, 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; { auto eov = lang_bind::generate(buff, src, cfg, state, MKey.view()); if(eov.is_error()){ return eov; } } if constexpr ((i+1) < sizeof...(M) ){ return generate_element(buff, src, cfg, state); } return void_t{}; } static error_or generate(buffer& buff, buffer& src, const language_binding_config& cfg){ if(cfg.prefix.size() == 0){ return make_error("C interfaces need a prefix."); } language_binding_state state; /** * Setup context creation to bind interface to a context */ /** * Context definition */ /// @todo Add Macro which reduces typing time ? Not really that much shorter :/ // SAW_CALL_AND_RETURN_ON_ERROR(lang_bind_helper::append_string(buff, "struct ")); { auto eov = lang_bind_helper::append_string(buff, "struct "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_context {\n\tvoid* ctx;\n};\n\n"); if(eov.is_error()){ return eov; } } /** * Create and destroy declaration */ auto ctx_func = [&](std::string_view str) -> error_or{ { auto eov = lang_bind_helper::append_string(buff, "int "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_context_"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, str); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, " ( "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_context* ctx );\n\n"); if(eov.is_error()){ return eov; } } return void_t{}; }; { auto eov = ctx_func("create"); if(eov.is_error()){ return eov; } } { auto eov = ctx_func("destroy"); if(eov.is_error()){ return eov; } } if constexpr (sizeof...(M) > 0){ return generate_element<0>(buff, src, cfg, state); } return void_t{}; } }; } template struct language_binding { static_assert(always_false, "Case not supported."); }; template struct language_binding { static error_or generate(buffer& buff, buffer& src, const language_binding_config& cfg){ return impl::lang_bind::generate(buff, src, cfg); } }; }