Skip to content

Commit

Permalink
Made it work for most tests
Browse files Browse the repository at this point in the history
  • Loading branch information
liuzicheng1987 committed Nov 9, 2024
1 parent deb7154 commit ab72519
Show file tree
Hide file tree
Showing 43 changed files with 1,396 additions and 77 deletions.
99 changes: 40 additions & 59 deletions include/rfl/ubjson/Reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#include <cstddef>
#include <exception>
#include <jsoncons_ext/ubjson/ubjson_cursor.hpp>
#include <jsoncons/json.hpp>
#include <string>
#include <string_view>
#include <type_traits>
Expand All @@ -15,25 +15,28 @@

namespace rfl::ubjson {

struct Reader {
using CursorType = jsoncons::ubjson::ubjson_bytes_cursor;

class Reader {
public:
struct UBJSONInputArray {
CursorType* cursor_;
jsoncons::json* val_;
};

struct UBJSONInputObject {
CursorType* cursor_;
jsoncons::json* val_;
};

struct UBJSONInputVar {
CursorType* cursor_;
jsoncons::json* val_;
};

using InputArrayType = UBJSONInputArray;
using InputObjectType = UBJSONInputObject;
using InputVarType = UBJSONInputVar;

Reader() {}

~Reader() = default;

template <class T>
static constexpr bool has_custom_constructor = (requires(InputVarType var) {
T::from_ubjson_obj(var);
Expand All @@ -49,85 +52,63 @@ struct Reader {

template <class T>
rfl::Result<T> to_basic_type(const InputVarType& _var) const noexcept {
const auto& event = _var.cursor_->current();
const auto event_type = event.event_type();
if constexpr (std::is_same<std::remove_cvref_t<T>, std::string>()) {
if (event_type != jsoncons::staj_event_type::string_value) {
if (!_var.val_->is_string()) {
return Error("Could not cast to string.");
}
return std::string(event.get<std::string_view>());

/* } else if constexpr (std::is_same<std::remove_cvref_t<T>,
rfl::Bytestring>()) {
if (!ubjson_value_is_byte_string(&_var.val_)) {
return Error("Could not cast to bytestring.");
}
rfl::Bytestring bstr;
const auto err = get_bytestring(&_var.val_, &bstr);
if (err != CborNoError) {
return Error(ubjson_error_string(err));
}
return bstr;*/
return _var.val_->as<std::string>();
} else if constexpr (std::is_same<std::remove_cvref_t<T>,
rfl::Bytestring>()) {
if (!_var.val_->is_byte_string()) {
return Error("Could not cast to bytestring.");
}
return rfl::Bytestring(); // TODO
} else if constexpr (std::is_same<std::remove_cvref_t<T>, bool>()) {
if (event_type != jsoncons::staj_event_type::bool_value) {
if (!_var.val_->is_bool()) {
return rfl::Error("Could not cast to boolean.");
}
return std::string(event.get<bool>());
return _var.val_->as<bool>();
} else if constexpr (std::is_floating_point<std::remove_cvref_t<T>>() ||
std::is_integral<std::remove_cvref_t<T>>()) {
switch (event_type) {
case jsoncons::staj_event_type::int64_value:
return static_cast<T>(event.get<int64_t>());
case jsoncons::staj_event_type::uint64_value:
return static_cast<T>(event.get<uint64_t>());
case jsoncons::staj_event_type::double_value:
return static_cast<T>(event.get<double>());
default:
return rfl::Error(
"Could not cast to numeric value. The type must be integral, "
"float or double.");
if (_var.val_->is_double()) {
return static_cast<T>(_var.val_->as<double>());
}
if (_var.val_->is_int64()) {
return static_cast<T>(_var.val_->as<int64_t>());
}
if (_var.val_->is_uint64()) {
return static_cast<T>(_var.val_->as<uint64_t>());
}
return rfl::Error(
"Could not cast to numeric value. The type must be integral, "
"float or double.");
} else {
static_assert(rfl::always_false_v<T>, "Unsupported type.");
}
}

rfl::Result<InputArrayType> to_array(const InputVarType& _var) const noexcept;
rfl::Result<InputArrayType> to_array(InputVarType _var) const noexcept;

rfl::Result<InputObjectType> to_object(
const InputVarType& _var) const noexcept;
rfl::Result<InputObjectType> to_object(InputVarType _var) const noexcept;

template <class ArrayReader>
std::optional<Error> read_array(const ArrayReader& _array_reader,
const InputArrayType& _arr) const noexcept {
for (const auto& event = _arr.cursor_->current();
event.event_type() != jsoncons::staj_event_type::end_array;
_arr.cursor_->next()) {
const auto err = _array_reader.read(InputVarType{_arr.cursor_});
std::optional<Error> read_array(ArrayReader _array_reader,
InputArrayType _arr) const noexcept {
for (auto& val : _arr.val_->array_range()) {
const auto err = _array_reader.read(InputVarType{&val});
if (err) {
// TODO: Go to end of cursor
return err;
}
}
_arr.cursor_->next();
return std::nullopt;
}

template <class ObjectReader>
std::optional<Error> read_object(const ObjectReader& _object_reader,
const InputObjectType& _obj) const noexcept {
for (const auto& event = _obj.cursor_->current();
event.event_type() != jsoncons::staj_event_type::end_object;
_obj.cursor_->next()) {
if (event.event_type() != jsoncons::staj_event_type::key) {
_obj.cursor_->reset();
_obj.cursor_->reset();
return Error("Expected a key.");
}
const auto key = event.get<std::string_view>();
_object_reader.read(key, InputVarType{_obj.cursor_});
InputObjectType _obj) const noexcept {
for (auto& kv : _obj.val_->object_range()) {
_object_reader.read(kv.key(), InputVarType{&kv.value()});
}
_obj.cursor_->next();
return std::nullopt;
}

Expand Down
7 changes: 4 additions & 3 deletions include/rfl/ubjson/read.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

#include <bit>
#include <istream>
#include <jsoncons_ext/ubjson/ubjson_cursor.hpp>
#include <jsoncons/json.hpp>
#include <jsoncons_ext/ubjson/decode_ubjson.hpp>
#include <string>

#include "../Processors.hpp"
Expand All @@ -23,9 +24,9 @@ Result<internal::wrap_in_rfl_array_t<T>> read(const char* _bytes,
auto buffer =
std::vector<uint8_t>(std::bit_cast<const uint8_t*>(_bytes),
std::bit_cast<const uint8_t*>(_bytes) + _size);
auto cursor = jsoncons::ubjson::ubjson_bytes_cursor(buffer);
auto val = jsoncons::ubjson::decode_ubjson<jsoncons::json>(buffer);
auto r = Reader();
auto result = Parser<T, Processors<Ps...>>::read(r, InputVarType{&cursor});
auto result = Parser<T, Processors<Ps...>>::read(r, InputVarType{&val});
return result;
}

Expand Down
29 changes: 17 additions & 12 deletions src/rfl/ubjson/Reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,40 @@ namespace rfl::ubjson {

rfl::Result<Reader::InputVarType> Reader::get_field_from_array(
const size_t _idx, const InputArrayType& _arr) const noexcept {
return Error("TODO");
if (_idx >= _arr.val_->size()) {
return Error("Index out of range.");
}
return InputVarType{&_arr.val_->at(_idx)};
}

rfl::Result<Reader::InputVarType> Reader::get_field_from_object(
const std::string& _name, const InputObjectType& _obj) const noexcept {
return Error("TODO");
for (auto& kv : _obj.val_->object_range()) {
if (kv.key() == _name) {
return InputVarType{&kv.value()};
};
}
return Error("Field name '" + _name + "' not found.");
}

bool Reader::is_empty(const InputVarType& _var) const noexcept {
return _var.cursor_->current().event_type() ==
jsoncons::staj_event_type::null_value;
return _var.val_->is_null();
}

rfl::Result<Reader::InputArrayType> Reader::to_array(
const InputVarType& _var) const noexcept {
if (_var.cursor_->current().event_type() !=
jsoncons::staj_event_type::begin_array) {
InputVarType _var) const noexcept {
if (!_var.val_->is_array()) {
return Error("Could not cast to an array.");
}
return InputArrayType{_var.cursor_};
return InputArrayType{_var.val_};
}

rfl::Result<Reader::InputObjectType> Reader::to_object(
const InputVarType& _var) const noexcept {
if (_var.cursor_->current().event_type() !=
jsoncons::staj_event_type::begin_object) {
InputVarType _var) const noexcept {
if (!_var.val_->is_object()) {
return Error("Could not cast to an object.");
}
return InputObjectType{_var.cursor_};
return InputObjectType{_var.val_};
}

} // namespace rfl::ubjson
46 changes: 46 additions & 0 deletions tests/ubjson/test_add_struct_name.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include <iostream>
#include <string>
#include <vector>

#include "write_and_read.hpp"

namespace test_add_struct_name {

using Age = rfl::Validator<unsigned int, rfl::Minimum<0>, rfl::Maximum<130>>;

struct Person {
rfl::Rename<"firstName", std::string> first_name;
rfl::Rename<"lastName", std::string> last_name = "Simpson";
std::string town = "Springfield";
rfl::Timestamp<"%Y-%m-%d"> birthday;
Age age;
rfl::Email email;
std::vector<Person> children;
};

TEST(ubjson, test_add_struct_name) {
const auto bart = Person{.first_name = "Bart",
.birthday = "1987-04-19",
.age = 10,
.email = "[email protected]"};

const auto lisa = Person{.first_name = "Lisa",
.birthday = "1987-04-19",
.age = 8,
.email = "[email protected]"};

const auto maggie = Person{.first_name = "Maggie",
.birthday = "1987-04-19",
.age = 0,
.email = "[email protected]"};

const auto homer =
Person{.first_name = "Homer",
.birthday = "1987-04-19",
.age = 45,
.email = "[email protected]",
.children = std::vector<Person>({bart, lisa, maggie})};

write_and_read<rfl::AddStructName<"type">>(homer);
}
} // namespace test_add_struct_name
35 changes: 35 additions & 0 deletions tests/ubjson/test_array.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include <array>
#include <iostream>
#include <memory>
#include <rfl/ubjson.hpp>
#include <string>

// Make sure things still compile when
// rfl.hpp is included after rfl/ubjson.hpp.
#include <rfl.hpp>

#include "write_and_read.hpp"

namespace test_array {

struct Person {
rfl::Rename<"firstName", std::string> first_name;
rfl::Rename<"lastName", std::string> last_name = "Simpson";
std::unique_ptr<std::array<Person, 3>> children = nullptr;
};

TEST(ubjson, test_array) {
auto bart = Person{.first_name = "Bart"};

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

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

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

write_and_read(homer);
}
} // namespace test_array
44 changes: 44 additions & 0 deletions tests/ubjson/test_box.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <cassert>
#include <iostream>
#include <rfl.hpp>
#include <string>
#include <vector>

#include "write_and_read.hpp"

namespace test_box {

struct DecisionTree {
struct Leaf {
using Tag = rfl::Literal<"Leaf">;
double value;
};

struct Node {
using Tag = rfl::Literal<"Node">;
rfl::Rename<"criticalValue", double> critical_value;
rfl::Box<DecisionTree> lesser;
rfl::Box<DecisionTree> greater;
};

using LeafOrNode = rfl::TaggedUnion<"type", Leaf, Node>;

rfl::Field<"leafOrNode", LeafOrNode> leaf_or_node;
};

TEST(ubjson, test_box) {
auto leaf1 = DecisionTree::Leaf{.value = 3.0};

auto leaf2 = DecisionTree::Leaf{.value = 5.0};

auto node = DecisionTree::Node{
.critical_value = 10.0,
.lesser = rfl::make_box<DecisionTree>(DecisionTree{leaf1}),
.greater = rfl::make_box<DecisionTree>(DecisionTree{leaf2})};

const DecisionTree tree{.leaf_or_node = std::move(node)};

write_and_read(tree);

}
} // namespace test_box
21 changes: 21 additions & 0 deletions tests/ubjson/test_bytestring.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <iostream>
#include <rfl.hpp>
#include <string>
#include <vector>

#include "write_and_read.hpp"

namespace test_bytestring {

struct TestStruct {
rfl::Bytestring bytestring;
};

TEST(ubjson, test_bytestring) {
const auto test =
TestStruct{.bytestring = rfl::Bytestring({std::byte{13}, std::byte{14},
std::byte{15}, std::byte{16}})};

write_and_read(test);
}
} // namespace test_bytestring
Loading

0 comments on commit ab72519

Please sign in to comment.