Skip to content

Commit

Permalink
Added basic schema generation
Browse files Browse the repository at this point in the history
  • Loading branch information
liuzicheng1987 committed Dec 26, 2024
1 parent 5a898af commit 7419533
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 18 deletions.
2 changes: 1 addition & 1 deletion include/rfl/capnproto.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// #include "capnproto/load.hpp"
#include "capnproto/read.hpp"
// #include "capnproto/save.hpp"
// #include "capnproto/to_schema.hpp"
#include "capnproto/to_schema.hpp"
#include "capnproto/write.hpp"

#endif
2 changes: 2 additions & 0 deletions include/rfl/capnproto/schema/Type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ struct Type {

const auto& reflection() const { return value; }

Type with_name(const std::string& _name) const;

ReflectionType value;
};

Expand Down
8 changes: 4 additions & 4 deletions include/rfl/capnproto/to_schema.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@

namespace rfl::capnproto {

std::string to_json_representation(
std::string to_string_representation(
const parsing::schema::Definition& internal_schema);

/// Returns the Capnproto schema for a class.
/// Returns the Cap'n Proto schema for a class.
template <class T, class... Ps>
Schema<T> to_schema() noexcept {
const auto internal_schema =
parsing::schema::make<Reader, Writer, T, Processors<Ps...>>();
const auto json_str = to_json_representation(internal_schema);
return std::move(Schema<T>::from_json(json_str).value());
const auto str = to_string_representation(internal_schema);
return Schema<T>::from_string(str).value();
}
} // namespace rfl::capnproto

Expand Down
2 changes: 1 addition & 1 deletion src/reflectcpp_capnproto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ SOFTWARE.
#include "rfl/capnproto/SchemaImpl.cpp"
#include "rfl/capnproto/Type.cpp"
#include "rfl/capnproto/Writer.cpp"

#include "rfl/capnproto/to_schema.cpp"
16 changes: 15 additions & 1 deletion src/rfl/capnproto/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,20 @@ SOFTWARE.

namespace rfl::capnproto::schema {

Type Type::with_name(const std::string& _name) const {
const auto set_name = [&](const auto& _v) -> ReflectionType {
using T = std::remove_cvref_t<decltype(_v)>;
if constexpr (std::is_same<T, Struct>()) {
auto v_with_name = _v;
v_with_name.name = _name;
return v_with_name;
} else {
return _v;
}
};
return Type{.value = value.visit(set_name)};
}

std::ostream& operator<<(std::ostream& _os, const Type::Void&) {
return _os << "Void";
}
Expand Down Expand Up @@ -98,7 +112,7 @@ std::ostream& operator<<(std::ostream& _os, const Type::List& _l) {
}

std::ostream& operator<<(std::ostream& _os, const Type::Reference& _r) {
return _os << _r.type_name;
return _os;
}

std::ostream& operator<<(std::ostream& _os, const Type& _t) {
Expand Down
181 changes: 181 additions & 0 deletions src/rfl/capnproto/to_schema.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
MIT License
Copyright (c) 2023-2024 Code17 GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include "rfl/capnproto/to_schema.hpp"

#include <sstream>

#include "rfl/capnproto/schema/Type.hpp"
#include "rfl/internal/strings/split.hpp"
#include "rfl/json.hpp"
#include "rfl/parsing/schemaful/tuple_to_object.hpp"

namespace rfl::capnproto {

inline bool is_named_type(const parsing::schema::Type& _type) {
return _type.variant_.visit([&](const auto& _v) -> bool {
using T = std::remove_cvref_t<decltype(_v)>;
return std::is_same<T, parsing::schema::Type::Object>() ||
std::is_same<T, parsing::schema::Type::Literal>();
});
}

schema::Type type_to_capnproto_schema_type(
const parsing::schema::Type& _type,
const std::map<std::string, parsing::schema::Type>& _definitions,
std::set<std::string>* _already_known, size_t* _num_unnamed) {
auto handle_variant = [&](const auto& _t) -> schema::Type {
using T = std::remove_cvref_t<decltype(_t)>;
using Type = parsing::schema::Type;
if constexpr (std::is_same<T, Type::Boolean>()) {
return schema::Type{.value = schema::Type::Bool{}};

} else if constexpr (std::is_same<T, Type::Bytestring>()) {
return schema::Type{.value = schema::Type::Data{}};

} else if constexpr (std::is_same<T, Type::Int32>() ||
std::is_same<T, Type::Integer>()) {
return schema::Type{.value = schema::Type::Int32{}};

} else if constexpr (std::is_same<T, Type::Int64>()) {
return schema::Type{.value = schema::Type::Int64{}};

} else if constexpr (std::is_same<T, Type::UInt32>()) {
return schema::Type{.value = schema::Type::UInt32{}};

} else if constexpr (std::is_same<T, Type::UInt64>()) {
return schema::Type{.value = schema::Type::UInt64{}};

} else if constexpr (std::is_same<T, Type::Float>()) {
return schema::Type{.value = schema::Type::Float32{}};

} else if constexpr (std::is_same<T, Type::Double>()) {
return schema::Type{.value = schema::Type::Float64{}};

} else if constexpr (std::is_same<T, Type::String>()) {
return schema::Type{.value = schema::Type::Text{}};

} else if constexpr (std::is_same<T, Type::AnyOf>()) {
// TODO
return schema::Type{.value = schema::Type::Void{}};

} else if constexpr (std::is_same<T, Type::Description>()) {
return type_to_capnproto_schema_type(*_t.type_, _definitions,
_already_known, _num_unnamed);

} else if constexpr (std::is_same<T, Type::FixedSizeTypedArray>()) {
return schema::Type{
.value = schema::Type::List{
.type = Ref<schema::Type>::make(type_to_capnproto_schema_type(
*_t.type_, _definitions, _already_known, _num_unnamed))}};

} else if constexpr (std::is_same<T, Type::Literal>()) {
// TODO
return schema::Type{.value = schema::Type::Void{}};
/*return schema::Type{
.value = schema::Type::Enum{.name = std::string("unnamed_") +
std::to_string(++(*_num_unnamed)),
.symbols = _t.values_}};*/

} else if constexpr (std::is_same<T, Type::Object>()) {
auto struct_schema = schema::Type::Struct{
.name = std::string("Unnamed") + std::to_string(++(*_num_unnamed))};
for (const auto& [k, v] : _t.types_) {
struct_schema.fields.push_back(std::make_pair(
k, type_to_capnproto_schema_type(v, _definitions, _already_known,
_num_unnamed)));
}
return schema::Type{.value = struct_schema};

} else if constexpr (std::is_same<T, Type::Optional>()) {
// TODO
return schema::Type{.value = schema::Type::Void{}};
/*return schema::Type{
.value = std::vector<schema::Type>(
{type_to_capnproto_schema_type(*_t.type_, _definitions,
_already_known, _num_unnamed),
schema::Type{schema::Type::Null{}}})};*/

} else if constexpr (std::is_same<T, Type::Reference>()) {
return schema::Type{.value =
schema::Type::Reference{.type_name = _t.name_}};

} else if constexpr (std::is_same<T, Type::StringMap>()) {
// TODO
return schema::Type{.value = schema::Type::Void{}};
/*return schema::Type{
.value = schema::Type::Map{
.values = Ref<schema::Type>::make(type_to_capnproto_schema_type(
*_t.value_type_, _definitions, _already_known,
_num_unnamed))}};*/

} else if constexpr (std::is_same<T, Type::Tuple>()) {
return type_to_capnproto_schema_type(
Type{parsing::schemaful::tuple_to_object(_t)}, _definitions,
_already_known, _num_unnamed);

} else if constexpr (std::is_same<T, Type::TypedArray>()) {
return schema::Type{
.value = schema::Type::List{
.type = Ref<schema::Type>::make(type_to_capnproto_schema_type(
*_t.type_, _definitions, _already_known, _num_unnamed))}};

} else if constexpr (std::is_same<T, Type::Validated>()) {
// Cap'n Proto knows no validation.
return type_to_capnproto_schema_type(*_t.type_, _definitions,
_already_known, _num_unnamed);

} else {
static_assert(rfl::always_false_v<T>, "Not all cases were covered.");
}
};

return rfl::visit(handle_variant, _type.variant_);
}

std::string to_string_representation(
const parsing::schema::Definition& _internal_schema) {
std::set<std::string> already_known;
size_t num_unnamed = 0;
const auto capnproto_schema = type_to_capnproto_schema_type(
_internal_schema.root_, _internal_schema.definitions_, &already_known,
&num_unnamed);
std::stringstream sstream;
// TODO: ID is hardcoded.
sstream << "@0xdbb9ad1f14bf0b36;" << std::endl
<< std::endl
<< capnproto_schema;
for (const auto& [name, def] : _internal_schema.definitions_) {
sstream << type_to_capnproto_schema_type(def, _internal_schema.definitions_,
&already_known, &num_unnamed)
.with_name(internal::strings::split(name, "__").back())
<< std::endl
<< std::endl;
}
return sstream.str();
}

} // namespace rfl::capnproto
12 changes: 1 addition & 11 deletions tests/capnproto/test_person.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,13 @@

namespace test_tutorial_example {

const std::string PERSON_SCHEMA = R"(
@0xb07899ba441fd7ec;
struct Person {
firstName @0 :Text;
lastName @1 :Text;
}
)";

struct Person {
std::string firstName;
std::string lastName;
};

TEST(capnproto, test_person) {
const auto schema =
rfl::capnproto::Schema<Person>::from_string(PERSON_SCHEMA).value();
const auto schema = rfl::capnproto::to_schema<Person>();
const auto homer1 = Person{.firstName = "Homer", .lastName = "Simpson"};
const auto serialized1 = rfl::capnproto::write(homer1, schema);
const auto homer2 = rfl::capnproto::read<Person>(serialized1, schema).value();
Expand Down

0 comments on commit 7419533

Please sign in to comment.