Skip to content

Commit

Permalink
Added support for optionals
Browse files Browse the repository at this point in the history
  • Loading branch information
liuzicheng1987 committed Dec 29, 2024
1 parent bb78efd commit 96c1ec8
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 91 deletions.
27 changes: 11 additions & 16 deletions include/rfl/capnproto/Reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@

namespace rfl::capnproto {

struct Reader {
class Reader {
public:
struct CapNProtoInputArray {
capnp::DynamicList::Reader val_;
};
Expand Down Expand Up @@ -143,9 +144,6 @@ struct Reader {
std::optional<Error> read_object(const ObjectReader& _object_reader,
const InputObjectType& _obj) const noexcept {
for (auto field : _obj.val_.getSchema().getFields()) {
if (!_obj.val_.has(field)) {
continue;
}
_object_reader.read(field.getProto().getName().cStr(),
InputVarType{_obj.val_.get(field)});
}
Expand All @@ -155,20 +153,13 @@ struct Reader {
template <class VariantType, class UnionReaderType>
rfl::Result<VariantType> read_union(
const InputUnionType& _union) const noexcept {
// TODO
/*int disc = 0;
auto err = capnproto_value_get_discriminant(_union.val_, &disc);
if (err) {
const auto opt_pair = identify_discriminant(_union);
if (!opt_pair) {
return Error("Could not get the discriminant.");
}
capnproto_value_t value;
err = capnproto_value_get_current_branch(_union.val_, &value);
if (err) {
return Error("Could not cast the union type.");
}
return UnionReaderType::read(*this, static_cast<size_t>(disc),
InputVarType{&value});*/
return Error("TODO");
const auto& [field, disc] = *opt_pair;
return UnionReaderType::read(*this, disc,
InputVarType{_union.val_.get(field)});
}

template <class T>
Expand All @@ -180,6 +171,10 @@ struct Reader {
return rfl::Error(e.what());
}
}

private:
std::optional<std::pair<capnp::StructSchema::Field, size_t>>
identify_discriminant(const InputUnionType& _union) const noexcept;
};

} // namespace rfl::capnproto
Expand Down
60 changes: 14 additions & 46 deletions include/rfl/capnproto/Writer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,60 +202,28 @@ class Writer {
template <class T>
OutputVarType add_value_to_union(const size_t _index, const T& _var,
OutputUnionType* _parent) const noexcept {
const auto field_maybe = _parent->val_.getSchema().getFieldByDiscriminant(
static_cast<uint16_t>(_index));
field_maybe.map([&](const auto& _field) {
if constexpr (std::is_same<std::remove_cvref_t<T>, std::string>()) {
_parent->val_.set(_field, _var.c_str());

} else if constexpr (std::is_floating_point<std::remove_cvref_t<T>>() ||
std::is_same<std::remove_cvref_t<T>, bool>()) {
_parent->val_.set(_field, _var);

} else if constexpr (std::is_integral<std::remove_cvref_t<T>>()) {
_parent->val_.set(_field, static_cast<std::int64_t>(_var));

} else {
static_assert(rfl::always_false_v<T>, "Unsupported type.");
}
return _field;
});
return OutputVarType{};
}

void end_array(OutputArrayType* _arr) const noexcept {}

void end_map(OutputMapType* _obj) const noexcept {}

void end_object(OutputObjectType* _obj) const noexcept {}

private:
/*template <class T>
void set_value(const T& _var, capnproto_value_t* _val) const noexcept {
const auto field = _parent->val_.getSchema().getFields()[_index];
if constexpr (std::is_same<std::remove_cvref_t<T>, std::string>()) {
capnproto_value_set_string_len(_val, _var.c_str(), _var.size() + 1);
} else if constexpr (std::is_same<std::remove_cvref_t<T>,
rfl::Bytestring>()) {
auto var = _var;
capnproto_value_set_bytes(_val, var.data(), var.size() + 1);
} else if constexpr (std::is_same<std::remove_cvref_t<T>, bool>()) {
capnproto_value_set_boolean(_val, _var);
_parent->val_.set(field, _var.c_str());

} else if constexpr (std::is_floating_point<std::remove_cvref_t<T>>()) {
capnproto_value_set_double(_val, static_cast<double>(_var));
} else if constexpr (std::is_floating_point<std::remove_cvref_t<T>>() ||
std::is_same<std::remove_cvref_t<T>, bool>()) {
_parent->val_.set(field, _var);

} else if constexpr (std::is_integral<std::remove_cvref_t<T>>()) {
capnproto_value_set_long(_val, static_cast<std::int64_t>(_var));
} else if constexpr (internal::is_literal_v<T>) {
capnproto_value_set_enum(_val, static_cast<int>(_var.value()));
_parent->val_.set(field, static_cast<std::int64_t>(_var));

} else {
static_assert(rfl::always_false_v<T>, "Unsupported type.");
}
}*/
return OutputVarType{};
}

void end_array(OutputArrayType* _arr) const noexcept {}

void end_map(OutputMapType* _obj) const noexcept {}

void end_object(OutputObjectType* _obj) const noexcept {}

private:
capnp::DynamicStruct::Builder* root_;
Expand Down
13 changes: 12 additions & 1 deletion src/rfl/capnproto/Reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,19 @@ namespace rfl::capnproto {
static_assert(parsing::schemaful::IsSchemafulReader<Reader>,
"This must be a schemaful reader.");

std::optional<std::pair<capnp::StructSchema::Field, size_t>>
Reader::identify_discriminant(const InputUnionType& _union) const noexcept {
size_t ix = 0;
for (auto field : _union.val_.getSchema().getFields()) {
if (_union.val_.has(field)) {
return std::make_pair(field, ix);
}
++ix;
}
return std::nullopt;
}

bool Reader::is_empty(const InputVarType& _var) const noexcept {
// TODO: Is this correct?
return _var.val_.getType() == capnp::DynamicValue::VOID;
}

Expand Down
19 changes: 4 additions & 15 deletions src/rfl/capnproto/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,9 @@ Writer::OutputArrayType Writer::add_array_to_object(
Writer::OutputArrayType Writer::add_array_to_union(
const size_t _index, const size_t _size,
OutputUnionType* _parent) const noexcept {
const auto field_maybe = _parent->val_.getSchema().getFieldByDiscriminant(
static_cast<uint16_t>(_index));
const auto field = _parent->val_.getSchema().getFields()[_index];
return OutputArrayType{
field_maybe
.map([&](const auto& _field) {
return _parent->val_.init(_field, _size)
.template as<capnp::DynamicList>();
})
.orDefault(_parent->val_.init("indexOutOfRange", _size)
.template as<capnp::DynamicList>())};
_parent->val_.init(field, _size).template as<capnp::DynamicList>()};
}

Writer::OutputMapType Writer::add_map_to_array(
Expand Down Expand Up @@ -183,12 +176,8 @@ return OutputVarType{new_null};*/

Writer::OutputVarType Writer::add_null_to_union(
const size_t _index, OutputUnionType* _parent) const noexcept {
const auto field_maybe = _parent->val_.getSchema().getFieldByDiscriminant(
static_cast<uint16_t>(_index));
field_maybe.map([&](const auto& _field) {
_parent->val_.set(_field, capnp::VOID);
return _field;
});
const auto field = _parent->val_.getSchema().getFields()[_index];
_parent->val_.set(field, capnp::VOID);
return OutputVarType{};
}

Expand Down
17 changes: 4 additions & 13 deletions src/rfl/capnproto/to_schema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,18 +111,13 @@ schema::Type type_to_capnproto_schema_type(
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,
_num_unnamed),
schema::Type{schema::Type::Null{}}})};*/

return schema::Type{
.value = schema::Type::Optional{
.type = Ref<schema::Type>::make(type_to_capnproto_schema_type(
*_t.type_, _definitions, _num_unnamed))}};
} 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{}};
Expand All @@ -131,23 +126,19 @@ schema::Type type_to_capnproto_schema_type(
.values = Ref<schema::Type>::make(type_to_capnproto_schema_type(
*_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,
_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, _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,
_num_unnamed);

} else {
static_assert(rfl::always_false_v<T>, "Not all cases were covered.");
}
Expand Down
30 changes: 30 additions & 0 deletions tests/capnproto/test_optional_fields.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include <iostream>
#include <rfl.hpp>
#include <rfl/json.hpp>
#include <string>
#include <vector>

#include "write_and_read.hpp"

namespace test_optional_fields {

struct Person {
std::string first_name;
std::string last_name = "Simpson";
std::optional<std::vector<Person>> children;
};

TEST(capnproto, test_optional_fields) {
const auto bart = Person{.first_name = "Bart"};

const auto lisa = Person{.first_name = "Lisa"};

const auto maggie = Person{.first_name = "Maggie"};

const auto homer =
Person{.first_name = "Homer",
.children = std::vector<Person>({bart, lisa, maggie})};

write_and_read(homer);
}
} // namespace test_optional_fields
4 changes: 4 additions & 0 deletions tests/capnproto/write_and_read.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <iostream>
#include <rfl/capnproto.hpp>
#include <rfl/json.hpp>
#include <string>

template <class... Ps>
Expand All @@ -16,5 +17,8 @@ void write_and_read(const auto& _struct) {
<< res.error().value().what();
const auto serialized2 = rfl::capnproto::write<Ps...>(res.value());
EXPECT_EQ(serialized1, serialized2);

// For temporary testing only, remove later.
std::cout << rfl::json::write(res.value()) << std::endl;
}
#endif

0 comments on commit 96c1ec8

Please sign in to comment.