Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
106 changes: 85 additions & 21 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_);
Comment thread
liuzicheng1987 marked this conversation as resolved.
Outdated
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