-
Notifications
You must be signed in to change notification settings - Fork 107
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5a34c9b
commit 51a3013
Showing
9 changed files
with
578 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#ifndef RFL_CBOR_PARSER_HPP_ | ||
#define RFL_CBOR_PARSER_HPP_ | ||
|
||
#include "../parsing/Parser.hpp" | ||
#include "Reader.hpp" | ||
#include "Writer.hpp" | ||
|
||
namespace rfl { | ||
namespace cbor { | ||
|
||
template <class T> | ||
using Parser = parsing::Parser<Reader, Writer, T>; | ||
|
||
} | ||
} // namespace rfl | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
#ifndef RFL_CBOR_READER_HPP_ | ||
#define RFL_CBOR_READER_HPP_ | ||
|
||
#include <bson/bson.h> | ||
|
||
#include <array> | ||
#include <concepts> | ||
#include <exception> | ||
#include <map> | ||
#include <memory> | ||
#include <sstream> | ||
#include <stdexcept> | ||
#include <string> | ||
#include <string_view> | ||
#include <type_traits> | ||
#include <unordered_map> | ||
#include <vector> | ||
|
||
#include "../Box.hpp" | ||
#include "../Result.hpp" | ||
#include "../always_false.hpp" | ||
|
||
namespace rfl { | ||
namespace cbor { | ||
|
||
/// Please refer to https://mongoc.org/libbson/current/api.html | ||
struct Reader { | ||
struct CBORValue { | ||
bson_value_t val_; | ||
}; | ||
|
||
struct CBORInputArray { | ||
CBORValue* val_; | ||
}; | ||
|
||
struct CBORInputObject { | ||
CBORValue* val_; | ||
}; | ||
|
||
struct CBORInputVar { | ||
CBORValue* val_; | ||
}; | ||
|
||
using InputArrayType = CBORInputArray; | ||
using InputObjectType = CBORInputObject; | ||
using InputVarType = CBORInputVar; | ||
|
||
template <class T> | ||
static constexpr bool has_custom_constructor = (requires(InputVarType var) { | ||
T::from_bson_obj(var); | ||
}); | ||
|
||
rfl::Result<InputVarType> get_field( | ||
const std::string& _name, const InputObjectType& _obj) const noexcept { | ||
bson_t b; | ||
bson_iter_t iter; | ||
const auto doc = _obj.val_->val_.value.v_doc; | ||
if (bson_init_static(&b, doc.data, doc.data_len)) { | ||
if (bson_iter_init(&iter, &b)) { | ||
while (bson_iter_next(&iter)) { | ||
auto key = std::string(bson_iter_key(&iter)); | ||
if (key == _name) { | ||
return to_input_var(&iter); | ||
} | ||
} | ||
} | ||
} | ||
return Error("No field named '" + _name + "' was found."); | ||
} | ||
|
||
bool is_empty(const InputVarType& _var) const noexcept { | ||
return _var.val_->val_.value_type == CBOR_TYPE_NULL; | ||
} | ||
|
||
template <class T> | ||
rfl::Result<T> to_basic_type(const InputVarType& _var) const noexcept { | ||
const auto btype = _var.val_->val_.value_type; | ||
const auto value = _var.val_->val_.value; | ||
if constexpr (std::is_same<std::remove_cvref_t<T>, std::string>()) { | ||
switch (btype) { | ||
case CBOR_TYPE_UTF8: | ||
return std::string(value.v_utf8.str, value.v_utf8.len); | ||
|
||
case CBOR_TYPE_SYMBOL: | ||
return std::string(value.v_symbol.symbol, value.v_symbol.len); | ||
|
||
default: | ||
return rfl::Error( | ||
"Could not cast to string. The type must be UTF8 or symbol."); | ||
} | ||
} else if constexpr (std::is_same<std::remove_cvref_t<T>, bool>()) { | ||
if (btype != CBOR_TYPE_BOOL) { | ||
return rfl::Error("Could not cast to boolean."); | ||
} | ||
return value.v_bool; | ||
} else if constexpr (std::is_floating_point<std::remove_cvref_t<T>>() || | ||
std::is_integral<std::remove_cvref_t<T>>()) { | ||
switch (btype) { | ||
case CBOR_TYPE_DOUBLE: | ||
return static_cast<T>(value.v_double); | ||
|
||
case CBOR_TYPE_INT32: | ||
return static_cast<T>(value.v_int32); | ||
|
||
case CBOR_TYPE_INT64: | ||
return static_cast<T>(value.v_int64); | ||
|
||
case CBOR_TYPE_DATE_TIME: | ||
return static_cast<T>(value.v_datetime); | ||
|
||
default: | ||
return rfl::Error( | ||
"Could not cast to numeric value. The type must be double, " | ||
"int32, int64 or date_time."); | ||
} | ||
} else { | ||
static_assert(rfl::always_false_v<T>, "Unsupported type."); | ||
} | ||
} | ||
|
||
rfl::Result<InputArrayType> to_array( | ||
const InputVarType& _var) const noexcept { | ||
const auto btype = _var.val_->val_.value_type; | ||
if (btype != CBOR_TYPE_ARRAY && btype != CBOR_TYPE_DOCUMENT) { | ||
return Error("Could not cast to an array."); | ||
} | ||
return InputArrayType{_var.val_}; | ||
} | ||
|
||
template <size_t size, class FunctionType> | ||
std::array<std::optional<InputVarType>, size> to_fields_array( | ||
const FunctionType& _fct, const InputObjectType& _obj) const noexcept { | ||
std::array<std::optional<InputVarType>, size> f_arr; | ||
bson_t b; | ||
bson_iter_t iter; | ||
const auto doc = _obj.val_->val_.value.v_doc; | ||
if (bson_init_static(&b, doc.data, doc.data_len)) { | ||
if (bson_iter_init(&iter, &b)) { | ||
while (bson_iter_next(&iter)) { | ||
const char* k = bson_iter_key(&iter); | ||
const auto ix = _fct(std::string_view(k)); | ||
if (ix != -1) { | ||
f_arr[ix] = to_input_var(&iter); | ||
} | ||
} | ||
} | ||
} | ||
return f_arr; | ||
} | ||
|
||
rfl::Result<std::vector<std::pair<std::string, InputVarType>>> to_map( | ||
const InputObjectType& _obj) const noexcept { | ||
std::vector<std::pair<std::string, InputVarType>> map; | ||
bson_t b; | ||
bson_iter_t iter; | ||
const auto doc = _obj.val_->val_.value.v_doc; | ||
if (bson_init_static(&b, doc.data, doc.data_len)) { | ||
if (bson_iter_init(&iter, &b)) { | ||
while (bson_iter_next(&iter)) { | ||
auto key = std::string(bson_iter_key(&iter)); | ||
map.emplace_back(std::make_pair(std::move(key), to_input_var(&iter))); | ||
} | ||
} | ||
} | ||
return map; | ||
} | ||
|
||
rfl::Result<InputObjectType> to_object( | ||
const InputVarType& _var) const noexcept { | ||
const auto btype = _var.val_->val_.value_type; | ||
if (btype != CBOR_TYPE_DOCUMENT) { | ||
return Error("Could not cast to a document."); | ||
} | ||
return InputObjectType{_var.val_}; | ||
} | ||
|
||
std::vector<InputVarType> to_vec(const InputArrayType& _arr) const noexcept { | ||
std::vector<InputVarType> vec; | ||
bson_t b; | ||
bson_iter_t iter; | ||
const auto doc = _arr.val_->val_.value.v_doc; | ||
if (bson_init_static(&b, doc.data, doc.data_len)) { | ||
if (bson_iter_init(&iter, &b)) { | ||
while (bson_iter_next(&iter)) { | ||
vec.push_back(to_input_var(&iter)); | ||
} | ||
} | ||
} | ||
return vec; | ||
} | ||
|
||
template <class T> | ||
rfl::Result<T> use_custom_constructor( | ||
const InputVarType& _var) const noexcept { | ||
try { | ||
return T::from_bson_obj(_var); | ||
} catch (std::exception& e) { | ||
return rfl::Error(e.what()); | ||
} | ||
} | ||
|
||
private: | ||
struct CBORValues { | ||
std::vector<rfl::Box<CBORValue>> vec_; | ||
~CBORValues() { | ||
for (auto& v : vec_) { | ||
bson_value_destroy(&(v->val_)); | ||
} | ||
} | ||
}; | ||
|
||
private: | ||
InputVarType to_input_var(bson_iter_t* _iter) const noexcept { | ||
values_->vec_.emplace_back(rfl::Box<CBORValue>::make()); | ||
auto* last_value = values_->vec_.back().get(); | ||
bson_value_copy(bson_iter_value(_iter), &last_value->val_); | ||
return InputVarType{last_value}; | ||
} | ||
|
||
private: | ||
/// Contains the values inside the object. | ||
rfl::Ref<CBORValues> values_; | ||
}; | ||
|
||
} // namespace cbor | ||
} // namespace rfl | ||
|
||
#endif // JSON_PARSER_HPP_ |
Oops, something went wrong.