From d8af2d072ef0352318c7975968f41865af61ce92 Mon Sep 17 00:00:00 2001 From: Borislav Stanimirov Date: Tue, 3 Dec 2024 09:58:21 +0200 Subject: [PATCH] feat(schema): generate schema json, ref #149 --- astl/include/astl/tuple_util.hpp | 8 +-- dummy-plugin/CMakeLists.txt | 4 ++ dummy-plugin/code/ac/dummy/DummyInterface.hpp | 2 +- .../code/ac/dummy/DummyLoaderSchema.hpp | 7 +- dummy-plugin/example/CMakeLists.txt | 11 ++++ dummy-plugin/example/e-gen-dummy-schema.cpp | 12 ++++ local/code/ac/local/ModelLoader.hpp | 4 +- .../ac/schema/GenerateLoaderSchemaDict.hpp | 36 ++++++++++ schema/code/ac/schema/SchemaVisitor.hpp | 66 ++++++++----------- 9 files changed, 101 insertions(+), 49 deletions(-) create mode 100644 dummy-plugin/example/CMakeLists.txt create mode 100644 dummy-plugin/example/e-gen-dummy-schema.cpp create mode 100644 schema/code/ac/schema/GenerateLoaderSchemaDict.hpp diff --git a/astl/include/astl/tuple_util.hpp b/astl/include/astl/tuple_util.hpp index a9aa0df7..c9c1c63f 100644 --- a/astl/include/astl/tuple_util.hpp +++ b/astl/include/astl/tuple_util.hpp @@ -59,15 +59,15 @@ template struct expand_for_each { Func& f; template - constexpr void operator()(Args&... args) { - (f(args), ...); + constexpr void operator()(Args&&... args) { + (f(std::forward(args)), ...); } }; } // namespace impl template -constexpr void for_each(Tuple& tup, Func f) { - std::apply(impl::expand_for_each{f}, tup); +constexpr void for_each(Tuple&& tup, Func f) { + std::apply(impl::expand_for_each{f}, std::forward(tup)); } } // namespace astl::tuple diff --git a/dummy-plugin/CMakeLists.txt b/dummy-plugin/CMakeLists.txt index 7dd4d638..e9c9c6cf 100644 --- a/dummy-plugin/CMakeLists.txt +++ b/dummy-plugin/CMakeLists.txt @@ -8,3 +8,7 @@ if(AC_LOCAL_BUILD_TESTS OR AC_LOCAL_BUILD_EXAMPLES) endif() ac_local_add_test_subdir() + +if(AC_LOCAL_BUILD_EXAMPLES) + add_subdirectory(example) +endif() diff --git a/dummy-plugin/code/ac/dummy/DummyInterface.hpp b/dummy-plugin/code/ac/dummy/DummyInterface.hpp index 602b4b80..80c0b959 100644 --- a/dummy-plugin/code/ac/dummy/DummyInterface.hpp +++ b/dummy-plugin/code/ac/dummy/DummyInterface.hpp @@ -14,7 +14,7 @@ struct DummyInterface { struct OpRun { static constexpr auto id = "run"; - static constexpr auto desc = "Run the dummy inference and produce some output"; + static constexpr auto description = "Run the dummy inference and produce some output"; struct Params { Field> input; diff --git a/dummy-plugin/code/ac/dummy/DummyLoaderSchema.hpp b/dummy-plugin/code/ac/dummy/DummyLoaderSchema.hpp index 1dfa637c..ca13282d 100644 --- a/dummy-plugin/code/ac/dummy/DummyLoaderSchema.hpp +++ b/dummy-plugin/code/ac/dummy/DummyLoaderSchema.hpp @@ -8,7 +8,9 @@ namespace ac::local::schema { struct DummyLoader { - static constexpr auto id = "dummy"; + static inline constexpr std::string_view id = "dummy"; + static inline constexpr std::string_view description = "Dummy inference for tests, examples, and experiments."; + struct Params { Field spliceString = std::nullopt; @@ -19,7 +21,8 @@ struct DummyLoader { }; struct InstanceGeneral { - static constexpr auto id = "general"; + static inline constexpr std::string_view id = "general"; + static inline constexpr std::string_view description = "General instance"; struct Params { Field cutoff = Default(-1); diff --git a/dummy-plugin/example/CMakeLists.txt b/dummy-plugin/example/CMakeLists.txt new file mode 100644 index 00000000..1a42c73d --- /dev/null +++ b/dummy-plugin/example/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) Alpaca Core +# SPDX-License-Identifier: MIT +# +set(tgt example-ac-local-gen-dummy-schema) +add_executable(${tgt} + e-gen-dummy-schema.cpp +) +target_link_libraries(${tgt} + ac::schema + aclp-dummy-baselib +) diff --git a/dummy-plugin/example/e-gen-dummy-schema.cpp b/dummy-plugin/example/e-gen-dummy-schema.cpp new file mode 100644 index 00000000..4558fc74 --- /dev/null +++ b/dummy-plugin/example/e-gen-dummy-schema.cpp @@ -0,0 +1,12 @@ +// Copyright (c) Alpaca Core +// SPDX-License-Identifier: MIT +// +#include +#include +#include + +int main() { + auto d = ac::local::schema::generateLoaderSchema(); + std::cout << d.dump(2) << std::endl; + return 0; +} diff --git a/local/code/ac/local/ModelLoader.hpp b/local/code/ac/local/ModelLoader.hpp index 30247f48..477292e5 100644 --- a/local/code/ac/local/ModelLoader.hpp +++ b/local/code/ac/local/ModelLoader.hpp @@ -27,8 +27,8 @@ class AC_LOCAL_EXPORT ModelLoader { /// Optional human readable name of the loader vendor. std::string vendor; - /// Model schema for the models this loader produces. - Dict modelSchema; + /// Schema for the loader. + Dict schema; /// Additional tags that can be used to filter loaders std::vector tags; diff --git a/schema/code/ac/schema/GenerateLoaderSchemaDict.hpp b/schema/code/ac/schema/GenerateLoaderSchemaDict.hpp new file mode 100644 index 00000000..44bc2d90 --- /dev/null +++ b/schema/code/ac/schema/GenerateLoaderSchemaDict.hpp @@ -0,0 +1,36 @@ +// Copyright (c) Alpaca Core +// SPDX-License-Identifier: MIT +// +#pragma once +#include "SchemaVisitor.hpp" +#include + +namespace ac::local::schema { + +template +Dict generateLoaderSchema() { + Dict dict; + dict["id"] = Schema::id; + dict["description"] = Schema::description; + Struct_toSchema(dict["params"]); + + auto& is = dict["instances"]; + astl::tuple::for_each(typename Schema::Instances{}, [&](Instance) { + auto& i = is[Instance::id]; + i["description"] = Instance::description; + Struct_toSchema(i["params"]); + auto& os = i["ops"]; + astl::tuple::for_each(typename Instance::Interfaces{}, [&](Interface) { + astl::tuple::for_each(typename Interface::Ops{}, [&](Op) { + auto& o = os[Op::id]; + o["description"] = Op::description; + Struct_toSchema(o["params"]); + Struct_toSchema(o["return"]); + }); + }); + }); + + return dict; +} + +} diff --git a/schema/code/ac/schema/SchemaVisitor.hpp b/schema/code/ac/schema/SchemaVisitor.hpp index 32044c52..99b2fa18 100644 --- a/schema/code/ac/schema/SchemaVisitor.hpp +++ b/schema/code/ac/schema/SchemaVisitor.hpp @@ -24,47 +24,33 @@ struct SchemaVisitor { props = &out["properties"]; } - template - static void describeField(Dict& obj) { - obj["type"] = "integer"; - } - - template - static void describeField(Dict& obj) { - obj["type"] = "integer"; - } - - template - static void describeField(Dict& obj) { - obj["type"] = "number"; - } - - template S> - static void describeField(Dict& obj) { - obj["type"] = "string"; - } - - template B> - static void describeField(Dict& obj) { - obj["type"] = "boolean"; - } - - template N> - static void describeField(Dict& obj) { - obj["type"] = "null"; - } - - template - static void describeField(Dict& d) { - SchemaVisitor v(d); - V schema; - schema.visitFields(v); - } - - template + template static void describeField(Dict& obj) { - obj["type"] = "array"; - describeField(obj["items"]); + if constexpr (std::signed_integral || std::unsigned_integral) { + obj["type"] = "integer"; + } + else if constexpr (std::floating_point) { + obj["type"] = "number"; + } + else if constexpr (std::same_as || std::same_as) { + obj["type"] = "string"; + } + else if constexpr (std::same_as) { + obj["type"] = "boolean"; + } + else if constexpr (std::same_as) { + obj["type"] = "null"; + } + else if constexpr (Visitable) { + SchemaVisitor v(obj); + T schema; + schema.visitFields(v); + } + else { + // assume array + obj["type"] = "array"; + describeField(obj["items"]); + } } template