Skip to content

Commit

Permalink
More robust handling of the type names
Browse files Browse the repository at this point in the history
  • Loading branch information
liuzicheng1987 committed Dec 26, 2024
1 parent 7419533 commit 3031862
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 45 deletions.
10 changes: 7 additions & 3 deletions include/rfl/capnproto/read.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
#include <type_traits>

#include "../Processors.hpp"
#include "../SnakeCaseToCamelCase.hpp"
#include "../internal/strings/to_pascal_case.hpp"
#include "../internal/wrap_in_rfl_array_t.hpp"
#include "../parsing/make_type_name.hpp"
#include "Parser.hpp"
#include "Reader.hpp"
#include "Schema.hpp"
Expand All @@ -26,7 +29,7 @@ using InputVarType = typename Reader::InputVarType;
template <class T, class... Ps>
auto read(const InputVarType& _obj) {
const auto r = Reader();
return Parser<T, Processors<Ps...>>::read(r, _obj);
return Parser<T, Processors<SnakeCaseToCamelCase, Ps...>>::read(r, _obj);
}

/// Parses an object from CAPNPROTO using reflection.
Expand All @@ -37,8 +40,9 @@ Result<internal::wrap_in_rfl_array_t<T>> read(
internal::ptr_cast<const kj::byte*>(_bytes), _size);
auto input_stream = kj::ArrayInputStream(array_ptr);
auto message_reader = capnp::PackedMessageReader(input_stream);
// TODO: Person is hardcoded.
const auto root_schema = _schema.value().getNested("Person");
const auto root_name = internal::strings::to_pascal_case(
parsing::make_type_name<std::remove_cvref_t<T>>());
const auto root_schema = _schema.value().getNested(root_name.c_str());
const auto input_var = InputVarType{
message_reader.getRoot<capnp::DynamicStruct>(root_schema.asStruct())};
return read<T, Ps...>(input_var);
Expand Down
12 changes: 8 additions & 4 deletions include/rfl/capnproto/write.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
#include <type_traits>
#include <utility>

#include "../SnakeCaseToCamelCase.hpp"
#include "../internal/ptr_cast.hpp"
#include "../internal/strings/to_pascal_case.hpp"
#include "../parsing/Parent.hpp"
#include "../parsing/make_type_name.hpp"
#include "Parser.hpp"
#include "Schema.hpp"
#include "Writer.hpp"
Expand All @@ -33,14 +36,15 @@ std::vector<char> write(const auto& _obj, const auto& _schema) noexcept {
using ParentType = parsing::Parent<Writer>;
static_assert(std::is_same<T, U>(),
"The schema must be compatible with the type to write.");
// TODO: Person is hardcoded.
const auto root_schema = _schema.value().getNested("Person");
const auto root_name = internal::strings::to_pascal_case(
parsing::make_type_name<std::remove_cvref_t<T>>());
const auto root_schema = _schema.value().getNested(root_name.c_str());
capnp::MallocMessageBuilder message_builder;
auto root =
message_builder.initRoot<capnp::DynamicStruct>(root_schema.asStruct());
const auto writer = Writer(&root);
Parser<T, Processors<Ps...>>::write(writer, _obj,
typename ParentType::Root{});
Parser<T, Processors<SnakeCaseToCamelCase, Ps...>>::write(
writer, _obj, typename ParentType::Root{});
kj::VectorOutputStream output_stream;
capnp::writePackedMessage(output_stream, message_builder);
auto arr_ptr = output_stream.getArray();
Expand Down
40 changes: 40 additions & 0 deletions include/rfl/internal/strings/to_pascal_case.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef RFL_INTERNAL_STRINGS_TOPASCALCASE_HPP_
#define RFL_INTERNAL_STRINGS_TOPASCALCASE_HPP_

#include <string>
#include <vector>

namespace rfl {
namespace internal {
namespace strings {

inline char to_upper(const char ch) {
if (ch >= 'a' && ch <= 'z') {
return ch + ('A' - 'a');
} else {
return ch;
}
}

/// Splits a string alongside the delimiter
inline std::string to_pascal_case(const std::string& _str) {
std::string result;
bool capitalize = true;
for (const char ch : _str) {
if (ch == '_') {
capitalize = true;
} else if (capitalize) {
result.push_back(to_upper(ch));
capitalize = false;
} else {
result.push_back(ch);
}
}
return result;
}

} // namespace strings
} // namespace internal
} // namespace rfl

#endif
19 changes: 1 addition & 18 deletions include/rfl/parsing/Parser_default.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@
#include "../internal/ptr_cast.hpp"
#include "../internal/to_ptr_named_tuple.hpp"
#include "../to_view.hpp"
#include "../type_name_t.hpp"
#include "AreReaderAndWriter.hpp"
#include "Parent.hpp"
#include "Parser_base.hpp"
#include "call_destructors_where_necessary.hpp"
#include "is_tagged_union_wrapper.hpp"
#include "make_type_name.hpp"
#include "schema/Type.hpp"
#include "schemaful/IsSchemafulReader.hpp"
#include "schemaful/IsSchemafulWriter.hpp"
Expand Down Expand Up @@ -265,16 +265,6 @@ struct Parser {
.validation_ = ValidationType::template to_schema<ReflectionType>()}};
}

template <class U>
static std::string make_type_name() {
if constexpr (is_tagged_union_wrapper_v<U>) {
return replace_non_alphanumeric(type_name_t<typename U::Type>().str() +
"__tagged");
} else {
return replace_non_alphanumeric(type_name_t<U>().str());
}
}

/// The way this works is that we allocate space on the stack in this size of
/// the struct in which we then write the individual fields using
/// views and placement new. This is how we deal with the fact that some
Expand Down Expand Up @@ -312,13 +302,6 @@ struct Parser {
}
return t;
}

static std::string replace_non_alphanumeric(std::string _str) {
for (auto& ch : _str) {
ch = std::isalnum(ch) ? ch : '_';
}
return _str;
}
};

} // namespace rfl::parsing
Expand Down
30 changes: 30 additions & 0 deletions include/rfl/parsing/make_type_name.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef RFL_PARSING_MAKETYPENAME_HPP_
#define RFL_PARSING_MAKETYPENAME_HPP_

#include "../type_name_t.hpp"
#include "is_tagged_union_wrapper.hpp"

namespace rfl {
namespace parsing {

inline std::string replace_non_alphanumeric(std::string _str) {
for (auto& ch : _str) {
ch = std::isalnum(ch) ? ch : '_';
}
return _str;
}

template <class U>
static std::string make_type_name() {
if constexpr (is_tagged_union_wrapper_v<U>) {
return replace_non_alphanumeric(type_name_t<typename U::Type>().str() +
"__tagged");
} else {
return replace_non_alphanumeric(type_name_t<U>().str());
}
}

} // namespace parsing
} // namespace rfl

#endif
4 changes: 3 additions & 1 deletion src/rfl/capnproto/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ SOFTWARE.

#include "rfl/capnproto/schema/Type.hpp"

#include "rfl/internal/strings/to_pascal_case.hpp"

namespace rfl::capnproto::schema {

Type Type::with_name(const std::string& _name) const {
Expand Down Expand Up @@ -112,7 +114,7 @@ std::ostream& operator<<(std::ostream& _os, const Type::List& _l) {
}

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

std::ostream& operator<<(std::ostream& _os, const Type& _t) {
Expand Down
32 changes: 13 additions & 19 deletions src/rfl/capnproto/to_schema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ SOFTWARE.

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

Expand All @@ -46,7 +47,7 @@ inline bool is_named_type(const parsing::schema::Type& _type) {
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) {
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;
Expand Down Expand Up @@ -84,13 +85,13 @@ schema::Type type_to_capnproto_schema_type(

} else if constexpr (std::is_same<T, Type::Description>()) {
return type_to_capnproto_schema_type(*_t.type_, _definitions,
_already_known, _num_unnamed);
_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))}};
*_t.type_, _definitions, _num_unnamed))}};

} else if constexpr (std::is_same<T, Type::Literal>()) {
// TODO
Expand All @@ -105,8 +106,7 @@ schema::Type type_to_capnproto_schema_type(
.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)));
k, type_to_capnproto_schema_type(v, _definitions, _num_unnamed)));
}
return schema::Type{.value = struct_schema};

Expand All @@ -116,7 +116,7 @@ schema::Type type_to_capnproto_schema_type(
/*return schema::Type{
.value = std::vector<schema::Type>(
{type_to_capnproto_schema_type(*_t.type_, _definitions,
_already_known, _num_unnamed),
_num_unnamed),
schema::Type{schema::Type::Null{}}})};*/

} else if constexpr (std::is_same<T, Type::Reference>()) {
Expand All @@ -129,24 +129,24 @@ schema::Type type_to_capnproto_schema_type(
/*return schema::Type{
.value = schema::Type::Map{
.values = Ref<schema::Type>::make(type_to_capnproto_schema_type(
*_t.value_type_, _definitions, _already_known,
*_t.value_type_, _definitions,
_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);
_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))}};
*_t.type_, _definitions, _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);
_num_unnamed);

} else {
static_assert(rfl::always_false_v<T>, "Not all cases were covered.");
Expand All @@ -158,20 +158,14 @@ schema::Type type_to_capnproto_schema_type(

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;
sstream << "@0xdbb9ad1f14bf0b36;" << std::endl << std::endl;
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())
&num_unnamed)
.with_name(internal::strings::to_pascal_case(name))
<< std::endl
<< std::endl;
}
Expand Down

0 comments on commit 3031862

Please sign in to comment.