Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/rfl/AddStructName.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ namespace rfl {
template <internal::StringLiteral field_name_>
struct AddStructName {
/// Adds the name of the struct as a new field.
/// @param _view The view of the struct
/// @return A new named tuple with the struct name added as a field
template <class StructType>
static auto process(const auto& _view) {
using LiteralType = Literal<
Expand Down
10 changes: 10 additions & 0 deletions include/rfl/AddTagsToVariants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ namespace rfl {
/// they might encounter.
struct AddTagsToVariants {
public:
/// Processes a named tuple (a tuple-like structure with named fields) without modification.
/// This method exists to satisfy the processor interface but doesn't transform the data.
/// @tparam StructType The type of the struct being processed
/// @param _named_tuple The named tuple representing the struct's fields
/// @return The unmodified named tuple
template <class StructType>
static auto process(auto&& _named_tuple) {
return _named_tuple;
Expand All @@ -19,6 +24,11 @@ struct AddTagsToVariants {
/// they might encounter.
struct AddNamespacedTagsToVariants {
public:
/// Processes a named tuple (a tuple-like structure with named fields) without modification.
/// This method exists to satisfy the processor interface but doesn't transform the data.
/// @tparam StructType The type of the struct being processed
/// @param _named_tuple The named tuple representing the struct's fields
/// @return The unmodified named tuple
template <class StructType>
static auto process(auto&& _named_tuple) {
return _named_tuple;
Expand Down
7 changes: 6 additions & 1 deletion include/rfl/AllOf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,19 @@

namespace rfl {

/// Requires that all of the contraints C and Cs be true.
/// Requires that all of the constraints C and Cs be true.
template <class C, class... Cs>
struct AllOf {
/// Validates that all constraints are satisfied.
/// @param _value The value to validate
/// @return The value if all constraints pass, otherwise an error
template <class T>
static rfl::Result<T> validate(T _value) noexcept {
return validate_impl<T, C, Cs...>(_value);
}

/// Converts the validator to a JSON schema type.
/// @return A ValidationType representing all-of schema
template <class T>
static parsing::schema::ValidationType to_schema() {
using ValidationType = parsing::schema::ValidationType;
Expand Down
13 changes: 11 additions & 2 deletions include/rfl/AllowRawPtrs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,19 @@

namespace rfl {

/// This is a "fake" processor - it doesn't do much in itself, but its
/// inclusion instructs the parsers to allow raw pointers.
/// A processor that instructs parsers to allow raw pointers in structs.
/// This is a marker type (doesn't modify data) that changes parser behavior.
/// By default, reflect-cpp does not support raw pointers to avoid memory management issues.
/// When AllowRawPtrs is added as a processor, raw pointers (T*) in structs will be accepted
/// and serialized/deserialized. Use with caution as this can lead to memory leaks or dangling pointers.
/// Usage: rfl::json::read<MyStruct, AllowRawPtrs>(json_str)
struct AllowRawPtrs {
public:
/// Identity process function - returns the named tuple unchanged.
/// The actual raw pointer handling happens in the parser, not here.
/// @tparam StructType The struct type being processed
/// @param _named_tuple The named tuple representation of the struct
/// @return The same named tuple (unchanged)
template <class StructType>
static auto process(auto&& _named_tuple) {
return _named_tuple;
Expand Down
10 changes: 9 additions & 1 deletion include/rfl/AnyOf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,19 @@

namespace rfl {

/// Requires that all of the contraints C and Cs be true.
/// Requires that at least one of the constraints C and Cs be true.
template <class C, class... Cs>
struct AnyOf {
/// Validates that at least one constraint is satisfied.
/// @param _value The value to validate
/// @return The value if at least one constraint passes, otherwise an error
template <class T>
static rfl::Result<T> validate(const T& _value) noexcept {
return validate_impl<T, C, Cs...>(_value, {});
}

/// Converts the validator to a JSON schema type.
/// @return A ValidationType representing any-of schema
template <class T>
static parsing::schema::ValidationType to_schema() {
using ValidationType = parsing::schema::ValidationType;
Expand All @@ -28,6 +33,9 @@ struct AnyOf {
}

private:
/// Creates an error message from a list of errors.
/// @param _errors The list of errors from failed validations
/// @return A formatted error message
static std::string make_error_message(const std::vector<Error>& _errors) {
std::stringstream stream;
stream << "Expected at least one of the following validations to pass, but "
Expand Down
108 changes: 86 additions & 22 deletions include/rfl/Attribute.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,126 +12,190 @@

namespace rfl {

/// Wraps a field value to mark it as an XML attribute.
/// In XML serialization, fields wrapped in Attribute will be rendered as attributes
/// on the XML element rather than child elements. For non-XML formats, this wrapper
/// is transparent and behaves like a normal field.
/// Example: <element attr="value"> instead of <element><field>value</field></element>
/// @tparam T The type of the attribute value
template <class T>
struct Attribute {
using Type = T;
using ReflectionType = T;

/// Default constructor.
Attribute() : value_(Type()) {}

/// Constructs from a const reference to the value.
/// @param _value The value to store
Attribute(const Type& _value) : value_(_value) {}

/// Constructs from an rvalue reference to the value.
/// @param _value The value to store (will be moved)
Attribute(Type&& _value) noexcept : value_(std::move(_value)) {}

/// Move constructor.
/// @param _attr The Attribute to move from
Attribute(Attribute<T>&& _attr) noexcept = default;

/// Copy constructor.
/// @param _attr The Attribute to copy from
Attribute(const Attribute<Type>& _attr) = default;

/// Copy constructor from Attribute with compatible type.
/// @tparam U Type compatible with T
/// @param _attr The Attribute to copy the value from
template <class U>
Attribute(const Attribute<U>& _attr) : value_(_attr.get()) {}

/// Move constructor from Attribute with compatible type.
/// @tparam U Type compatible with T
/// @param _attr The Attribute to move the value from
template <class U>
Attribute(Attribute<U>&& _attr) : value_(_attr.get()) {}

/// Constructs from any type convertible to Type (copy).
/// @tparam U Type convertible to T
/// @param _value The value to convert and store
template <class U>
requires std::is_convertible_v<U, Type>
Attribute(const U& _value) : value_(_value) {}

/// Constructs from any type convertible to Type (move).
/// @tparam U Type convertible to T
/// @param _value The value to convert and store (will be moved)
template <class U>
requires std::is_convertible_v<U, Type>
Attribute(U&& _value) noexcept : value_(std::forward<U>(_value)) {}

/// Constructs from an Attribute with compatible type.
/// @tparam U Type convertible to T
/// @param _attr The Attribute to copy the value from
template <class U>
requires std::is_convertible_v<U, Type>
Attribute(const Attribute<U>& _attr) : value_(_attr.value()) {}

/// Assigns the underlying object to its default value.
/// Assigns the underlying object to its default value using the Default sentinel.
/// @tparam U The type (must be default constructible)
/// @param The default sentinel value
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For unnamed parameters in Doxygen, it's a good practice to provide a placeholder name (like _ or unused) for clarity in the generated documentation. This makes it clear that the parameter is intentionally unnamed.

Suggested change
/// @param The default sentinel value
/// @param _ The default sentinel value

template <class U = Type>
requires std::is_default_constructible_v<U>
Attribute(const Default&) : value_(Type()) {}

/// Destructor.
~Attribute() = default;

/// Returns the underlying object.
/// Returns the underlying value.
/// @return Const reference to the stored value
const Type& get() const noexcept { return value_; }

/// Returns the underlying object.
/// Returns the underlying value.
/// @return Reference to the stored value
Type& get() noexcept { return value_; }

/// Returns the underlying object.
/// Dereference operator - returns the underlying value.
/// @return Reference to the stored value
Type& operator*() noexcept { return value_; }

/// Returns the underlying object.
/// Dereference operator (const) - returns the underlying value.
/// @return Const reference to the stored value
const Type& operator*() const noexcept { return value_; }

/// Returns the underlying object.
/// Function call operator - returns the underlying value.
/// @return Reference to the stored value
Type& operator()() noexcept { return value_; }

/// Returns the underlying object.
/// Function call operator (const) - returns the underlying value.
/// @return Const reference to the stored value
const Type& operator()() const noexcept { return value_; }

/// Assigns the underlying object.
/// Assigns a new value.
/// @param _value The value to assign
/// @return Reference to this Attribute
auto& operator=(const Type& _value) {
value_ = _value;
return *this;
}

/// Assigns the underlying object.
/// Assigns a new value (move version).
/// @param _value The value to assign (will be moved)
/// @return Reference to this Attribute
auto& operator=(Type&& _value) noexcept {
value_ = std::move(_value);
return *this;
}

/// Assigns the underlying object.
/// Assigns from any type convertible to the underlying type.
/// @tparam U Type convertible to T
/// @param _value The value to convert and assign
/// @return Reference to this Attribute
template <class U>
requires std::is_convertible_v<U, Type>
auto& operator=(const U& _value) {
value_ = _value;
return *this;
}

/// Assigns the underlying object to its default value.
/// Assigns the value to its default using the Default sentinel.
/// @tparam U The type (must be default constructible)
/// @param The default sentinel value
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For unnamed parameters in Doxygen, it's a good practice to provide a placeholder name (like _ or unused) for clarity in the generated documentation. This makes it clear that the parameter is intentionally unnamed.

Suggested change
/// @param The default sentinel value
/// @param _ The default sentinel value

/// @return Reference to this Attribute
template <class U = Type>
requires std::is_default_constructible_v<U>
auto& operator=(const Default&) {
value_ = Type();
return *this;
}

/// Assigns the underlying object.
/// Copy assignment operator.
/// @param _attr The Attribute to copy from
/// @return Reference to this Attribute
Attribute<T>& operator=(const Attribute<T>& _attr) = default;

/// Assigns the underlying object.
/// Move assignment operator.
/// @param _attr The Attribute to move from
/// @return Reference to this Attribute
Attribute<T>& operator=(Attribute<T>&& _attr) = default;

/// Assigns the underlying object.
/// Assigns from another Attribute with compatible type (copy).
/// @tparam U Type compatible with T
/// @param _attr The Attribute to copy the value from
/// @return Reference to this Attribute
template <class U>
auto& operator=(const Attribute<U>& _attr) {
value_ = _attr.get();
return *this;
}

/// Assigns the underlying object.
/// Assigns from another Attribute with compatible type (move).
/// @tparam U Type compatible with T
/// @param _attr The Attribute to move the value from
/// @return Reference to this Attribute
template <class U>
auto& operator=(Attribute<U>&& _attr) {
value_ = std::forward<T>(_attr.value_);
value_ = std::move(_attr.value_);
return *this;
}

/// We want all parsers other than the XML parser to treat attributes like
/// normal fields, so we just implement the reflection interface.
/// Returns the underlying value for reflection (used by parsers).
/// Non-XML parsers treat attributes like normal fields.
/// @return Const reference to the stored value
const ReflectionType& reflection() const { return value_; }

/// Assigns the underlying object.
/// Sets the value (copy version).
/// @param _value The value to set
void set(const Type& _value) { value_ = _value; }

/// Assigns the underlying object.
/// Sets the value (move version).
/// @param _value The value to set (will be moved)
void set(Type&& _value) { value_ = std::move(_value); }

/// Returns the underlying object.
/// Returns the underlying value.
/// @return Reference to the stored value
Type& value() noexcept { return value_; }

/// Returns the underlying object.
/// Returns the underlying value (const).
/// @return Const reference to the stored value
const Type& value() const noexcept { return value_; }

/// The underlying value.
Expand Down
Loading
Loading