diff --git a/include/rfl/AddStructName.hpp b/include/rfl/AddStructName.hpp index 6f6cd5db..35ff7460 100644 --- a/include/rfl/AddStructName.hpp +++ b/include/rfl/AddStructName.hpp @@ -16,6 +16,8 @@ namespace rfl { template 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 static auto process(const auto& _view) { using LiteralType = Literal< diff --git a/include/rfl/AddTagsToVariants.hpp b/include/rfl/AddTagsToVariants.hpp index 1a68130e..464a4bde 100644 --- a/include/rfl/AddTagsToVariants.hpp +++ b/include/rfl/AddTagsToVariants.hpp @@ -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 static auto process(auto&& _named_tuple) { return _named_tuple; @@ -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 static auto process(auto&& _named_tuple) { return _named_tuple; diff --git a/include/rfl/AllOf.hpp b/include/rfl/AllOf.hpp index 9cd2ec03..ca25c887 100644 --- a/include/rfl/AllOf.hpp +++ b/include/rfl/AllOf.hpp @@ -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 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 static rfl::Result validate(T _value) noexcept { return validate_impl(_value); } + /// Converts the validator to a JSON schema type. + /// @return A ValidationType representing all-of schema template static parsing::schema::ValidationType to_schema() { using ValidationType = parsing::schema::ValidationType; diff --git a/include/rfl/AllowRawPtrs.hpp b/include/rfl/AllowRawPtrs.hpp index ed9576a7..cae9060f 100644 --- a/include/rfl/AllowRawPtrs.hpp +++ b/include/rfl/AllowRawPtrs.hpp @@ -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(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 static auto process(auto&& _named_tuple) { return _named_tuple; diff --git a/include/rfl/AnyOf.hpp b/include/rfl/AnyOf.hpp index 2d74fcc2..eb642540 100644 --- a/include/rfl/AnyOf.hpp +++ b/include/rfl/AnyOf.hpp @@ -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 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 static rfl::Result validate(const T& _value) noexcept { return validate_impl(_value, {}); } + /// Converts the validator to a JSON schema type. + /// @return A ValidationType representing any-of schema template static parsing::schema::ValidationType to_schema() { using ValidationType = parsing::schema::ValidationType; @@ -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& _errors) { std::stringstream stream; stream << "Expected at least one of the following validations to pass, but " diff --git a/include/rfl/Attribute.hpp b/include/rfl/Attribute.hpp index 37d3b315..c9ea66fb 100644 --- a/include/rfl/Attribute.hpp +++ b/include/rfl/Attribute.hpp @@ -12,77 +12,123 @@ 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: instead of value +/// @tparam T The type of the attribute value template 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&& _attr) noexcept = default; + /// Copy constructor. + /// @param _attr The Attribute to copy from Attribute(const Attribute& _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 Attribute(const Attribute& _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 Attribute(Attribute&& _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 requires std::is_convertible_v 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 requires std::is_convertible_v Attribute(U&& _value) noexcept : value_(std::forward(_value)) {} + /// Constructs from an Attribute with compatible type. + /// @tparam U Type convertible to T + /// @param _attr The Attribute to copy the value from template requires std::is_convertible_v Attribute(const Attribute& _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 template requires std::is_default_constructible_v 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 requires std::is_convertible_v auto& operator=(const U& _value) { @@ -90,7 +136,10 @@ struct Attribute { 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 + /// @return Reference to this Attribute template requires std::is_default_constructible_v auto& operator=(const Default&) { @@ -98,40 +147,55 @@ struct Attribute { return *this; } - /// Assigns the underlying object. + /// Copy assignment operator. + /// @param _attr The Attribute to copy from + /// @return Reference to this Attribute Attribute& operator=(const Attribute& _attr) = default; - /// Assigns the underlying object. + /// Move assignment operator. + /// @param _attr The Attribute to move from + /// @return Reference to this Attribute Attribute& operator=(Attribute&& _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 auto& operator=(const Attribute& _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 auto& operator=(Attribute&& _attr) { - value_ = std::forward(_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. diff --git a/include/rfl/Binary.hpp b/include/rfl/Binary.hpp index f44bc5d5..9dc81a65 100644 --- a/include/rfl/Binary.hpp +++ b/include/rfl/Binary.hpp @@ -11,73 +11,116 @@ namespace rfl { -/// Used to define a field in the NamedTuple. +/// Wraps an unsigned integer value for binary string serialization. +/// When serialized, Binary converts the integer to its binary string +/// representation (e.g., "101010"). When deserialized, it parses a binary +/// string back to an integer value. This is useful for representing flags, bit +/// patterns, or when you need human-readable binary format. +/// @tparam T The unsigned integer type to wrap (must satisfy +/// std::is_unsigned_v) template requires std::is_unsigned_v struct Binary { - /// The underlying type. + /// The underlying unsigned integer type. using Type = T; using ReflectionType = std::string; using Bitset = std::bitset; + /// Default constructor - initializes to zero. Binary() : value_(0) {} + /// Constructs from the underlying integer value. + /// @param _value The integer value to wrap Binary(const Type& _value) : value_(_value) {} + /// Move constructor. + /// @param _other The Binary to move from Binary(Binary&& _other) noexcept = default; + /// Copy constructor. + /// @param _other The Binary to copy from Binary(const Binary& _other) = default; + /// Copy constructor from Binary with compatible type. + /// @tparam U Type compatible with T + /// @param _other The Binary to copy the value from template Binary(const Binary& _other) : value_(_other.get()) {} + /// Move constructor from Binary with compatible type. + /// @tparam U Type compatible with T + /// @param _other The Binary to move the value from template Binary(Binary&& _other) : value_(_other.get()) {} + /// Constructs from any type convertible to Type (copy). + /// @tparam U Type convertible to T + /// @param _value The value to convert and store template requires std::is_convertible_v Binary(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 requires std::is_convertible_v Binary(U&& _value) noexcept : value_(std::forward(_value)) {} + /// Constructs from a Binary with compatible type. + /// @tparam U Type convertible to T + /// @param _other The Binary to copy the value from template requires std::is_convertible_v Binary(const Binary& _other) : value_(_other.value()) {} + /// Constructs from a binary string representation. + /// Parses strings like "101010" into the corresponding integer value. + /// @param _str The binary string to parse (e.g., "10101010") Binary(const std::string& _str) : value_(static_cast(Bitset{_str}.to_ullong())) {} + /// Destructor. ~Binary() = default; - /// Returns the underlying object. + /// Returns the underlying integer value. + /// @return Const reference to the stored value const Type& get() const noexcept { return value_; } - /// Returns the underlying object. + /// Returns the underlying integer 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 integer value. + /// @param _value The value to assign + /// @return Reference to this Binary auto& operator=(const Type& _value) { value_ = _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 Binary template requires std::is_convertible_v auto& operator=(const U& _value) { @@ -85,49 +128,68 @@ struct Binary { return *this; } - /// Assigns the underlying object. + /// Copy assignment operator. + /// @param _other The Binary to copy from + /// @return Reference to this Binary Binary& operator=(const Binary& _other) = default; - /// Assigns the underlying object. + /// Move assignment operator. + /// @param _other The Binary to move from + /// @return Reference to this Binary Binary& operator=(Binary&& _other) = default; - /// Assigns the underlying object. + /// Assigns from another Binary with compatible type (copy). + /// @tparam U Type compatible with T + /// @param _other The Binary to copy the value from + /// @return Reference to this Binary template auto& operator=(const Binary& _other) { value_ = _other.get(); return *this; } - /// Assigns the underlying object. - template + /// Assigns from a binary string representation. + /// Parses strings like "101010" into the corresponding integer value. + /// @tparam U Template parameter for compatibility + /// @param _str The binary string to parse + /// @return Reference to this Binary auto& operator=(const std::string& _str) { value_ = static_cast(Bitset{_str}.to_ullong()); return *this; } - /// Assigns the underlying object. + /// Assigns from another Binary with compatible type (move). + /// @tparam U Type compatible with T + /// @param _other The Binary to move the value from + /// @return Reference to this Binary template auto& operator=(Binary&& _other) { - value_ = std::forward(_other.value_); + value_ = std::move(_other.value_); return *this; } - /// Necessary for the automated parsing to work. + /// Returns the value as a binary string for serialization. + /// Converts the integer to binary string representation (e.g., "10101010"). + /// @return The binary string representation std::string reflection() const { return Bitset{value_}.to_string(); } - /// Assigns the underlying object. + /// Sets the integer value. + /// @param _value The value to set void set(const Type& _value) { value_ = _value; } - /// Returns the underlying value as a string, alias for .reflection(). + /// Returns the value as a binary string, alias for .reflection(). + /// @return The binary string representation std::string str() const { return reflection(); } - /// Returns the underlying object. + /// Returns the underlying integer value. + /// @return Reference to the stored value Type& value() noexcept { return value_; } - /// Returns the underlying object. + /// Returns the underlying integer value (const). + /// @return Const reference to the stored value const Type& value() const noexcept { return value_; } - /// The underlying value. + /// The underlying integer value. Type value_; }; diff --git a/include/rfl/Box.hpp b/include/rfl/Box.hpp index e2fb2b90..e0655220 100644 --- a/include/rfl/Box.hpp +++ b/include/rfl/Box.hpp @@ -8,32 +8,40 @@ namespace rfl { +/// Enum defining whether a Box is copyable or not. +/// Determines the availability of copy constructor and assignment operators. enum class Copyability { - COPYABLE, - NON_COPYABLE + COPYABLE, ///< Box can be copied (creates a deep copy of the contained object) + NON_COPYABLE ///< Box cannot be copied (behaves like unique_ptr) }; -/// The Box class behaves very similarly to the unique_ptr, but unlike the -/// unique_ptr, it is 100% guaranteed to be filled at all times (unless the user -/// tries to access it after calling std::move does something else that is +/// A smart pointer wrapper that is guaranteed to always contain a valid object. +/// The Box class behaves very similarly to unique_ptr, but unlike unique_ptr, +/// it is 100% guaranteed to be filled at all times (unless the user +/// tries to access it after calling std::move or does something else that is /// clearly bad practice). /// /// By default Box behaves like a unique_ptr in relation to copying, but it can be /// configured to add copy constructor and assignment operators that call the /// same function of the contained type T. - +/// @tparam T The type of object to contain +/// @tparam C Copyability mode (defaults to NON_COPYABLE) template class Box { public: - /// The only way of creating new boxes is - /// Box::make(...). + /// The only way of creating new boxes is Box::make(...). + /// Constructs a new Box with the given arguments forwarded to T's constructor. + /// @tparam Args Types of constructor arguments + /// @param _args Arguments to forward to T's constructor + /// @return A new Box containing the constructed object template static Box make(Args&&... _args) { return Box(std::make_unique(std::forward(_args)...)); } - /// You can generate them from unique_ptrs as well, in which case it will - /// return an Error, if the unique_ptr is not set. + /// Creates a Box from a unique_ptr, returns an Error if the unique_ptr is null. + /// @param _ptr The unique_ptr to convert to a Box + /// @return Result containing the Box or an error if _ptr is nullptr static Result make(std::unique_ptr&& _ptr) { if (!_ptr) { return error("std::unique_ptr was a nullptr."); @@ -41,29 +49,42 @@ class Box { return Box(std::move(_ptr)); } + /// Default constructor - creates a Box containing a default-constructed T. Box() : ptr_(std::make_unique()) {} - /// Copy constructor if copyable + /// Copy constructor - only available when C == Copyability::COPYABLE. + /// Creates a deep copy of the contained object. + /// @param _other The Box to copy from Box(const Box& _other) requires (C == Copyability::COPYABLE) { ptr_ = std::make_unique(*_other); } - /// Copy constructor if not copyable + /// Copy constructor deleted when not copyable. Box(const Box& _other) requires (C == Copyability::NON_COPYABLE) = delete; + /// Move constructor. + /// @param _other The Box to move from Box(Box&& _other) = default; + /// Move constructor from a Box with different copyability mode. + /// @tparam U Type convertible to T + /// @tparam C2 Copyability mode of the other Box + /// @param _other The Box to move from template Box(Box&& _other) noexcept : ptr_(std::forward>(_other.ptr())) {} + /// Destructor. ~Box() = default; - /// Returns a pointer to the underlying object + /// Returns a pointer to the underlying object. + /// @return Raw pointer to the contained object T* get() const { return ptr_.get(); } - /// Copy assignment operator if copyable + /// Copy assignment operator - only available when C == Copyability::COPYABLE. + /// @param other The Box to copy from + /// @return Reference to this Box Box& operator=(const Box& other) requires (C == Copyability::COPYABLE) { if(this != &other) { ptr_ = std::make_unique(*other); @@ -71,66 +92,102 @@ class Box { return *this; } - /// Copy assignment operator if not copyable + /// Copy assignment operator deleted when not copyable. Box& operator=(const Box& _other) requires (C == Copyability::NON_COPYABLE) = delete; - /// Move assignment operator + /// Move assignment operator. + /// @param _other The Box to move from + /// @return Reference to this Box Box& operator=(Box&& _other) noexcept = default; - /// Move assignment operator + /// Move assignment operator from Box with different type. + /// @tparam U Type convertible to T + /// @param _other The Box to move from + /// @return Reference to this Box template Box& operator=(Box&& _other) noexcept { ptr_ = std::forward>(_other.ptr()); return *this; } - /// Returns the underlying object. + /// Dereference operator - returns the underlying object. + /// @return Reference to the contained object T& operator*() { return *ptr_; } - /// Returns the underlying object. + /// Dereference operator (const) - returns the underlying object. + /// @return Const reference to the contained object T& operator*() const { return *ptr_; } - /// Returns the underlying object. + /// Arrow operator - provides access to the underlying object's members. + /// @return Pointer to the contained object T* operator->() { return ptr_.get(); } - /// Returns the underlying object. + /// Arrow operator (const) - provides access to the underlying object's members. + /// @return Const pointer to the contained object T* operator->() const { return ptr_.get(); } - /// Returns the underlying unique_ptr + /// Returns the underlying unique_ptr. + /// @return Reference to the internal unique_ptr std::unique_ptr& ptr() { return ptr_; } - /// Returns the underlying unique_ptr + /// Returns the underlying unique_ptr (const). + /// @return Const reference to the internal unique_ptr const std::unique_ptr& ptr() const { return ptr_; } private: - /// Only make is allowed to use this constructor. + /// Only make() is allowed to use this constructor. + /// @param _ptr The unique_ptr to wrap explicit Box(std::unique_ptr&& _ptr) : ptr_(std::move(_ptr)) {} private: - /// The underlying unique_ptr_ + /// The underlying unique_ptr. std::unique_ptr ptr_; }; -/// Generates a new Ref. +/// Generates a new Box by forwarding arguments to T's constructor. +/// @tparam T The type to box +/// @tparam Args Types of constructor arguments +/// @param _args Arguments to forward to T's constructor +/// @return A new Box template auto make_box(Args&&... _args) { return Box::make(std::forward(_args)...); } -/// Template specialization for a box that is copyable. +/// Template specialization for a Box that is copyable. +/// CopyableBox allows copying via the copy constructor and assignment operators. +/// @tparam T The type to box template using CopyableBox = Box; +/// Generates a new CopyableBox by forwarding arguments to T's constructor. +/// @tparam T The type to box +/// @tparam Args Types of constructor arguments +/// @param _args Arguments to forward to T's constructor +/// @return A new CopyableBox template auto make_copyable_box(Args&&... _args) { return CopyableBox::make(std::forward(_args)...); } +/// Three-way comparison operator for Boxes. +/// @tparam T1 Type of the first Box +/// @tparam T2 Type of the second Box +/// @param _b1 The first Box to compare +/// @param _b2 The second Box to compare +/// @return The ordering relationship between the underlying pointers template inline auto operator<=>(const Box& _b1, const Box& _b2) { return _b1.ptr() <=> _b2.ptr(); } +/// Stream insertion operator for Box. +/// @tparam CharT Character type +/// @tparam Traits Character traits +/// @tparam T Type contained in the Box +/// @param _os The output stream +/// @param _b The Box to output +/// @return The output stream template inline std::basic_ostream& operator<<( std::basic_ostream& _os, const Box& _b) { @@ -142,13 +199,23 @@ inline std::basic_ostream& operator<<( namespace std { +/// Specialization of std::hash for Box. +/// Allows Box to be used in unordered containers. +/// @tparam T The type contained in the Box template struct hash> { + /// Computes hash of the Box by hashing its underlying unique_ptr. + /// @param _b The Box to hash + /// @return The hash value size_t operator()(const rfl::Box& _b) const { return std::hash>{}(_b.ptr()); } }; +/// Specialization of std::swap for Box. +/// @tparam T The type contained in the Box +/// @param _b1 The first Box to swap +/// @param _b2 The second Box to swap template inline void swap(rfl::Box& _b1, rfl::Box& _b2) { return swap(_b1.ptr(), _b2.ptr()); diff --git a/include/rfl/Bytestring.hpp b/include/rfl/Bytestring.hpp index 197531e5..29ce6472 100644 --- a/include/rfl/Bytestring.hpp +++ b/include/rfl/Bytestring.hpp @@ -6,6 +6,10 @@ namespace rfl { +/// Type alias for a vector of bytes. +/// Bytestring represents binary data as a sequence of std::byte values. +/// This is useful for handling raw binary data, especially in formats that distinguish +/// between text strings and binary data (like MessagePack, CBOR, etc.). using Bytestring = std::vector; } // namespace rfl diff --git a/include/rfl/CamelCaseToSnakeCase.hpp b/include/rfl/CamelCaseToSnakeCase.hpp index d41d9698..dcc15d9e 100644 --- a/include/rfl/CamelCaseToSnakeCase.hpp +++ b/include/rfl/CamelCaseToSnakeCase.hpp @@ -10,6 +10,10 @@ namespace rfl { struct CamelCaseToSnakeCase { public: /// Replaces all instances of camelCase field names with snake_case. + /// A named tuple is a tuple-like structure where each element has a name/key. + /// @tparam StructType The type of the struct being processed + /// @param _named_tuple The named tuple containing the struct's fields + /// @return A new named tuple with field names converted to snake_case template static auto process(const auto& _named_tuple) { return _named_tuple.transform([](const FieldType& _f) { @@ -23,7 +27,10 @@ struct CamelCaseToSnakeCase { } private: - /// Applies the logic to a single field. + /// Applies the camelCase to snake_case transformation to a single field. + /// @tparam FieldType The type of the field being transformed + /// @param _f The field to transform + /// @return A new field with the transformed name and the same value template static auto handle_one_field(const FieldType& _f) { using NewFieldType = diff --git a/include/rfl/Commented.hpp b/include/rfl/Commented.hpp index 83657493..8d5e8756 100644 --- a/include/rfl/Commented.hpp +++ b/include/rfl/Commented.hpp @@ -10,94 +10,151 @@ namespace rfl { +/// Wraps a field value with an optional comment for formats that support +/// comments. The comment is preserved during serialization for formats like +/// TOML and YAML that support inline comments. For formats without comment +/// support, the comment is ignored. This allows you to maintain +/// documentation/metadata alongside your data. +/// @tparam T The type of the field value template struct Commented { public: using Type = std::remove_cvref_t; using ReflectionType = Type; + /// Default constructor - initializes with default-constructed value and no + /// comment. Commented() : value_(Type()) {} + /// Constructs from a value without a comment. + /// @param _value The value to store Commented(const Type& _value) : value_(_value) {} + /// Constructs from a value without a comment (move version). + /// @param _value The value to store (will be moved) Commented(Type&& _value) noexcept : value_(std::move(_value)) {} + /// Constructs from a value with an optional comment. + /// @param _value The value to store + /// @param _comment The optional comment to associate with the value Commented(const Type& _value, std::optional _comment) : comment_(std::move(_comment)), value_(_value) {} + /// Constructs from a value with an optional comment (move version). + /// @param _value The value to store (will be moved) + /// @param _comment The optional comment to associate with the value Commented(Type&& _value, std::optional _comment) noexcept : comment_(std::move(_comment)), value_(std::move(_value)) {} + /// Move constructor. + /// @param _commented The Commented to move from Commented(Commented&& _commented) noexcept = default; + /// Copy constructor. + /// @param _commented The Commented to copy from Commented(const Commented& _commented) = default; + /// Copy constructor from Commented with compatible type. + /// @tparam U Type compatible with T + /// @param _commented The Commented to copy from template Commented(const Commented& _commented) : comment_(_commented.comment()), value_(_commented.get()) {} + /// Move constructor from Commented with compatible type. + /// @tparam U Type compatible with T + /// @param _commented The Commented to move from template Commented(Commented&& _commented) noexcept : comment_(std::move(_commented.comment())), value_(std::move(_commented.value())) {} + /// Copy constructor from Commented with convertible type. + /// @tparam U Type convertible to T + /// @param _commented The Commented to copy from template requires(std::is_convertible_v) Commented(const Commented& _commented) : comment_(_commented.comment()), value_(_commented.value()) {} + /// Constructs from any type convertible to Type (copy). + /// @tparam U Type convertible to T + /// @param _value The value to convert and store template requires(std::is_convertible_v) Commented(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 requires(std::is_convertible_v) Commented(U&& _value) noexcept : value_(std::forward(_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 template requires(std::is_default_constructible_v) Commented(const Default&) : value_(Type()) {} + /// Destructor. ~Commented() = default; - /// Sets the comment associated with the field. + /// Sets or updates the comment associated with the field. + /// @param _comment The comment text to associate with this field void add_comment(std::string _comment) { comment_ = std::move(_comment); } /// Returns the comment associated with the field, if any. + /// @return An optional containing the comment string, or nullopt if no + /// comment const std::optional& comment() const { return comment_; } - /// Returns the underlying object. + /// Returns the underlying value. + /// @return Reference to the stored value Type& get() { return value_; } - /// Returns the underlying object. + /// Returns the underlying value (const). + /// @return Const reference to the stored value const Type& get() const { return value_; } - /// Returns the underlying object. + /// Function call operator - returns the underlying value. + /// @return Reference to the stored value Type& operator()() { 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 { return value_; } - /// Returns the underlying object. + /// Dereference operator - returns the underlying value. + /// @return Reference to the stored value Type& operator*() { return value_; } - /// Returns the underlying object. + /// Dereference operator (const) - returns the underlying value. + /// @return Const reference to the stored value const Type& operator*() const { return value_; } - /// Assigns the underlying object. + /// Assigns a new value (preserves the comment). + /// @param _value The value to assign + /// @return Reference to this Commented auto& operator=(const Type& _value) { value_ = _value; return *this; } - /// Assigns the underlying object. + /// Assigns a new value (move version, preserves the comment). + /// @param _value The value to assign (will be moved) + /// @return Reference to this Commented 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 Commented template requires std::is_convertible_v auto& operator=(const U& _value) { @@ -105,7 +162,10 @@ struct Commented { 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 + /// @return Reference to this Commented template requires std::is_default_constructible_v auto& operator=(const Default&) { @@ -113,13 +173,21 @@ struct Commented { return *this; } - /// Assigns the underlying object. + /// Copy assignment operator. + /// @param _commented The Commented to copy from + /// @return Reference to this Commented Commented& operator=(const Commented& _commented) = default; - /// Assigns the underlying object. + /// Move assignment operator. + /// @param _commented The Commented to move from + /// @return Reference to this Commented Commented& operator=(Commented&& _commented) = default; - /// Assigns the underlying object. + /// Assigns from another Commented with compatible type (copy). + /// Copies both the value and the comment. + /// @tparam U Type compatible with T + /// @param _commented The Commented to copy from + /// @return Reference to this Commented template auto& operator=(const Commented& _commented) { value_ = _commented.get(); @@ -127,7 +195,11 @@ struct Commented { return *this; } - /// Assigns the underlying object. + /// Assigns from another Commented with compatible type (move). + /// Moves both the value and the comment. + /// @tparam U Type compatible with T + /// @param _commented The Commented to move from + /// @return Reference to this Commented template auto& operator=(Commented&& _commented) { value_ = std::move(_commented.value_); @@ -135,22 +207,27 @@ struct Commented { return *this; } - /// Returns the underlying object. + /// Returns the underlying value for reflection (used by parsers). + /// @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() { return value_; } - /// Returns the underlying object. + /// Returns the underlying value (const). + /// @return Const reference to the stored value const Type& value() const { return value_; } - /// The comment associated with the field. + /// The comment associated with the field (if any). std::optional comment_; /// The underlying value. diff --git a/include/rfl/DefaultIfMissing.hpp b/include/rfl/DefaultIfMissing.hpp index 010d6260..fc32de52 100644 --- a/include/rfl/DefaultIfMissing.hpp +++ b/include/rfl/DefaultIfMissing.hpp @@ -3,11 +3,19 @@ namespace rfl { -/// This is a "fake" processor - it doesn't do much in itself, but its -/// inclusion instructs the parsers to use the default values for missing -/// fields. +/// A processor that instructs parsers to use default values for missing fields. +/// This is a marker type (doesn't modify data) that changes parser behavior. +/// When a field is missing from input and has a default value, that default will be used +/// instead of treating it as an error. Works with fields that have default constructors, +/// rfl::default_value, or are wrapped in DefaultVal. +/// Usage: rfl::json::read(json_str) struct DefaultIfMissing { public: + /// Identity process function - returns the named tuple unchanged. + /// The actual default value application 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 static auto process(auto&& _named_tuple) { return _named_tuple; diff --git a/include/rfl/DefaultVal.hpp b/include/rfl/DefaultVal.hpp index ca700851..e1692253 100644 --- a/include/rfl/DefaultVal.hpp +++ b/include/rfl/DefaultVal.hpp @@ -8,79 +8,124 @@ namespace rfl { +/// Wraps a field with a default value that will be used when the field is missing during parsing. +/// When combined with the DefaultIfMissing processor, fields wrapped in DefaultVal will use +/// their stored default value if not present in the input. This is more explicit than relying +/// on default constructors. +/// @tparam T The type of the field value template struct DefaultVal { public: using Type = std::remove_cvref_t; + /// Default constructor - initializes with default-constructed value. DefaultVal() : value_(Type()) {} + /// Constructs from a const reference to the value. + /// @param _value The value to store DefaultVal(const Type& _value) : value_(_value) {} + /// Constructs from an rvalue reference to the value. + /// @param _value The value to store (will be moved) DefaultVal(Type&& _value) noexcept : value_(std::move(_value)) {} + /// Move constructor. + /// @param _field The DefaultVal to move from DefaultVal(DefaultVal&& _field) noexcept = default; + /// Copy constructor. + /// @param _field The DefaultVal to copy from DefaultVal(const DefaultVal& _field) = default; + /// Copy constructor from DefaultVal with compatible type. + /// @tparam U Type compatible with T + /// @param _field The DefaultVal to copy the value from template DefaultVal(const DefaultVal& _field) : value_(_field.get()) {} + /// Move constructor from DefaultVal with compatible type. + /// @tparam U Type compatible with T + /// @param _field The DefaultVal to move the value from template DefaultVal(DefaultVal&& _field) noexcept( noexcept(Type(std::move(_field.value())))) : value_(std::move(_field.value())) {} + /// Constructs from any type convertible to Type (copy). + /// @tparam U Type convertible to T + /// @param _value The value to convert and store template requires(std::is_convertible_v) DefaultVal(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 requires(std::is_convertible_v) DefaultVal(U&& _value) noexcept : value_(std::forward(_value)) {} + /// Constructs from a DefaultVal with compatible type. + /// @tparam U Type convertible to T + /// @param _field The DefaultVal to copy the value from template requires(std::is_convertible_v) DefaultVal(const DefaultVal& _field) : value_(_field.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 template requires(std::is_default_constructible_v) DefaultVal(const Default&) : value_(Type()) {} + /// Destructor. ~DefaultVal() = 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 DefaultVal 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 DefaultVal 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 DefaultVal template requires std::is_convertible_v auto& operator=(const U& _value) { @@ -88,7 +133,10 @@ struct DefaultVal { 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 + /// @return Reference to this DefaultVal template requires std::is_default_constructible_v auto& operator=(const Default&) { @@ -96,36 +144,50 @@ struct DefaultVal { return *this; } - /// Assigns the underlying object. + /// Copy assignment operator. + /// @param _field The DefaultVal to copy from + /// @return Reference to this DefaultVal DefaultVal& operator=(const DefaultVal& _field) = default; - /// Assigns the underlying object. + /// Move assignment operator. + /// @param _field The DefaultVal to move from + /// @return Reference to this DefaultVal DefaultVal& operator=(DefaultVal&& _field) = default; - /// Assigns the underlying object. + /// Assigns from another DefaultVal with compatible type (copy). + /// @tparam U Type compatible with T + /// @param _field The DefaultVal to copy the value from + /// @return Reference to this DefaultVal template auto& operator=(const DefaultVal& _field) { value_ = _field.get(); return *this; } - /// Assigns the underlying object. + /// Assigns from another DefaultVal with compatible type (move). + /// @tparam U Type compatible with T + /// @param _field The DefaultVal to move the value from + /// @return Reference to this DefaultVal template auto& operator=(DefaultVal&& _field) { - value_ = std::forward(_field.value_); + value_ = std::move(_field.value_); return *this; } - /// 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. diff --git a/include/rfl/Deprecated.hpp b/include/rfl/Deprecated.hpp index 5d341a10..34053492 100644 --- a/include/rfl/Deprecated.hpp +++ b/include/rfl/Deprecated.hpp @@ -13,89 +13,127 @@ namespace rfl { -/// Used to mark a field as deprecated in the JSON schema, replacing -/// rfl::Description for deprecated fields. Includes both a deprecation message -/// and a description: -/// rfl::Deprecated<"use X instead", "description of field", T> +/// Marks a field as deprecated and provides deprecation information for JSON schema generation. +/// Similar to Description, but specifically for deprecated fields. The deprecation message and +/// description are used when generating JSON schemas but are ignored during normal serialization/ +/// deserialization. This allows you to document deprecated fields in a way that appears in +/// generated schemas and warns API users. +/// @tparam _deprecation_message The compile-time deprecation message (e.g., "use field X instead") +/// @tparam _description The compile-time description of what the field does +/// @tparam T The type of the field value template struct Deprecated { /// The underlying type. using Type = T; - /// The deprecation message. + /// The deprecation message as a Literal type. using DeprecationMessage = rfl::Literal<_deprecation_message>; - /// The description of the field (same role as Description::Content). + /// The description as a Literal type (same role as Description::Content). using Content = rfl::Literal<_description>; using ReflectionType = Type; + /// Default constructor. Deprecated() : value_(Type()) {} + /// Constructs from a const reference to the value. + /// @param _value The value to store Deprecated(const Type& _value) : value_(_value) {} + /// Constructs from an rvalue reference to the value. + /// @param _value The value to store (will be moved) Deprecated(Type&& _value) noexcept : value_(std::move(_value)) {} + /// Move constructor. + /// @param _field The Deprecated to move from Deprecated(Deprecated&& _field) noexcept = default; + /// Copy constructor. + /// @param _field The Deprecated to copy from Deprecated(const Deprecated& _field) = default; + /// Copy constructor from Deprecated with same messages but compatible type. + /// @tparam U Type compatible with T + /// @param _field The Deprecated to copy the value from template , bool>::type = true> Deprecated(const Deprecated<_deprecation_message, _description, U>& _field) : value_(_field.get()) {} + /// Move constructor from Deprecated with same messages but compatible type. + /// @tparam U Type compatible with T + /// @param _field The Deprecated to move the value from template , bool>::type = true> Deprecated(Deprecated<_deprecation_message, _description, U>&& _field) : value_(std::move(_field.value_)) {} + /// Constructs from any type convertible to Type (copy). + /// @tparam U Type convertible to T + /// @param _value The value to convert and store template , bool>::type = true> Deprecated(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 , bool>::type = true> Deprecated(U&& _value) noexcept : value_(std::forward(_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 template , bool>::type = true> Deprecated(const Default&) : value_(Type()) {} + /// Destructor. ~Deprecated() = default; - /// The deprecation message, for internal use. + /// The deprecation message as a compile-time string literal, for internal use. constexpr static const internal::StringLiteral deprecation_message_ = _deprecation_message; - /// The description, for internal use. + /// The description as a compile-time string literal, for internal use. constexpr static const internal::StringLiteral description_ = _description; - /// Returns the underlying object. + /// Returns the underlying value. + /// @return Const reference to the stored value const Type& get() const { return value_; } - /// Returns the underlying object. + /// Function call operator - returns the underlying value. + /// @return Reference to the stored value Type& operator()() { 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 { return value_; } - /// Assigns the underlying object. + /// Assigns a new value. + /// @param _value The value to assign + /// @return Reference to this Deprecated 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 Deprecated 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 Deprecated template , bool>::type = true> auto& operator=(const U& _value) { @@ -103,7 +141,10 @@ struct Deprecated { 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 + /// @return Reference to this Deprecated template , bool>::type = true> @@ -112,13 +153,20 @@ struct Deprecated { return *this; } - /// Assigns the underlying object. + /// Copy assignment operator. + /// @param _field The Deprecated to copy from + /// @return Reference to this Deprecated Deprecated& operator=(const Deprecated& _field) = default; - /// Assigns the underlying object. + /// Move assignment operator. + /// @param _field The Deprecated to move from + /// @return Reference to this Deprecated Deprecated& operator=(Deprecated&& _field) = default; - /// Assigns the underlying object. + /// Assigns from another Deprecated with same messages but compatible type (copy). + /// @tparam U Type compatible with T + /// @param _field The Deprecated to copy the value from + /// @return Reference to this Deprecated template auto& operator=( const Deprecated<_deprecation_message, _description, U>& _field) { @@ -126,26 +174,34 @@ struct Deprecated { return *this; } - /// Assigns the underlying object. + /// Assigns from another Deprecated with same messages but compatible type (move). + /// @tparam U Type compatible with T + /// @param _field The Deprecated to move the value from + /// @return Reference to this Deprecated template auto& operator=(Deprecated<_deprecation_message, _description, U>&& _field) { value_ = std::move(_field.value_); return *this; } - /// Returns the underlying object - necessary for the reflection to work. + /// Returns the underlying value for reflection (used by parsers). + /// @return Const reference to the stored value const Type& 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() { return value_; } - /// Returns the underlying object. + /// Returns the underlying value (const). + /// @return Const reference to the stored value const Type& value() const { return value_; } /// The underlying value. diff --git a/include/rfl/Description.hpp b/include/rfl/Description.hpp index 1bdcbbc6..d5f1faed 100644 --- a/include/rfl/Description.hpp +++ b/include/rfl/Description.hpp @@ -13,89 +13,133 @@ namespace rfl { -/// Used to add a description to the field - this is only relevant for the JSON -/// schema and will be ignored by the normal serialization routines. +/// Used to add a description to a field for documentation and JSON schema generation. +/// The description is used when generating JSON schemas but is ignored during normal +/// serialization/deserialization. This allows you to document fields in a way that +/// appears in generated schemas. +/// @tparam _description The compile-time string literal description text +/// @tparam T The type of the field value template struct Description { /// The underlying type. using Type = T; - /// The description of the field. + /// The description as a Literal type. using Content = rfl::Literal<_description>; using ReflectionType = Type; + /// Default constructor. Description() : value_(Type()) {} + /// Constructs from a const reference to the value. + /// @param _value The value to store Description(const Type& _value) : value_(_value) {} + /// Constructs from an rvalue reference to the value. + /// @param _value The value to store (will be moved) Description(Type&& _value) noexcept : value_(std::move(_value)) {} + /// Move constructor. + /// @param _field The Description to move from Description(Description&& _field) noexcept = default; + /// Copy constructor. + /// @param _field The Description to copy from Description(const Description& _field) = default; + /// Copy constructor from Description with same description but compatible type. + /// @tparam U Type compatible with T + /// @param _field The Description to copy the value from template Description(const Description<_description, U>& _field) : value_(_field.get()) {} + /// Move constructor from Description with same description but compatible type. + /// @tparam U Type compatible with T + /// @param _field The Description to move the value from template Description(Description<_description, U>&& _field) : value_(_field.get()) {} + /// Constructs from any type convertible to Type (copy). + /// @tparam U Type convertible to T + /// @param _value The value to convert and store template requires std::is_convertible_v Description(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 requires std::is_convertible_v Description(U&& _value) noexcept : value_(std::forward(_value)) {} + /// Constructs from a Description with compatible type. + /// @tparam U Type convertible to T + /// @param _field The Description to copy the value from template requires std::is_convertible_v Description(const Description<_description, U>& _field) : value_(_field.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 template requires std::is_default_constructible_v Description(const Default&) : value_(Type()) {} + /// Destructor. ~Description() = default; - /// The description of the field, for internal use. + /// The description as a compile-time string literal, for internal use. constexpr static const internal::StringLiteral description_ = _description; - /// 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 Description 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 Description 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 Description template requires std::is_convertible_v auto& operator=(const U& _value) { @@ -103,7 +147,10 @@ struct Description { 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 + /// @return Reference to this Description template requires std::is_default_constructible_v auto& operator=(const Default&) { @@ -111,39 +158,54 @@ struct Description { return *this; } - /// Assigns the underlying object. + /// Copy assignment operator. + /// @param _field The Description to copy from + /// @return Reference to this Description Description& operator=(const Description& _field) = default; - /// Assigns the underlying object. + /// Move assignment operator. + /// @param _field The Description to move from + /// @return Reference to this Description Description& operator=(Description&& _field) = default; - /// Assigns the underlying object. + /// Assigns from another Description with same description but compatible type (copy). + /// @tparam U Type compatible with T + /// @param _field The Description to copy the value from + /// @return Reference to this Description template auto& operator=(const Description<_description, U>& _field) { value_ = _field.get(); return *this; } - /// Assigns the underlying object. + /// Assigns from another Description with same description but compatible type (move). + /// @tparam U Type compatible with T + /// @param _field The Description to move the value from + /// @return Reference to this Description template auto& operator=(Description<_description, U>&& _field) { value_ = std::forward(_field.value_); return *this; } - /// Returns the underlying object - necessary for the reflection to work. + /// Returns the underlying value for reflection (used by parsers). + /// @return Const reference to the stored value const Type& 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. diff --git a/include/rfl/ExtraFields.hpp b/include/rfl/ExtraFields.hpp index dc77983b..b91c253a 100644 --- a/include/rfl/ExtraFields.hpp +++ b/include/rfl/ExtraFields.hpp @@ -5,8 +5,12 @@ namespace rfl { -/// Used to embed additional fields for which the names cannot be known in -/// advance and can therefore not be encoded in the struct. +/// Used to embed additional fields for which the names cannot be known in advance. +/// ExtraFields extends Object to capture unknown or dynamic fields during deserialization. +/// This is useful when you want to preserve fields that aren't part of your struct definition, +/// or when dealing with schemas that allow arbitrary additional properties. +/// For example, in JSON you might receive extra fields beyond what your struct defines. +/// @tparam T The value type for the extra fields (typically a variant or generic type) template class ExtraFields : public Object {}; diff --git a/include/rfl/Field.hpp b/include/rfl/Field.hpp index adb0d326..4c9e3c96 100644 --- a/include/rfl/Field.hpp +++ b/include/rfl/Field.hpp @@ -13,85 +13,130 @@ namespace rfl { -/// Used to define a field in the NamedTuple. +/// Used to define a field in the NamedTuple with a compile-time name. +/// A Field associates a compile-time string literal name with a value of type T. +/// This is the building block for creating named tuples and structured data with reflection. +/// @tparam _name The compile-time string literal name of the field +/// @tparam T The type of the value stored in the field template struct Field { - /// The underlying type. + /// The underlying type (wrapped in array if necessary). using Type = internal::wrap_in_rfl_array_t; - /// The name of the field. + /// The name of the field as a Literal type. using Name = rfl::Literal<_name>; + /// Constructs a Field from a const reference to the value. + /// @param _value The value to store in the field Field(const Type& _value) : value_(_value) {} + /// Constructs a Field from an rvalue reference to the value. + /// @param _value The value to store in the field (will be moved) Field(Type&& _value) noexcept : value_(std::move(_value)) {} + /// Move constructor. + /// @param _field The field to move from Field(Field&& _field) noexcept = default; + /// Copy constructor. + /// @param _field The field to copy from Field(const Field& _field) = default; + /// Copy constructor from a Field with the same name but different type. + /// @tparam U The type of the other field + /// @param _field The field to copy from template Field(const Field<_name, U>& _field) : value_(_field.get()) {} + /// Move constructor from a Field with the same name but different type. + /// @tparam U The type of the other field + /// @param _field The field to move from template Field(Field<_name, U>&& _field) : value_(std::move(_field.get())) {} + /// Constructs from any type convertible to Type (copy). + /// @tparam U Type convertible to the field's type + /// @param _value The value to convert and store template requires std::is_convertible_v Field(const U& _value) : value_(_value) {} + /// Constructs from any type convertible to Type (move). + /// @tparam U Type convertible to the field's type + /// @param _value The value to convert and store (will be moved) template requires std::is_convertible_v Field(U&& _value) noexcept : value_(std::forward(_value)) {} + /// Constructs from a Field with compatible type. + /// @tparam U Type convertible to the field's type + /// @param _field The field to copy the value from template requires std::is_convertible_v Field(const Field<_name, U>& _field) : value_(_field.value()) {} /// Assigns the underlying object to its default value. + /// This constructor allows using rfl::default_value to initialize fields. + /// @tparam U The type (must be default constructible) + /// @param The default sentinel value template requires std::is_default_constructible_v Field(const Default&) : value_(Type()) {} + /// Destructor. ~Field() = default; - /// The name of the field, for internal use. + /// The name of the field as a compile-time string literal, for internal use. constexpr static const internal::StringLiteral name_ = _name; - /// 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_; } - /// The name of the field. + /// Returns the name of the field as a string_view. + /// @return The field's name constexpr static std::string_view name() { return name_.string_view(); } - /// 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 to the field. + /// @param _value The value to assign + /// @return Reference to this field auto& operator=(const Type& _value) { value_ = _value; return *this; } - /// Assigns the underlying object. + /// Assigns a new value to the field (move version). + /// @param _value The value to assign (will be moved) + /// @return Reference to this field auto& operator=(Type&& _value) noexcept { value_ = std::move(_value); return *this; } - /// Assigns the underlying object. + /// Assigns from any type convertible to the field's type. + /// @tparam U Type convertible to the field's type + /// @param _value The value to convert and assign + /// @return Reference to this field template requires std::is_convertible_v auto& operator=(const U& _value) { @@ -99,7 +144,10 @@ struct Field { return *this; } - /// Assigns the underlying object to its default value. + /// Assigns the field to its default value using the Default sentinel. + /// @tparam U The type (must be default constructible) + /// @param The default sentinel value + /// @return Reference to this field template requires std::is_default_constructible_v auto& operator=(const Default&) { @@ -107,13 +155,20 @@ struct Field { return *this; } - /// Assigns the underlying object. + /// Copy assignment operator. + /// @param _field The field to copy from + /// @return Reference to this field Field& operator=(const Field& _field) = default; - /// Assigns the underlying object. + /// Move assignment operator. + /// @param _field The field to move from + /// @return Reference to this field Field& operator=(Field&& _field) = default; - /// Assigns the underlying object. + /// Assigns from another Field with the same name but different type. + /// @tparam U The type of the other field + /// @param _field The field to copy the value from + /// @return Reference to this field template auto& operator=(const Field<_name, U>& _field) { value_ = _field.get(); diff --git a/include/rfl/Flatten.hpp b/include/rfl/Flatten.hpp index a9cf6fbf..c4f9b09f 100644 --- a/include/rfl/Flatten.hpp +++ b/include/rfl/Flatten.hpp @@ -10,35 +10,58 @@ namespace rfl { /// Used to embed another struct into the generated output. +/// When serializing, the fields of the embedded struct are flattened into the parent. template struct Flatten { /// The underlying type. using Type = std::remove_cvref_t; + /// Default constructor. Flatten() = default; + /// Constructs a Flatten from a const reference to the underlying type. + /// @param _value The value to wrap Flatten(const Type& _value) : value_(_value) {} + /// Constructs a Flatten from an rvalue reference to the underlying type. + /// @param _value The value to wrap (will be moved) Flatten(Type&& _value) noexcept : value_(std::forward(_value)) {} + /// Copy constructor. + /// @param _f The Flatten to copy from Flatten(const Flatten& _f) = default; + /// Move constructor. + /// @param _f The Flatten to move from Flatten(Flatten&& _f) noexcept = default; + /// Constructs from another Flatten with a different but compatible type. + /// @tparam U The type of the other Flatten + /// @param _f The Flatten to copy from template Flatten(const Flatten& _f) : value_(_f.get()) {} + /// Constructs from another Flatten with a different but compatible type (move version). + /// @tparam U The type of the other Flatten + /// @param _f The Flatten to move from template Flatten(Flatten&& _f) : value_(std::move(_f.get())) {} + /// Constructs from any type convertible to the underlying type. + /// @tparam U The type to convert from + /// @param _value The value to convert and wrap template requires std::is_convertible_v Flatten(const U& _value) : value_(_value) {} + /// Constructs from any type convertible to the underlying type (move version). + /// @tparam U The type to convert from + /// @param _value The value to convert and wrap (will be moved) template requires std::is_convertible_v Flatten(U&& _value) : value_(std::forward(_value)) {} + /// Destructor. ~Flatten() = default; /// Returns the underlying object. @@ -66,18 +89,25 @@ struct Flatten { const Type& value() const noexcept { return value_; } /// Assigns the underlying object. + /// @param _value The value to assign + /// @return Reference to this object Flatten& operator=(const T& _value) { value_ = _value; return *this; } - /// Assigns the underlying object. + /// Assigns the underlying object (move version). + /// @param _value The value to assign (will be moved) + /// @return Reference to this object Flatten& operator=(T&& _value) { value_ = std::forward(_value); return *this; } - /// Assigns the underlying object. + /// Assigns from any type convertible to the underlying type. + /// @tparam U The type to convert from + /// @param _value The value to assign + /// @return Reference to this object template requires std::is_convertible_v Flatten& operator=(const U& _value) { @@ -85,42 +115,60 @@ struct Flatten { return *this; } - /// Assigns the underlying object. + /// Copy assignment operator. + /// @param _f The Flatten to copy from + /// @return Reference to this object Flatten& operator=(const Flatten& _f) = default; - /// Assigns the underlying object. + /// Move assignment operator. + /// @param _f The Flatten to move from + /// @return Reference to this object Flatten& operator=(Flatten&& _f) = default; - /// Assigns the underlying object. + /// Assigns from another Flatten with a different but compatible type. + /// @tparam U The type of the other Flatten + /// @param _f The Flatten to copy from + /// @return Reference to this object template Flatten& operator=(const Flatten& _f) { value_ = _f.get(); return *this; } - /// Assigns the underlying object. + /// Assigns from another Flatten with a different but compatible type (move version). + /// @tparam U The type of the other Flatten + /// @param _f The Flatten to move from + /// @return Reference to this object template Flatten& operator=(Flatten&& _f) { value_ = std::move(_f.get()); return *this; } - /// Three-way comparison operator + /// Three-way comparison operator. + /// @tparam U The type of the other Flatten + /// @param _f The Flatten to compare with + /// @return The result of comparing the underlying values template auto operator<=>(const Flatten& _f) const { return value_ <=> _f.value_; } /// Equality comparison operator. + /// @tparam U The type of the other Flatten + /// @param _f The Flatten to compare with + /// @return true if the underlying values are equal template bool operator==(const Flatten& _f) const { return value_ == _f.get(); } /// Assigns the underlying object. + /// @param _value The value to assign void set(const Type& _value) { value_ = _value; } - /// Assigns the underlying object. + /// Assigns the underlying object (move version). + /// @param _value The value to assign (will be moved) void set(Type&& _value) { value_ = std::forward(_value); } /// The underlying value. diff --git a/include/rfl/Generic.hpp b/include/rfl/Generic.hpp index aab7be7c..977dd7d7 100644 --- a/include/rfl/Generic.hpp +++ b/include/rfl/Generic.hpp @@ -27,28 +27,46 @@ class RFL_API Generic { using ReflectionType = std::optional< std::variant>; + /// Default constructor - creates a Generic with null value. Generic(); + /// Move constructor. + /// @param _other The Generic to move from Generic(Generic&& _other) noexcept; + /// Copy constructor. + /// @param _other The Generic to copy from Generic(const Generic& _other); + /// Constructs from a variant (copy). + /// @param _value The variant value to wrap Generic(const VariantType& _value); + /// Constructs from a variant (move). + /// @param _value The variant value to wrap (will be moved) Generic(VariantType&& _value) noexcept; + /// Constructs from a reflection type. + /// @param _value The reflection type value (optional variant) Generic(const ReflectionType& _value); + /// Constructs from any type convertible to VariantType (copy). + /// @tparam T The type to convert from + /// @param _value The value to convert and wrap template requires std::is_convertible_v Generic(const T& _value) { value_ = _value; } + /// Constructs from any type convertible to VariantType (move). + /// @tparam T The type to convert from + /// @param _value The value to convert and wrap (will be moved) template requires std::is_convertible_v Generic(T&& _value) noexcept : value_(std::forward(_value)) {} + /// Destructor. ~Generic(); /// Returns the underlying object. @@ -79,12 +97,20 @@ class RFL_API Generic { bool is_null() const noexcept; /// Assigns the underlying object. + /// @param _value The variant value to assign + /// @return Reference to this object Generic& operator=(const VariantType& _value); - /// Assigns the underlying object. + /// Assigns the underlying object (move version). + /// @param _value The variant value to assign (will be moved) + /// @return Reference to this object Generic& operator=(VariantType&& _value) noexcept; - /// Assigns the underlying object. + /// Assigns from any type convertible to VariantType. + /// Handles special conversions for numeric types to ensure proper variant alternative selection. + /// @tparam T The type to convert from + /// @param _value The value to assign + /// @return Reference to this object template requires std::is_convertible_v auto& operator=(const T& _value) { @@ -101,10 +127,14 @@ class RFL_API Generic { return *this; } - /// Assigns the underlying object. + /// Copy assignment operator. + /// @param _other The Generic to copy from + /// @return Reference to this object Generic& operator=(const Generic& _other); - /// Assigns the underlying object. + /// Move assignment operator. + /// @param _other The Generic to move from + /// @return Reference to this object Generic& operator=(Generic&& _other); /// Returns the underlying object, necessary for the serialization to work. @@ -268,6 +298,9 @@ class RFL_API Generic { const VariantType& variant() const noexcept { return value_; }; private: + /// Converts a ReflectionType to a VariantType. + /// @param _r The reflection type (optional variant) to convert + /// @return The converted variant type static VariantType from_reflection_type(const ReflectionType& _r) noexcept; private: diff --git a/include/rfl/Hex.hpp b/include/rfl/Hex.hpp index fb8a48fe..70eafad6 100644 --- a/include/rfl/Hex.hpp +++ b/include/rfl/Hex.hpp @@ -10,72 +10,114 @@ namespace rfl { -/// Used to define a field in the NamedTuple. +/// Wraps an integral value for hexadecimal string serialization. +/// When serialized, Hex converts the integer to its hexadecimal string representation (e.g., "1a2b"). +/// When deserialized, it parses a hex string back to an integer value. +/// This is useful for representing values that are conventionally displayed in hex format, +/// such as memory addresses, color codes, or hardware identifiers. +/// @tparam T The integral type to wrap (must satisfy std::is_integral_v) template requires std::is_integral_v struct Hex { - /// The underlying type. + /// The underlying integral type. using Type = T; using ReflectionType = std::string; + /// Default constructor - initializes to zero. Hex() : value_(0) {} + /// Constructs from the underlying integer value. + /// @param _value The integer value to wrap Hex(const Type& _value) : value_(_value) {} + /// Move constructor. + /// @param _other The Hex to move from Hex(Hex&& _other) noexcept = default; + /// Copy constructor. + /// @param _other The Hex to copy from Hex(const Hex& _other) = default; + /// Copy constructor from Hex with compatible type. + /// @tparam U Type compatible with T + /// @param _other The Hex to copy the value from template Hex(const Hex& _other) : value_(_other.get()) {} + /// Move constructor from Hex with compatible type. + /// @tparam U Type compatible with T + /// @param _other The Hex to move the value from template Hex(Hex&& _other) : value_(_other.get()) {} + /// Constructs from any type convertible to Type (copy). + /// @tparam U Type convertible to T + /// @param _value The value to convert and store template requires std::is_convertible_v Hex(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 requires std::is_convertible_v Hex(U&& _value) noexcept : value_(std::forward(_value)) {} + /// Constructs from a Hex with compatible type. + /// @tparam U Type convertible to T + /// @param _other The Hex to copy the value from template requires std::is_convertible_v Hex(const Hex& _other) : value_(_other.value()) {} + /// Constructs from a hexadecimal string representation. + /// Parses strings like "1a2b" or "0x1A2B" into the corresponding integer value. + /// @param _str The hexadecimal string to parse (e.g., "ff" or "0xFF") Hex(const std::string& _str) { std::istringstream(_str) >> std::hex >> value_; } + /// Destructor. ~Hex() = default; - /// Returns the underlying object. + /// Returns the underlying integer value. + /// @return Const reference to the stored value const Type& get() const noexcept { return value_; } - /// Returns the underlying object. + /// Returns the underlying integer 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 integer value. + /// @param _value The value to assign + /// @return Reference to this Hex auto& operator=(const Type& _value) { value_ = _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 Hex template requires std::is_convertible_v auto& operator=(const U& _value) { @@ -83,53 +125,73 @@ struct Hex { return *this; } - /// Assigns the underlying object. + /// Copy assignment operator. + /// @param _other The Hex to copy from + /// @return Reference to this Hex Hex& operator=(const Hex& _other) = default; - /// Assigns the underlying object. + /// Move assignment operator. + /// @param _other The Hex to move from + /// @return Reference to this Hex Hex& operator=(Hex&& _other) = default; - /// Assigns the underlying object. + /// Assigns from another Hex with compatible type (copy). + /// @tparam U Type compatible with T + /// @param _other The Hex to copy the value from + /// @return Reference to this Hex template auto& operator=(const Hex& _other) { value_ = _other.get(); return *this; } - /// Assigns the underlying object. + /// Assigns from a hexadecimal string representation. + /// Parses strings like "1a2b" or "0x1A2B" into the corresponding integer value. + /// @tparam U Template parameter for compatibility + /// @param _str The hexadecimal string to parse + /// @return Reference to this Hex template auto& operator=(const std::string& _str) { std::istringstream(_str) >> std::hex >> value_; return *this; } - /// Assigns the underlying object. + /// Assigns from another Hex with compatible type (move). + /// @tparam U Type compatible with T + /// @param _other The Hex to move the value from + /// @return Reference to this Hex template auto& operator=(Hex&& _other) { - value_ = std::forward(_other.value_); + value_ = std::move(_other.value_); return *this; } - /// Necessary for the automated parsing to work. + /// Returns the value as a hexadecimal string for serialization. + /// Converts the integer to hex string representation (e.g., "ff"). + /// @return The hexadecimal string representation std::string reflection() const { std::stringstream stream; stream << std::hex << value_; return stream.str(); } - /// Assigns the underlying object. + /// Sets the integer value. + /// @param _value The value to set void set(const Type& _value) { value_ = _value; } - /// Returns the underlying value as a string, alias for .reflection(). + /// Returns the value as a hexadecimal string, alias for .reflection(). + /// @return The hexadecimal string representation std::string str() const { return reflection(); } - /// Returns the underlying object. + /// Returns the underlying integer value. + /// @return Reference to the stored value Type& value() noexcept { return value_; } - /// Returns the underlying object. + /// Returns the underlying integer value (const). + /// @return Const reference to the stored value const Type& value() const noexcept { return value_; } - /// The underlying value. + /// The underlying integer value. Type value_; }; diff --git a/include/rfl/Literal.hpp b/include/rfl/Literal.hpp index bd9ec0c8..f06e714e 100644 --- a/include/rfl/Literal.hpp +++ b/include/rfl/Literal.hpp @@ -18,11 +18,18 @@ namespace rfl { +/// Helper struct for Literal - stores a compile-time string name. template struct LiteralHelper { constexpr static internal::StringLiteral name_ = _name; }; +/// A type-safe representation of a fixed set of string values known at compile +/// time. Similar to an enum but with string values. Useful for representing +/// discriminators, status values, or any fixed set of string constants with +/// compile-time validation. +/// @tparam fields_ The compile-time string literals that this Literal can +/// represent template class Literal { using FieldsType = rfl::Tuple...>; @@ -37,31 +44,48 @@ class Literal { using ReflectionType = std::string; - /// Constructs a Literal from another literal. + /// Copy constructor - constructs a Literal from another literal with the same + /// fields. + /// @param _other The literal to copy from Literal(const Literal& _other) = default; - /// Constructs a Literal from another literal. + /// Move constructor - constructs a Literal from another literal with the same + /// fields. + /// @param _other The literal to move from Literal(Literal&& _other) noexcept = default; + /// Constructs a Literal from a string value. + /// @param _str The string representing one of the literal's allowed values + /// @throws std::bad_optional_access if the string is not one of the allowed + /// values Literal(const std::string& _str) : value_(find_value(_str).value()) {} + /// Default constructor - initializes to the first value (index 0). Literal() : value_(0) {} + /// Destructor. ~Literal() = default; - /// Constructs a new Literal. + /// Constructs a new Literal from a compile-time string name. + /// @tparam _name The compile-time string literal to create a Literal for + /// @return A Literal representing the specified name template static Literal make() { return Literal(Literal::template value_of<_name>()); } - /// Constructs a new Literal, equivalent to make, for reasons of consistency. + /// Constructs a new Literal from a compile-time string name. + /// Equivalent to make(), provided for consistency with from_value(). + /// @tparam _name The compile-time string literal to create a Literal for + /// @return A Literal representing the specified name template static Literal from_name() { return Literal::template make<_name>(); } - /// Constructs a new Literal. + /// Constructs a new Literal from a compile-time value index. + /// @tparam _value The index of the value (must be less than num_fields_) + /// @return A Literal representing the value at the specified index template static Literal from_value() { static_assert(_value < num_fields_, @@ -69,7 +93,10 @@ class Literal { return Literal(_value); } - /// Constructs a new Literal. + /// Constructs a new Literal from a runtime value index. + /// @param _value The index of the value + /// @return Result containing the Literal or an error if the value is out of + /// range static Result> from_value(ValueType _value) { if (_value >= num_fields_) { return error("Value cannot exceed number of fields."); @@ -77,7 +104,9 @@ class Literal { return Literal(_value); } - /// Determines whether the literal contains the string. + /// Determines whether the literal contains the string (runtime check). + /// @param _str The string to check for + /// @return true if the string is one of the allowed values, false otherwise static bool contains(const std::string& _str) { bool found = false; has_value(_str, &found); @@ -85,6 +114,8 @@ class Literal { } /// Determines whether the literal contains the string at compile time. + /// @tparam _name The compile-time string literal to check for + /// @return true if the string is one of the allowed values, false otherwise template static constexpr bool contains() { return find_value_of<_name>() != -1; @@ -92,6 +123,8 @@ class Literal { /// Determines whether the literal contains any of the strings in the other /// literal at compile time. + /// @tparam OtherLiteralType Another Literal type to check against + /// @return true if there is any overlap between the two literal types template static constexpr bool contains_any() { return [](const std::integer_sequence&) { @@ -103,6 +136,8 @@ class Literal { /// Determines whether the literal contains all of the strings in the other /// literal at compile time. + /// @tparam OtherLiteralType Another Literal type to check against + /// @return true if this literal contains all values from the other literal template static constexpr bool contains_all() { return [](const std::integer_sequence&) { @@ -113,13 +148,17 @@ class Literal { } /// Determines whether the literal has duplicate strings at compile time. - /// These is useful for checking collections of strings in other contexts. + /// This is useful for checking collections of strings in other contexts. + /// @return true if there are duplicate values in the literal static constexpr bool has_duplicates() { return !internal::no_duplicate_field_names(); } /// Constructs a Literal from a string. Returns an error if the string /// cannot be found. + /// @param _str The string to convert to a Literal + /// @return Result containing the Literal or an error if the string is not + /// recognized static Result from_string(const std::string& _str) { const auto to_literal = [](const auto& _v) { return Literal(_v); @@ -127,46 +166,68 @@ class Literal { return find_value(_str).transform(to_literal); }; - /// The name defined by the Literal. + /// The name defined by the Literal (returns the string representation). + /// @return The string value of the current literal std::string name() const { return find_name(); } /// Returns all possible values of the literal as a std::vector. + /// @return A vector containing all allowed string values static std::vector names() { return allowed_strings_vec(std::make_integer_sequence()); } /// Helper function to retrieve a name at compile time. + /// @tparam _value The index of the value to retrieve + /// @return A Literal containing just the name at the specified index template constexpr static auto name_of() { constexpr auto name = find_name_within_own_fields<_value>(); return Literal(); } - /// Assigns from another literal. + /// Copy assignment operator - assigns from another literal. + /// @param _other The literal to copy from + /// @return Reference to this literal Literal& operator=(const Literal& _other) = default; - /// Assigns from another literal. + /// Move assignment operator - assigns from another literal. + /// @param _other The literal to move from + /// @return Reference to this literal Literal& operator=(Literal&& _other) noexcept = default; - /// Assigns the literal from a string + /// Assigns the literal from a string. + /// @param _str The string to assign (must be one of the allowed values) + /// @return Reference to this literal + /// @throws std::bad_optional_access if the string is not one of the allowed + /// values Literal& operator=(const std::string& _str) { value_ = find_value(_str).value(); return *this; } - /// <=> for other Literals with the same fields. + /// Three-way comparison operator for other Literals with the same fields. + /// Compares by internal value index. + /// @param _other The other literal to compare with + /// @return The ordering relationship between the two literals auto operator<=>(const Literal& _other) const { return value() <=> _other.value(); } - /// <=> for other Literals with different fields. + /// Three-way comparison operator for other Literals with different fields. + /// Compares by string name lexicographically. + /// @tparam _fields The fields of the other Literal type + /// @param _l2 The other literal to compare with + /// @return The ordering relationship between the string values template inline auto operator<=>(const Literal<_fields...>& _l2) const { return name() <=> _l2.name(); } - /// <=> for strings. + /// Three-way comparison operator for strings. + /// @param _str The string to compare with + /// @return The ordering relationship between the literal's value and the + /// string inline auto operator<=>(const std::string& _str) const { #if __cpp_lib_three_way_comparison >= 201907L return name() <=> _str; @@ -182,8 +243,11 @@ class Literal { #endif } - /// <=> for const char*. - template + /// Three-way comparison operator for const char*. + /// @tparam other_fields Template parameter for compatibility + /// @param _str The C-string to compare with + /// @return The ordering relationship between the literal's value and the + /// string inline auto operator<=>(const char* _str) const { #if __cpp_lib_three_way_comparison >= 201907L return name() <=> _str; @@ -199,30 +263,42 @@ class Literal { #endif } - /// Equality operator. + /// Equality operator - works with Literals, strings, and other comparable + /// types. + /// @tparam Other The type to compare with + /// @param _other The value to compare with + /// @return true if the values are equal template bool operator==(const Other& _other) const { return (*this <=> _other) == 0; } - /// Alias for .name(). + /// Alias for .name() - returns the string representation for reflection. + /// @return The string value of the current literal std::string reflection() const { return name(); } /// Returns the number of fields in the Literal. + /// @return The total number of possible values this literal can hold static constexpr size_t size() { return num_fields_; } - /// Alias for .name(). + /// Alias for .name() - returns the string representation. + /// @return The string value of the current literal std::string str() const { return name(); } - /// Alias for .names(). + /// Alias for .names() - returns all possible string values. + /// @return A vector containing all allowed string values static std::vector strings() { return allowed_strings_vec(std::make_integer_sequence()); } - /// Returns the value actually contained in the Literal. + /// Returns the value actually contained in the Literal (the internal index). + /// @return The index representing the current value ValueType value() const { return value_; } - /// Returns the value of the string literal in the template. + /// Returns the value index of the string literal in the template at compile + /// time. + /// @tparam _name The compile-time string literal to get the index for + /// @return The index of the specified name template static constexpr ValueType value_of() { constexpr auto value = find_value_of<_name>(); @@ -231,7 +307,8 @@ class Literal { } private: - /// Only the static methods are allowed to access this. + /// Only the static methods are allowed to access this constructor. + /// @param _value The internal value index Literal(const ValueType _value) : value_(_value) {} /// Returns all of the allowed fields. diff --git a/include/rfl/MetaField.hpp b/include/rfl/MetaField.hpp index d55cbb2c..192c7e6c 100644 --- a/include/rfl/MetaField.hpp +++ b/include/rfl/MetaField.hpp @@ -5,25 +5,33 @@ namespace rfl { -/// Contains meta-information about a field in a struct. +/// Contains compile-time meta-information about a struct field. +/// MetaField stores the name and type information of a struct field for introspection purposes. +/// This is used internally by the reflection system to provide field metadata at runtime. class MetaField { public: + /// Constructs a MetaField with the given name and type information. + /// @param _name The name of the field as it appears in the struct + /// @param _type A string describing the type of the field MetaField(const std::string& _name, const std::string& _type) : name_(_name), type_(_type) {} + /// Destructor. ~MetaField() = default; - /// The name of the field we describe. + /// Returns the name of the field. + /// @return The field name as it appears in the struct const std::string& name() const { return name_; }; - /// The type of the field we describe. + /// Returns the type information of the field. + /// @return A string describing the field's type const std::string& type() const { return type_; }; private: - /// The name of the field we describe. + /// The name of the field. std::string name_; - /// The type of the field we describe. + /// The type information of the field. std::string type_; }; diff --git a/include/rfl/NamedTuple.hpp b/include/rfl/NamedTuple.hpp index ca759526..ccb6e597 100644 --- a/include/rfl/NamedTuple.hpp +++ b/include/rfl/NamedTuple.hpp @@ -22,8 +22,11 @@ namespace rfl { /// A named tuple behaves like a tuple, /// but the fields have explicit names, which /// allows for reflection. -/// IMPORTANT: We have two template specializations. One with fields, one -/// without fields. +/// It is one of the core types in the library, and is used as the underlying +/// type for structs. When we reflect a struct, we get a named tuple where each +/// field corresponds to a field in the struct, and the field names are the same +/// as the struct's field names. IMPORTANT: We have two template +/// specializations. One with fields, one without fields. template class NamedTuple; @@ -43,55 +46,74 @@ class NamedTuple { using Values = rfl::Tuple::Type...>; public: - /// Construct from the values. + /// @brief Construct NamedTuple from values of each field type. + /// @param _values Rvalue references to the values for each field. NamedTuple(typename std::remove_cvref::type::Type&&... _values) : values_( std::forward::type::Type>( _values)...) {} - /// Construct from the values. + /// @brief Construct NamedTuple from values of each field type. + /// @param _values Const lvalue references to the values for each field. NamedTuple( const typename std::remove_cvref::type::Type&... _values) : values_(rfl::make_tuple(_values...)) {} - /// Construct from the fields. + /// @brief Construct NamedTuple from fields (rvalue). + /// @param _fields Rvalue references to fields. NamedTuple(FieldTypes&&... _fields) : values_(rfl::make_tuple(std::move(_fields.value_)...)) {} - /// Construct from the fields. + /// @brief Construct NamedTuple from fields (const lvalue). + /// @param _fields Const lvalue references to fields. NamedTuple(const FieldTypes&... _fields) : values_(rfl::make_tuple(_fields.value_...)) {} - /// Construct from a tuple containing fields. + /// @brief Construct NamedTuple from a tuple containing fields (rvalue). + /// @param _tup Tuple of fields. NamedTuple(rfl::Tuple&& _tup) : NamedTuple(rfl::make_from_tuple>( std::forward>(_tup))) {} - /// Construct from a tuple containing fields. + /// @brief Construct NamedTuple from a tuple containing fields (const lvalue). + /// @param _tup Tuple of fields. NamedTuple(const rfl::Tuple& _tup) : NamedTuple(rfl::make_from_tuple>(_tup)) {} - /// Copy constructor. + /// @brief Copy constructor. + /// @param _other Another NamedTuple to copy from. NamedTuple(const NamedTuple& _other) = default; - /// Move constructor. + /// @brief Move constructor. + /// @param _other Another NamedTuple to move from. NamedTuple(NamedTuple&& _other) = default; - /// Copy constructor. + /// @brief Copy constructor from another NamedTuple with possibly different + /// field types. + /// @param _other Another NamedTuple to copy from. template NamedTuple(const NamedTuple& _other) : NamedTuple(retrieve_fields(_other.fields(), seq_)) {} - /// Move constructor. + /// @brief Move constructor from another NamedTuple with possibly different + /// field types. + /// @param _other Another NamedTuple to move from. template NamedTuple(NamedTuple&& _other) : NamedTuple(retrieve_fields( std::forward>(_other).fields(), seq_)) {} + /// @brief Destructor. ~NamedTuple() = default; - /// Returns a new named tuple with additional fields. + /// @brief Returns a new NamedTuple with additional fields (rvalue overload). + /// @tparam _name Name of the field to add. + /// @tparam FType Type of the field to add. + /// @tparam Tail Additional fields to add. + /// @param _head Field to add. + /// @param _tail Additional fields to add. + /// @return New NamedTuple with added fields. template auto add(Field<_name, FType>&& _head, Tail&&... _tail) && { using Head = Field<_name, FType>; @@ -105,7 +127,14 @@ class NamedTuple { } } - /// Returns a new named tuple with additional fields. + /// @brief Returns a new NamedTuple with additional fields (const lvalue + /// overload). + /// @tparam _name Name of the field to add. + /// @tparam FType Type of the field to add. + /// @tparam Tail Additional fields to add. + /// @param _head Field to add. + /// @param _tail Additional fields to add. + /// @return New NamedTuple with added fields. template auto add(Field<_name, FType> _head, const Tail&... _tail) const& { using Head = Field<_name, FType>; @@ -119,8 +148,12 @@ class NamedTuple { } } - /// Template specialization for rfl::Tuple, so we can pass fields from other - /// named tuples. + /// @brief Add fields from a tuple (rvalue overload). + /// @tparam TupContent Types of the tuple contents. + /// @tparam Tail Additional fields to add. + /// @param _tuple Tuple of fields to add. + /// @param _tail Additional fields to add. + /// @return New NamedTuple with added fields. template auto add(rfl::Tuple&& _tuple, Tail&&... _tail) && { if constexpr (sizeof...(Tail) > 0) { @@ -133,8 +166,12 @@ class NamedTuple { } } - /// Template specialization for rfl::Tuple, so we can pass fields from other - /// named tuples. + /// @brief Add fields from a tuple (const lvalue overload). + /// @tparam TupContent Types of the tuple contents. + /// @tparam Tail Additional fields to add. + /// @param _tuple Tuple of fields to add. + /// @param _tail Additional fields to add. + /// @return New NamedTuple with added fields. template auto add(rfl::Tuple _tuple, const Tail&... _tail) const& { if constexpr (sizeof...(Tail) > 0) { @@ -144,8 +181,12 @@ class NamedTuple { } } - /// Template specialization for NamedTuple, so we can pass fields from other - /// named tuples. + /// @brief Add fields from another NamedTuple (rvalue overload). + /// @tparam TupContent Types of the NamedTuple fields. + /// @tparam Tail Additional fields to add. + /// @param _named_tuple NamedTuple to add fields from. + /// @param _tail Additional fields to add. + /// @return New NamedTuple with added fields. template auto add(NamedTuple&& _named_tuple, Tail&&... _tail) && { return std::move(*this).add( @@ -154,16 +195,23 @@ class NamedTuple { std::forward(_tail)...); } - /// Template specialization for NamedTuple, so we can pass fields from other - /// named tuples. + /// @brief Add fields from another NamedTuple (const lvalue overload). + /// @tparam TupContent Types of the NamedTuple fields. + /// @tparam Tail Additional fields to add. + /// @param _named_tuple NamedTuple to add fields from. + /// @param _tail Additional fields to add. + /// @return New NamedTuple with added fields. template auto add(NamedTuple _named_tuple, const Tail&... _tail) const& { return add(_named_tuple.fields(), _tail...); } - /// Creates a new named tuple by applying the supplied function to - /// field. The function is expected to return a named tuple itself. + /// @brief Applies a function to each field, returning a new NamedTuple with + /// the results (rvalue overload). + /// @tparam F Callable type. + /// @param _f Function to apply to each field. Must return a NamedTuple. + /// @return New NamedTuple with fields from the results of _f. template auto and_then(const F& _f) && { const auto transform_field = [&_f](auto... _fields) { @@ -176,8 +224,11 @@ class NamedTuple { return to_nt(std::move(new_fields)); } - /// Creates a new named tuple by applying the supplied function to - /// field. The function is expected to return a named tuple itself. + /// @brief Applies a function to each field, returning a new NamedTuple with + /// the results (const lvalue overload). + /// @tparam F Callable type. + /// @param _f Function to apply to each field. Must return a NamedTuple. + /// @return New NamedTuple with fields from the results of _f. template auto and_then(const F& _f) const& { const auto transform_field = [&_f](auto... _fields) { @@ -190,7 +241,9 @@ class NamedTuple { return to_nt(std::move(new_fields)); } - /// Invokes a callable object once for each field in order. + /// @brief Invokes a callable object once for each field in order. + /// @tparam F Callable type. + /// @param _f Function to apply to each field. template void apply(F&& _f) const& { const auto apply_to_field = [&_f](const auto&... fields) { @@ -199,76 +252,98 @@ class NamedTuple { rfl::apply(apply_to_field, fields()); } - /// Returns a tuple containing the fields. + /// @brief Returns a tuple containing the fields (rvalue overload). + /// @return Tuple of fields. Fields fields() && { return std::move(*this).make_fields(seq_); } - /// Returns a tuple containing the fields. + /// @brief Returns a tuple containing the fields (const lvalue overload). + /// @return Tuple of fields. Fields fields() const& { return make_fields(seq_); } - /// Gets a field by index. + /// @brief Gets a field by index (mutable). + /// @tparam _index Index of the field. + /// @return Reference to the field. template auto& get() { return rfl::get<_index>(*this); } - /// Gets a field by name. + /// @brief Gets a field by name (mutable). + /// @tparam _field_name Name of the field. + /// @return Reference to the field. template auto& get() { return rfl::get<_field_name>(*this); } - /// Gets a field by the field type. + /// @brief Gets a field by the field type (mutable). + /// @tparam Field Field type. + /// @return Reference to the field. template auto& get() { return rfl::get(*this); } - /// Gets a field by index. + /// @brief Gets a field by index (const). + /// @tparam _index Index of the field. + /// @return Const reference to the field. template const auto& get() const { return rfl::get<_index>(*this); } - /// Gets a field by name. + /// @brief Gets a field by name (const). + /// @tparam _field_name Name of the field. + /// @return Const reference to the field. template const auto& get() const { return rfl::get<_field_name>(*this); } - /// Gets a field by the field type. + /// @brief Gets a field by the field type (const). + /// @tparam Field Field type. + /// @return Const reference to the field. template const auto& get() const { return rfl::get(*this); } - /// Returns the results wrapped in a field. + /// @brief Returns the results wrapped in a field. + /// @tparam _field_name Name of the field. + /// @return Field containing the value. template auto get_field() const { return rfl::make_field<_field_name>(rfl::get<_field_name>(*this)); } - /// Copy assignment operator. + /// @brief Copy assignment operator. + /// @param _other NamedTuple to copy from. + /// @return Reference to this NamedTuple. NamedTuple& operator=( const NamedTuple& _other) = default; - /// Move assignment operator. + /// @brief Move assignment operator. + /// @param _other NamedTuple to move from. + /// @return Reference to this NamedTuple. NamedTuple& operator=( NamedTuple&& _other) noexcept = default; - /// Equality operator + /// @brief Equality operator. + /// @param _other NamedTuple to compare with. + /// @return True if equal, false otherwise. inline auto operator==(const rfl::NamedTuple& _other) const { return values() == _other.values(); } - /// Three-way comparison operator. + /// @brief Three-way comparison operator. + /// @param _other NamedTuple to compare with. + /// @return Comparison result. inline auto operator<=>(const rfl::NamedTuple& _other) const { return values() <=> _other.values(); } - /// Returns the number of fields. Note that this is not necessary the same - /// thing as .size(), because there might be rfl::ExtraFields, which are - /// simply counted as one entry by .size(), but are counted by individually by - /// .num_fields(). + /// @brief Returns the number of fields, counting ExtraFields individually. + /// @return Number of fields. size_t num_fields() const { if constexpr (pos_extra_fields() == -1) { return size(); @@ -277,11 +352,19 @@ class NamedTuple { } } - /// The position of the extra fields, or -1 if there aren't any. + /// @brief Returns the position of the extra fields, or -1 if there aren't + /// any. + /// @return Position of extra fields or -1. constexpr static int pos_extra_fields() { return pos_extra_fields_; } - /// Replaces one or several fields, returning a new version - /// with the non-replaced fields left unchanged. + /// @brief Replaces one or several fields, returning a new version with the + /// non-replaced fields left unchanged (rvalue overload). + /// @tparam _name Name of the field to replace. + /// @tparam FType Type of the field to replace. + /// @tparam OtherRFields Other fields to replace. + /// @param _field Field to replace. + /// @param _other_fields Other fields to replace. + /// @return New NamedTuple with replaced fields. template auto replace(Field<_name, FType>&& _field, OtherRFields&&... _other_fields) && { @@ -296,8 +379,14 @@ class NamedTuple { } } - /// Replaces one or several fields, returning a new version - /// with the non-replaced fields left unchanged. + /// @brief Replaces one or several fields, returning a new version with the + /// non-replaced fields left unchanged (const lvalue overload). + /// @tparam _name Name of the field to replace. + /// @tparam FType Type of the field to replace. + /// @tparam OtherRFields Other fields to replace. + /// @param _field Field to replace. + /// @param _other_fields Other fields to replace. + /// @return New NamedTuple with replaced fields. template auto replace(Field<_name, FType> _field, const OtherRFields&... _other_fields) const& { @@ -311,8 +400,12 @@ class NamedTuple { } } - /// Template specialization for rfl::Tuple, so we can pass fields from other - /// named tuples. + /// @brief Replace fields from a tuple (rvalue overload). + /// @tparam TupContent Types of the tuple contents. + /// @tparam Tail Additional fields to replace. + /// @param _tuple Tuple of fields to replace. + /// @param _tail Additional fields to replace. + /// @return New NamedTuple with replaced fields. template auto replace(rfl::Tuple&& _tuple, Tail&&... _tail) && { if constexpr (sizeof...(Tail) > 0) { @@ -325,8 +418,12 @@ class NamedTuple { } } - /// Template specialization for rfl::Tuple, so we can pass fields from other - /// named tuples. + /// @brief Replace fields from a tuple (const lvalue overload). + /// @tparam TupContent Types of the tuple contents. + /// @tparam Tail Additional fields to replace. + /// @param _tuple Tuple of fields to replace. + /// @param _tail Additional fields to replace. + /// @return New NamedTuple with replaced fields. template auto replace(rfl::Tuple _tuple, const Tail&... _tail) const& { if constexpr (sizeof...(Tail) > 0) { @@ -336,8 +433,12 @@ class NamedTuple { } } - /// Template specialization for NamedTuple, so we can pass fields from other - /// named tuples. + /// @brief Replace fields from another NamedTuple (rvalue overload). + /// @tparam TupContent Types of the NamedTuple fields. + /// @tparam Tail Additional fields to replace. + /// @param _named_tuple NamedTuple to replace fields from. + /// @param _tail Additional fields to replace. + /// @return New NamedTuple with replaced fields. template auto replace(NamedTuple&& _named_tuple, Tail&&... _tail) && { return std::move(*this).replace( @@ -345,19 +446,28 @@ class NamedTuple { std::forward(_tail)...); } - /// Template specialization for NamedTuple, so we can pass fields from other - /// named tuples. + /// @brief Replace fields from another NamedTuple (const lvalue overload). + /// @tparam TupContent Types of the NamedTuple fields. + /// @tparam Tail Additional fields to replace. + /// @param _named_tuple NamedTuple to replace fields from. + /// @param _tail Additional fields to replace. + /// @return New NamedTuple with replaced fields. template auto replace(NamedTuple _named_tuple, const Tail&... _tail) const& { return replace(_named_tuple.fields(), _tail...); } - /// Returns the size of the named tuple + /// @brief Returns the size of the NamedTuple (number of fields, not counting + /// ExtraFields individually). + /// @return Number of fields. static constexpr size_t size() { return rfl::tuple_size_v; } - /// Creates a new named tuple by applying the supplied function to every - /// field. + /// @brief Applies a function to every field, returning a new NamedTuple with + /// the results (rvalue overload). + /// @tparam F Callable type. + /// @param _f Function to apply to each field. + /// @return New NamedTuple with transformed fields. template auto transform(const F& _f) && { const auto transform_field = [&_f](auto... fields) { @@ -370,8 +480,11 @@ class NamedTuple { return to_nt(std::move(new_fields)); } - /// Creates a new named tuple by applying the supplied function to every - /// field. + /// @brief Applies a function to every field, returning a new NamedTuple with + /// the results (const lvalue overload). + /// @tparam F Callable type. + /// @param _f Function to apply to each field. + /// @return New NamedTuple with transformed fields. template auto transform(const F& _f) const& { const auto transform_field = [&_f](auto... fields) { @@ -384,15 +497,20 @@ class NamedTuple { return to_nt(std::move(new_fields)); } - /// Returns the underlying rfl::Tuple. + /// @brief Returns the underlying rfl::Tuple of values (mutable). + /// @return Reference to the tuple of values. Values& values() { return values_; } - /// Returns the underlying rfl::Tuple. + /// @brief Returns the underlying rfl::Tuple of values (const). + /// @return Const reference to the tuple of values. const Values& values() const { return values_; } private: - /// Adds the elements of a tuple to a newly created named tuple, - /// and other elements to a newly created named tuple. + /// @brief Adds the elements of a tuple to a newly created NamedTuple (rvalue + /// overload). + /// @tparam TupContent Types of the tuple contents. + /// @param _tuple Tuple of fields to add. + /// @return New NamedTuple with added fields. template constexpr auto add_tuple(rfl::Tuple&& _tuple) && { const auto a = [this](auto&&... _fields) { @@ -401,8 +519,11 @@ class NamedTuple { return rfl::apply(a, std::forward>(_tuple)); } - /// Adds the elements of a tuple to a newly created named tuple, - /// and other elements to a newly created named tuple. + /// @brief Adds the elements of a tuple to a newly created NamedTuple (const + /// lvalue overload). + /// @tparam TupContent Types of the tuple contents. + /// @param _tuple Tuple of fields to add. + /// @return New NamedTuple with added fields. template constexpr auto add_tuple(rfl::Tuple&& _tuple) const& { const auto a = [this](auto&&... _fields) { @@ -411,7 +532,9 @@ class NamedTuple { return rfl::apply(a, std::forward>(_tuple)); } - /// Unfortunately, MSVC forces us to do this... + /// @brief Calculates the number of fields, counting ExtraFields individually. + /// @tparam _pos Position of ExtraFields. + /// @return Number of fields. template size_t calc_num_fields() const { const auto& extra_fields = get<_pos>(); @@ -423,7 +546,10 @@ class NamedTuple { } } - /// Finds the position of the extra fields, or -1 if there aren't any. + /// @brief Finds the position of the extra fields, or -1 if there aren't any. + /// @tparam _i Current index. + /// @tparam _idx Index of ExtraFields found so far. + /// @return Position of ExtraFields or -1. template constexpr static int find_extra_fields() { if constexpr (_i == size()) { @@ -443,7 +569,11 @@ class NamedTuple { } } - /// Generates the fields. + /// @brief Generates the fields for the NamedTuple (rvalue overload). + /// @tparam _is Indices of the fields. + /// @tparam AdditionalArgs Additional arguments to append. + /// @param _args Additional fields to append. + /// @return Tuple of fields. template auto make_fields(std::integer_sequence, AdditionalArgs&&... _args) && { @@ -455,7 +585,11 @@ class NamedTuple { std::forward(_args)...); } - /// Generates the fields. + /// @brief Generates the fields for the NamedTuple (const lvalue overload). + /// @tparam _is Indices of the fields. + /// @tparam AdditionalArgs Additional arguments to append. + /// @param _args Additional fields to append. + /// @return Tuple of fields. template auto make_fields(std::integer_sequence, AdditionalArgs... _args) const& { @@ -466,7 +600,15 @@ class NamedTuple { return rfl::make_tuple(wrap(Index<_is>{})..., _args...); } - /// Generates a new named tuple with one value replaced with a new value. + /// @brief Generates a new NamedTuple with one value replaced with a new + /// value. + /// @tparam _index Index of the field to replace. + /// @tparam V Tuple of values. + /// @tparam T Value to replace with. + /// @tparam _is Indices of the fields. + /// @param _values Tuple of values. + /// @param _val Value to replace with. + /// @return New NamedTuple with replaced value. template auto make_replaced(V&& _values, T&& _val, std::integer_sequence) const { @@ -482,7 +624,11 @@ class NamedTuple { return NamedTuple(wrap(Index<_is>{})...); } - /// Replaced the field signified by the field type. + /// @brief Replaces the field signified by the field type (rvalue overload). + /// @tparam Field Field type to replace. + /// @tparam T Value to replace with. + /// @param _val Value to replace with. + /// @return New NamedTuple with replaced value. template NamedTuple replace_value(T&& _val) && { using FieldType = std::remove_cvref_t; @@ -491,7 +637,12 @@ class NamedTuple { seq_); } - /// Replaced the field signified by the field type. + /// @brief Replaces the field signified by the field type (const lvalue + /// overload). + /// @tparam Field Field type to replace. + /// @tparam T Value to replace with. + /// @param _val Value to replace with. + /// @return New NamedTuple with replaced value. template NamedTuple replace_value(T&& _val) const& { using FieldType = std::remove_cvref_t; @@ -500,8 +651,10 @@ class NamedTuple { return make_replaced(std::move(values), std::forward(_val), seq_); } - /// Adds the elements of a tuple to a newly created named tuple, - /// and other elements to a newly created named tuple. + /// @brief Replaces fields from a tuple (rvalue overload). + /// @tparam TupContent Types of the tuple contents. + /// @param _tuple Tuple of fields to replace. + /// @return New NamedTuple with replaced fields. template auto replace_tuple(rfl::Tuple&& _tuple) && { const auto r = [this](auto&&... _fields) { @@ -510,8 +663,10 @@ class NamedTuple { return rfl::apply(r, std::forward>(_tuple)); } - /// Adds the elements of a tuple to a newly created named tuple, - /// and other elements to a newly created named tuple. + /// @brief Replaces fields from a tuple (const lvalue overload). + /// @tparam TupContent Types of the tuple contents. + /// @param _tuple Tuple of fields to replace. + /// @return New NamedTuple with replaced fields. template auto replace_tuple(rfl::Tuple&& _tuple) const& { const auto r = [this](auto&&... _fields) { @@ -520,7 +675,11 @@ class NamedTuple { return rfl::apply(r, std::forward>(_tuple)); } - /// Retrieves the fields from another tuple. + /// @brief Retrieves the fields from another tuple. + /// @tparam OtherFieldTypes Types of the other tuple's fields. + /// @tparam _is Indices of the fields. + /// @param _other_fields Tuple of fields to retrieve from. + /// @return Tuple of fields matching the current NamedTuple's field types. template constexpr static Fields retrieve_fields( rfl::Tuple&& _other_fields, @@ -538,19 +697,16 @@ class NamedTuple { } private: - /// The values actually contained in the named tuple. - /// As you can see, a NamedTuple is just a normal tuple under-the-hood, - /// everything else is resolved at compile time. It should have no - /// runtime overhead over a normal rfl::Tuple. + /// @brief The values actually contained in the NamedTuple. Values values_; - /// The position of rfl::ExtraFields, or -1 if there aren't any. + /// @brief The position of rfl::ExtraFields, or -1 if there aren't any. constexpr static int pos_extra_fields_ = find_extra_fields(); }; // ---------------------------------------------------------------------------- -/// We need a special template instantiation for empty named tuples. +/// @brief Specialization for empty NamedTuple. template <> class NamedTuple<> { public: @@ -558,11 +714,19 @@ class NamedTuple<> { using Names = Literal<>; using Values = rfl::Tuple<>; + /// @brief Default constructor for empty NamedTuple. NamedTuple(){}; + /// @brief Destructor. ~NamedTuple() = default; - /// Returns a new named tuple with additional fields. + /// @brief Returns a new NamedTuple with additional fields. + /// @tparam _name Name of the field to add. + /// @tparam FType Type of the field to add. + /// @tparam Tail Additional fields to add. + /// @param _head Field to add. + /// @param _tail Additional fields to add. + /// @return New NamedTuple with added fields. template auto add(Field<_name, FType> _head, const Tail&... _tail) const { if constexpr (sizeof...(Tail) > 0) { @@ -572,8 +736,12 @@ class NamedTuple<> { } } - /// Template specialization for rfl::Tuple, so we can pass fields from other - /// named tuples. + /// @brief Add fields from a tuple. + /// @tparam TupContent Types of the tuple contents. + /// @tparam Tail Additional fields to add. + /// @param _tuple Tuple of fields to add. + /// @param _tail Additional fields to add. + /// @return New NamedTuple with added fields. template auto add(rfl::Tuple _tuple, const Tail&... _tail) const { if constexpr (sizeof...(Tail) > 0) { @@ -583,47 +751,73 @@ class NamedTuple<> { } } - /// Template specialization for NamedTuple, so we can pass fields from other - /// named tuples. + /// @brief Add fields from another NamedTuple. + /// @tparam TupContent Types of the NamedTuple fields. + /// @tparam Tail Additional fields to add. + /// @param _named_tuple NamedTuple to add fields from. + /// @param _tail Additional fields to add. + /// @return New NamedTuple with added fields. template auto add(NamedTuple _named_tuple, const Tail&... _tail) const { return add(_named_tuple.fields(), _tail...); } - /// Returns an empty named tuple. + /// @brief Applies a function to each field, returning a new NamedTuple + /// (always empty). + /// @tparam F Callable type. + /// @param _f Function to apply. + /// @return Empty NamedTuple. template auto and_then(const F&) const { return NamedTuple<>(); } - /// Does nothing at all. + /// @brief Does nothing at all (for empty NamedTuple). + /// @tparam F Callable type. + /// @param _f Function to apply. template void apply(F&&) const {} - /// Returns an empty tuple. + /// @brief Returns an empty tuple of fields. + /// @return Empty tuple. auto fields() const { return rfl::Tuple(); } - /// Must always be 0. + /// @brief Must always be 0. + /// @return 0 size_t num_fields() const { return 0; } - /// Must always be -1. + /// @brief Must always be -1. + /// @return -1 constexpr static int pos_extra_fields() { return -1; } - /// Must always be 0. + /// @brief Must always be 0. + /// @return 0 static constexpr size_t size() { return 0; } - /// Returns an empty named tuple. + /// @brief Returns an empty NamedTuple. + /// @tparam F Callable type. + /// @param _f Function to apply. + /// @return Empty NamedTuple. template auto transform(const F&) const { return NamedTuple<>(); } - /// Returns an empty tuple. + /// @brief Returns an empty tuple of values. + /// @return Empty tuple. auto values() const { return rfl::Tuple(); } }; // ---------------------------------------------------------------------------- +/// @brief Operator* to combine two fields into a NamedTuple. +/// @tparam _name1 Name of first field. +/// @tparam Type1 Type of first field. +/// @tparam _name2 Name of second field. +/// @tparam Type2 Type of second field. +/// @param _f1 First field. +/// @param _f2 Second field. +/// @return NamedTuple containing both fields. template inline auto operator*(const rfl::Field<_name1, Type1>& _f1, @@ -631,24 +825,52 @@ inline auto operator*(const rfl::Field<_name1, Type1>& _f1, return NamedTuple(_f1, _f2); } +/// @brief Operator* to add a field to a NamedTuple. +/// @tparam _name Name of the field. +/// @tparam Type Type of the field. +/// @tparam FieldTypes Types of the NamedTuple fields. +/// @param _tup NamedTuple. +/// @param _f Field to add. +/// @return New NamedTuple with the field added. template inline auto operator*(const NamedTuple& _tup, const rfl::Field<_name, Type>& _f) { return _tup.add(_f); } +/// @brief Operator* to add a NamedTuple to a field. +/// @tparam _name Name of the field. +/// @tparam Type Type of the field. +/// @tparam FieldTypes Types of the NamedTuple fields. +/// @param _f Field to add. +/// @param _tup NamedTuple. +/// @return New NamedTuple with the field prepended. template inline auto operator*(const rfl::Field<_name, Type>& _f, const NamedTuple& _tup) { return NamedTuple(_f).add(_tup); } +/// @brief Operator* to combine two NamedTuples. +/// @tparam FieldTypes1 Types of the first NamedTuple fields. +/// @tparam FieldTypes2 Types of the second NamedTuple fields. +/// @param _tup1 First NamedTuple. +/// @param _tup2 Second NamedTuple. +/// @return New NamedTuple with all fields from both. template inline auto operator*(const NamedTuple& _tup1, const NamedTuple& _tup2) { return _tup1.add(_tup2); } +/// @brief Operator* to combine two fields into a NamedTuple (rvalue overload). +/// @tparam _name1 Name of first field. +/// @tparam Type1 Type of first field. +/// @tparam _name2 Name of second field. +/// @tparam Type2 Type of second field. +/// @param _f1 First field (rvalue). +/// @param _f2 Second field (rvalue). +/// @return NamedTuple containing both fields. template inline auto operator*(rfl::Field<_name1, Type1>&& _f1, @@ -657,12 +879,26 @@ inline auto operator*(rfl::Field<_name1, Type1>&& _f1, std::forward>(_f2)); } +/// @brief Operator* to add a field to a NamedTuple (rvalue overload). +/// @tparam _name Name of the field. +/// @tparam Type Type of the field. +/// @tparam FieldTypes Types of the NamedTuple fields. +/// @param _tup NamedTuple (rvalue). +/// @param _f Field to add (rvalue). +/// @return New NamedTuple with the field added. template inline auto operator*(NamedTuple&& _tup, rfl::Field<_name, Type>&& _f) { return _tup.add(std::forward>(_f)); } +/// @brief Operator* to add a NamedTuple to a field (rvalue overload). +/// @tparam _name Name of the field. +/// @tparam Type Type of the field. +/// @tparam FieldTypes Types of the NamedTuple fields. +/// @param _f Field to add (rvalue). +/// @param _tup NamedTuple (rvalue). +/// @return New NamedTuple with the field prepended. template inline auto operator*(rfl::Field<_name, Type>&& _f, NamedTuple&& _tup) { @@ -670,6 +906,12 @@ inline auto operator*(rfl::Field<_name, Type>&& _f, .add(std::forward>(_tup)); } +/// @brief Operator* to combine two NamedTuples (rvalue overload). +/// @tparam FieldTypes1 Types of the first NamedTuple fields. +/// @tparam FieldTypes2 Types of the second NamedTuple fields. +/// @param _tup1 First NamedTuple (rvalue). +/// @param _tup2 Second NamedTuple (rvalue). +/// @return New NamedTuple with all fields from both. template inline auto operator*(NamedTuple&& _tup1, NamedTuple&& _tup2) { diff --git a/include/rfl/NoExtraFields.hpp b/include/rfl/NoExtraFields.hpp index 85cf82ac..484507a3 100644 --- a/include/rfl/NoExtraFields.hpp +++ b/include/rfl/NoExtraFields.hpp @@ -3,11 +3,18 @@ namespace rfl { -/// This is a "fake" processor - it doesn't do much in itself, but its -/// inclusion instructs the parsers to return an error when there are extra -/// fields instead of ignoring them. +/// A processor that instructs parsers to return an error when extra fields are present. +/// This is a marker type (doesn't modify data) that changes parser behavior. +/// By default, parsers ignore unknown fields in serialized data. Including NoExtraFields +/// as a processor will cause parsing to fail if the input contains fields not in the struct. +/// Usage: rfl::json::read(json_str) struct NoExtraFields { public: + /// Identity process function - returns the named tuple unchanged. + /// The actual validation 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 static auto process(auto&& _named_tuple) { return _named_tuple; diff --git a/include/rfl/NoFieldNames.hpp b/include/rfl/NoFieldNames.hpp index 91677abe..12c05eee 100644 --- a/include/rfl/NoFieldNames.hpp +++ b/include/rfl/NoFieldNames.hpp @@ -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 strip field names. +/// A processor that instructs parsers to strip field names during serialization. +/// This is a marker type (doesn't modify data) that changes parser behavior. +/// When included as a processor, output will be positional/array-based instead of named. +/// For example, JSON output becomes [value1, value2] instead of {"field1": value1, "field2": value2}. +/// Note: Not supported for BSON, XML, TOML, or YAML formats. +/// Usage: rfl::json::write(my_struct) struct NoFieldNames { public: + /// Identity process function - returns the named tuple unchanged. + /// The actual stripping happens in the writer, 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 static auto process(auto&& _named_tuple) { return _named_tuple; diff --git a/include/rfl/NoOptionals.hpp b/include/rfl/NoOptionals.hpp index 9a7b3cd0..1da01c1f 100644 --- a/include/rfl/NoOptionals.hpp +++ b/include/rfl/NoOptionals.hpp @@ -3,10 +3,18 @@ namespace rfl { -/// This is a "fake" processor - it doesn't do much in itself, but its -/// inclusion instructs the parsers to require the inclusion of all fields. +/// A processor that instructs parsers to require all fields be present in input. +/// This is a marker type (doesn't modify data) that changes parser behavior. +/// By default, optional fields (std::optional, rfl::Box with defaults) can be omitted from input. +/// Including NoOptionals as a processor makes all fields mandatory, even those that would normally be optional. +/// Usage: rfl::json::read(json_str) struct NoOptionals { public: + /// Identity process function - returns the named tuple unchanged. + /// The actual requirement enforcement 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 static auto process(auto&& _named_tuple) { return _named_tuple; diff --git a/include/rfl/Object.hpp b/include/rfl/Object.hpp index f323793b..9a69bf67 100644 --- a/include/rfl/Object.hpp +++ b/include/rfl/Object.hpp @@ -14,6 +14,9 @@ namespace rfl { /// Used to embed additional fields for which the names cannot be known in /// advance and can therefore not be encoded in the struct. +/// This is an ordered associative container that preserves insertion order, +/// unlike std::map. Useful for JSON objects with unknown or dynamic keys. +/// @tparam T The value type stored in the object template class Object { public: @@ -36,119 +39,170 @@ class Object { using reverse_iterator = typename DataType::reverse_iterator; using const_reverse_iterator = typename DataType::const_reverse_iterator; + /// Default constructor - creates an empty object. Object() : data_(), i_(0) {} + /// Copy constructor. + /// @param _f The object to copy from Object(const Object& _f) = default; + /// Move constructor. + /// @param _f The object to move from Object(Object&& _f) noexcept = default; + /// Destructor. ~Object() = default; /// Iterator to the beginning. + /// @return Iterator to the first element auto begin() { return data_.begin(); } - /// Iterator to the beginning. + /// Iterator to the beginning (const version). + /// @return Const iterator to the first element auto begin() const { return data_.begin(); } /// Const iterator to the beginning. + /// @return Const iterator to the first element auto cbegin() const { return data_.cbegin(); } /// Iterator to the end. + /// @return Iterator past the last element auto end() { return data_.end(); } - /// Iterator to the end. + /// Iterator to the end (const version). + /// @return Const iterator past the last element auto end() const { return data_.end(); } /// Const iterator to the end. + /// @return Const iterator past the last element auto cend() const { return data_.cend(); } - /// Reverse iterator. + /// Reverse iterator to the beginning (points to last element). + /// @return Reverse iterator to the last element auto rbegin() { return data_.rbegin(); } - /// Reverse iterator. + /// Reverse iterator to the beginning (const version). + /// @return Const reverse iterator to the last element auto rbegin() const { return data_.rbegin(); } - /// Const reverse iterator. + /// Const reverse iterator to the beginning. + /// @return Const reverse iterator to the last element auto crbegin() const { return data_.crbegin(); } - /// Reverse iterator. + /// Reverse iterator to the end (points before first element). + /// @return Reverse iterator before the first element auto rend() { return data_.rend(); } - /// Reverse iterator. + /// Reverse iterator to the end (const version). + /// @return Const reverse iterator before the first element auto rend() const { return data_.rend(); } - /// Const reverse iterator. + /// Const reverse iterator to the end. + /// @return Const reverse iterator before the first element auto crend() const { return data_.crend(); } + /// Copy assignment operator. + /// @param _f The object to copy from + /// @return Reference to this object Object& operator=(const Object& _f) = default; + /// Move assignment operator. + /// @param _f The object to move from + /// @return Reference to this object Object& operator=(Object&& _f) = default; /// Whether the object is empty. + /// @return true if the object contains no elements auto empty() const { return data_.size() == 0; } /// The number of elements currently inside the object. + /// @return The number of key-value pairs auto size() const { return data_.size(); } + /// Counts occurrences of a key (0 or 1 since keys should be unique). + /// @param key The key to count + /// @return The number of elements with the specified key (typically 0 or 1) std::size_t count(const key_type& key) const { return std::count_if(cbegin(), cend(), [&](const auto& p) { return p.first == key; }); } - /// The maximum possible size. + /// The maximum possible size of the object. + /// @return The maximum number of elements that can be stored auto max_size() const { return data_.max_size(); } - /// Inserts a new element at the end. + /// Inserts new elements at the end (variadic copy version). + /// @tparam Args Types of the values to insert + /// @param _values The key-value pairs to insert template void insert(const Args&... _values) { (data_.push_back(_values), ...); i_ = 0; } - /// Inserts a new element at the end. + /// Inserts new elements at the end (variadic move version). + /// @tparam Args Types of the values to insert + /// @param _values The key-value pairs to insert (will be moved) template void insert(Args&&... _values) { (data_.emplace_back(std::move(_values)), ...); i_ = 0; } - /// Inserts a new element at the end. + /// Inserts a new key-value pair at the end (copy version). + /// @param _k The key + /// @param _v The value to associate with the key void insert(const std::string& _k, const T& _v) { insert(std::make_pair(_k, _v)); } - /// Inserts a new element at the end. + /// Inserts a new key-value pair at the end (value move version). + /// @param _k The key + /// @param _v The value to associate with the key (will be moved) void insert(const std::string& _k, T&& _v) { insert(std::make_pair(_k, std::move(_v))); } - /// Inserts a new element at the end. + /// Inserts a new key-value pair at the end (both move version). + /// @param _k The key (will be moved) + /// @param _v The value to associate with the key (will be moved) void insert(std::string&& _k, T&& _v) { insert(std::make_pair(std::move(_k), std::move(_v))); } - /// Inserts a new element at the end. + /// Inserts a new key-value pair at the end (string_view key, copy value). + /// @param _k The key as a string_view + /// @param _v The value to associate with the key void insert(const std::string_view& _k, const T& _v) { insert(std::make_pair(std::string(_k), _v)); } - /// Inserts a new element at the end. + /// Inserts a new key-value pair at the end (string_view key, move value). + /// @param _k The key as a string_view + /// @param _v The value to associate with the key (will be moved) void insert(const std::string_view& _k, T&& _v) { insert(std::make_pair(std::string(_k), std::move(_v))); } - /// Alias for insert that primarily exists for compatability with standard - /// containers. + /// Alias for insert that primarily exists for compatibility with standard containers. + /// Emplaces elements in-place at the end (move version). + /// @tparam Args Types of the arguments to forward + /// @param _args The arguments to forward to insert template void emplace(Args&&... _args) { insert(std::forward(_args)...); } - /// Alias for insert that primarily exists for compatability with standard - /// containers. + /// Alias for insert that primarily exists for compatibility with standard containers. + /// Emplaces elements in-place at the end (copy version). + /// @tparam Args Types of the arguments to forward + /// @param _args The arguments to forward to insert template void emplace(const Args&... _args) { insert(_args...); } - /// Inserts several new elements at the end. + /// Inserts several new elements at the end from an iterator range. + /// @tparam InputIt Iterator type + /// @param _first Iterator to the first element to insert + /// @param _last Iterator past the last element to insert template void insert_range(InputIt _first, InputIt _last) { for (auto it = _first; it != _last; ++it) { @@ -156,7 +210,9 @@ class Object { } } - /// Inserts several new elements at the end. + /// Inserts several new elements at the end from a range. + /// @tparam RangeType Type of the range + /// @param _range The range of elements to insert template void insert_range(RangeType _range) { for (const auto& val : _range) { @@ -165,6 +221,9 @@ class Object { } /// Returns the element signified by the key or creates a new one. + /// If the key doesn't exist, inserts a default-constructed value. + /// @param _key The key to look up or create + /// @return Reference to the value associated with the key T& operator[](const std::string& _key) { const auto i = find(_key); if (i != size()) { @@ -175,7 +234,10 @@ class Object { return data_.back().second; } - /// Returns the element signified by the key or creates a new one. + /// Returns the element signified by the key or creates a new one (move version). + /// If the key doesn't exist, inserts a default-constructed value. + /// @param _key The key to look up or create (will be moved) + /// @return Reference to the value associated with the key T& operator[](std::string&& _key) { const auto i = find(_key); if (i != size()) { @@ -186,13 +248,16 @@ class Object { return data_.back().second; } - /// Deletes all elements. + /// Deletes all elements from the object. void clear() { data_.clear(); i_ = 0; } /// Returns the element signified by the key or throws an exception. + /// @param _key The key to look up + /// @return Reference to the value associated with the key + /// @throws std::runtime_error if the key is not found T& at(const std::string& _key) { const auto i = find(_key); if (i == size()) { @@ -201,7 +266,10 @@ class Object { return data_[i].second; } - /// Returns the element signified by the key or throws an exception. + /// Returns the element signified by the key or throws an exception (const version). + /// @param _key The key to look up + /// @return Const reference to the value associated with the key + /// @throws std::runtime_error if the key is not found const T& at(const std::string& _key) const { const auto i = find(_key); if (i == size()) { @@ -211,6 +279,9 @@ class Object { } /// Returns a result wrapping the element signified by the key. + /// This is a non-throwing alternative to at(). + /// @param _key The key to look up + /// @return Result containing the value if found, or an error if not found Result get(const std::string& _key) const noexcept { const auto i = find(_key); if (i == size()) { @@ -220,6 +291,10 @@ class Object { } private: + /// Finds the index of a key in the data vector. + /// Uses a rotating search pattern starting from i_ for better cache locality. + /// @param _key The key to find + /// @return The index of the key, or size() if not found size_t find(const std::string& _key) const { for (size_t i = i_; i < size(); ++i) { if (data_[i].first == _key) { @@ -237,9 +312,10 @@ class Object { } private: + /// The underlying data storage - vector of key-value pairs DataType data_; - /// Allows faster access + /// Allows faster access by remembering the last accessed position mutable size_t i_; }; diff --git a/include/rfl/OneOf.hpp b/include/rfl/OneOf.hpp index db47ee0d..8b302cf1 100644 --- a/include/rfl/OneOf.hpp +++ b/include/rfl/OneOf.hpp @@ -11,14 +11,21 @@ namespace rfl { -/// Requires that all of the contraints C and Cs be true. +/// Requires that exactly one of the constraints C and Cs be true. template struct OneOf { + /// Validates that exactly one constraint is satisfied. + /// @tparam T The type of the value to validate + /// @param _value The value to validate + /// @return The value if exactly one constraint passes, otherwise an error template static rfl::Result validate(const T& _value) noexcept { return validate_impl(_value, {}); } + /// Converts the validator to a JSON schema type. + /// @tparam T The type being validated + /// @return A ValidationType representing one-of schema template static parsing::schema::ValidationType to_schema() { using ValidationType = parsing::schema::ValidationType; @@ -28,6 +35,9 @@ struct OneOf { } private: + /// Creates an error message from a list of errors. + /// @param _errors The list of errors from failed validations + /// @return A formatted error message indicating the validation failure static std::string make_error_message(const std::vector& _errors) { std::stringstream stream; stream << "Expected exactly 1 out of " << sizeof...(Cs) + 1 diff --git a/include/rfl/Pattern.hpp b/include/rfl/Pattern.hpp index 47a4eb74..43b42998 100644 --- a/include/rfl/Pattern.hpp +++ b/include/rfl/Pattern.hpp @@ -6,6 +6,10 @@ namespace rfl { +/// Type alias for a string that must match a compile-time regex pattern. +/// Provides a convenient way to create validated strings with pattern constraints. +/// @tparam _regex The compile-time regular expression pattern to validate against +/// @tparam _name A human-readable name for the pattern (used in error messages) template using Pattern = Validator>; diff --git a/include/rfl/PatternValidator.hpp b/include/rfl/PatternValidator.hpp index ef18ee63..6c74d709 100644 --- a/include/rfl/PatternValidator.hpp +++ b/include/rfl/PatternValidator.hpp @@ -17,11 +17,18 @@ namespace rfl { +/// Validator that checks if a string matches a compile-time regex pattern. +/// Uses the CTRE library for compile-time regular expression matching. +/// @tparam _regex The compile-time regular expression pattern +/// @tparam _name A human-readable name for the pattern (used in error messages) template struct PatternValidator { using Name = Literal<_name>; using Regex = Literal<_regex>; + /// Validates that a string matches the regex pattern. + /// @param _str The string to validate + /// @return Result containing the string if it matches, or an error if it doesn't static Result validate(const std::string& _str) noexcept { if (ctre::match{ ctll::construct_from_pointer, _regex.arr_.data()}>(_str)) { @@ -34,6 +41,9 @@ struct PatternValidator { } } + /// Converts the pattern validator to a JSON schema type. + /// @tparam T The type being validated (unused, for template compatibility) + /// @return A ValidationType representing the regex constraint template static parsing::schema::ValidationType to_schema() { using ValidationType = parsing::schema::ValidationType; diff --git a/include/rfl/Positional.hpp b/include/rfl/Positional.hpp index c877ee67..76a94f3d 100644 --- a/include/rfl/Positional.hpp +++ b/include/rfl/Positional.hpp @@ -9,75 +9,114 @@ namespace rfl { /// Marks a field as positional for CLI argument parsing. -/// For non-CLI formats (JSON, YAML, etc.), this is transparent. +/// In CLI contexts, positional fields are passed without names (e.g., "program arg1 arg2"). +/// For non-CLI formats (JSON, YAML, etc.), this wrapper is transparent and has no effect. +/// @tparam T The type of the positional field template struct Positional { /// The underlying type. using Type = T; + /// Default constructor - requires Type to be default constructible. Positional() requires std::is_default_constructible_v : value_(Type()) {} + /// Constructs from a const reference to the value. + /// @param _value The value to store Positional(const Type& _value) : value_(_value) {} + /// Constructs from an rvalue reference to the value. + /// @param _value The value to store (will be moved) Positional(Type&& _value) noexcept : value_(std::move(_value)) {} + /// Move constructor. + /// @param _field The Positional to move from Positional(Positional&& _field) noexcept = default; + /// Copy constructor. + /// @param _field The Positional to copy from Positional(const Positional& _field) = default; + /// Copy constructor from Positional with compatible type. + /// @tparam U Type compatible with T + /// @param _field The Positional to copy the value from template Positional(const Positional& _field) : value_(_field.get()) {} + /// Move constructor from Positional with compatible type. + /// @tparam U Type compatible with T + /// @param _field The Positional to move the value from template Positional(Positional&& _field) : value_(std::move(_field.value_)) {} + /// Constructs from any type convertible to Type (copy). + /// @tparam U Type convertible to T + /// @param _value The value to convert and store template requires std::is_convertible_v Positional(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 requires std::is_convertible_v Positional(U&& _value) noexcept : value_(std::forward(_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 template requires std::is_default_constructible_v Positional(const Default&) : value_(Type()) {} + /// Destructor. ~Positional() = 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 Positional 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 Positional 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 Positional template requires std::is_convertible_v auto& operator=(const U& _value) { @@ -85,7 +124,10 @@ struct Positional { 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 + /// @return Reference to this Positional template requires std::is_default_constructible_v auto& operator=(const Default&) { @@ -93,36 +135,50 @@ struct Positional { return *this; } - /// Assigns the underlying object. + /// Copy assignment operator. + /// @param _field The Positional to copy from + /// @return Reference to this Positional Positional& operator=(const Positional& _field) = default; - /// Assigns the underlying object. + /// Move assignment operator. + /// @param _field The Positional to move from + /// @return Reference to this Positional Positional& operator=(Positional&& _field) = default; - /// Assigns the underlying object. + /// Assigns from another Positional with compatible type (copy). + /// @tparam U Type compatible with T + /// @param _field The Positional to copy the value from + /// @return Reference to this Positional template auto& operator=(const Positional& _field) { value_ = _field.get(); return *this; } - /// Assigns the underlying object. + /// Assigns from another Positional with compatible type (move). + /// @tparam U Type compatible with T + /// @param _field The Positional to move the value from + /// @return Reference to this Positional template auto& operator=(Positional&& _field) { value_ = std::move(_field.value_); return *this; } - /// 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. diff --git a/include/rfl/Processors.hpp b/include/rfl/Processors.hpp index eded95dc..c693dba8 100644 --- a/include/rfl/Processors.hpp +++ b/include/rfl/Processors.hpp @@ -8,19 +8,33 @@ namespace rfl { +/// Represents a collection of processors that transform named tuples sequentially. +/// Processors are applied from left to right, each transforming the output of the previous one. template struct Processors; +/// Base case: no processors, returns the named tuple unchanged. template <> struct Processors<> { + /// Processes a named tuple (a tuple-like structure with named fields) without modification. + /// @tparam T The type of the struct being processed + /// @tparam NamedTupleType The type of the named tuple + /// @param _named_tuple The named tuple to process + /// @return The unmodified named tuple template static auto process(NamedTupleType&& _named_tuple) { return std::forward(_named_tuple); } }; +/// Recursive case: applies Head processor, then recursively applies Tail processors. template struct Processors { + /// Processes a named tuple by applying Head processor then all Tail processors. + /// @tparam T The type of the struct being processed + /// @tparam NamedTupleType The type of the named tuple + /// @param _named_tuple The named tuple to process + /// @return The transformed named tuple after all processors have been applied template static auto process(NamedTupleType&& _named_tuple) { return Processors::template process( diff --git a/include/rfl/Ref.hpp b/include/rfl/Ref.hpp index 9818a80f..296ff33c 100644 --- a/include/rfl/Ref.hpp +++ b/include/rfl/Ref.hpp @@ -8,22 +8,28 @@ namespace rfl { -/// The Ref class behaves very similarly to the shared_ptr, but unlike the -/// unique_ptr, it is 100% guaranteed to be filled at all times (unless the user -/// tries to access it after calling std::move does something else that is +/// A smart pointer wrapper that is guaranteed to always contain a valid object with shared ownership. +/// The Ref class behaves very similarly to shared_ptr, but unlike shared_ptr, +/// it is 100% guaranteed to be filled at all times (unless the user +/// tries to access it after calling std::move or does something else that is /// clearly bad practice). +/// @tparam T The type of object to contain template class Ref { public: - /// The default way of creating new references is - /// Ref::make(...) or make_ref(...). + /// The default way of creating new references is Ref::make(...) or make_ref(...). + /// Constructs a new Ref with the given arguments forwarded to T's constructor. + /// @tparam Args Types of constructor arguments + /// @param _args Arguments to forward to T's constructor + /// @return A new Ref containing the constructed object template static Ref make(Args&&... _args) { return Ref(std::make_shared(std::forward(_args)...)); } - /// You can generate them from shared_ptrs as well, in which case it will - /// return an Error, if the shared_ptr is not set. + /// Creates a Ref from a shared_ptr (move version), returns an Error if the shared_ptr is null. + /// @param _ptr The shared_ptr to convert to a Ref + /// @return Result containing the Ref or an error if _ptr is nullptr static Result> make(std::shared_ptr&& _ptr) { if (!_ptr) { return error("std::shared_ptr was a nullptr."); @@ -31,8 +37,9 @@ class Ref { return Ref(std::move(_ptr)); } - /// You can generate them from shared_ptrs as well, in which case it will - /// return an Error, if the shared_ptr is not set. + /// Creates a Ref from a shared_ptr (copy version), returns an Error if the shared_ptr is null. + /// @param _ptr The shared_ptr to convert to a Ref + /// @return Result containing the Ref or an error if _ptr is nullptr static Result> make(const std::shared_ptr& _ptr) { if (!_ptr) { return error("std::shared_ptr was a nullptr."); @@ -40,85 +47,133 @@ class Ref { return Ref(_ptr); } + /// Default constructor - creates a Ref containing a default-constructed T. Ref() : ptr_(std::make_shared()) {} + /// Copy constructor. + /// @param _other The Ref to copy from Ref(const Ref& _other) = default; + /// Move constructor. + /// @param _other The Ref to move from Ref(Ref&& _other) = default; + /// Copy constructor from a Ref with a different but compatible type. + /// @tparam U Type convertible to T + /// @param _other The Ref to copy from template Ref(const Ref& _other) : ptr_(_other.ptr()) {} + /// Move constructor from a Ref with a different but compatible type. + /// @tparam U Type convertible to T + /// @param _other The Ref to move from template Ref(Ref&& _other) noexcept : ptr_(std::forward>(_other.ptr())) {} + /// Destructor. ~Ref() = default; - /// Returns a pointer to the underlying object + /// Returns a pointer to the underlying object. + /// @return Raw pointer to the contained object T* get() const { return ptr_.get(); } - /// Returns the underlying object. + /// Dereference operator - returns the underlying object. + /// @return Reference to the contained object T& operator*() { return *ptr_; } - /// Returns the underlying object. + /// Dereference operator (const) - returns the underlying object. + /// @return Const reference to the contained object T& operator*() const { return *ptr_; } - /// Returns the underlying object. + /// Arrow operator - provides access to the underlying object's members. + /// @return Pointer to the contained object T* operator->() { return ptr_.get(); } - /// Returns the underlying object. + /// Arrow operator (const) - provides access to the underlying object's members. + /// @return Const pointer to the contained object T* operator->() const { return ptr_.get(); } - /// Returns the underlying shared_ptr + /// Returns the underlying shared_ptr. + /// @return Reference to the internal shared_ptr std::shared_ptr& ptr() { return ptr_; } - /// Returns the underlying shared_ptr + /// Returns the underlying shared_ptr (const). + /// @return Const reference to the internal shared_ptr const std::shared_ptr& ptr() const { return ptr_; } - /// Copy assignment operator. + /// Copy assignment operator from Ref with different type. + /// @tparam U Type convertible to T + /// @param _other The Ref to copy from + /// @return Reference to this Ref template Ref& operator=(const Ref& _other) { ptr_ = _other.ptr(); return *this; } - /// Move assignment operator + /// Move assignment operator from Ref with different type. + /// @tparam U Type convertible to T + /// @param _other The Ref to move from + /// @return Reference to this Ref template Ref& operator=(Ref&& _other) noexcept { ptr_ = std::forward>(_other.ptr()); return *this; } - /// Move assignment operator + /// Move assignment operator. + /// @param _other The Ref to move from + /// @return Reference to this Ref Ref& operator=(Ref&& _other) noexcept = default; - /// Copy assignment operator + /// Copy assignment operator. + /// @param _other The Ref to copy from + /// @return Reference to this Ref Ref& operator=(const Ref& _other) = default; private: - /// Only make is allowed to use this constructor. + /// Only make() is allowed to use this constructor (move version). + /// @param _ptr The shared_ptr to wrap explicit Ref(std::shared_ptr&& _ptr) : ptr_(std::move(_ptr)) {} - /// Only make is allowed to use this constructor. + /// Only make() is allowed to use this constructor (copy version). + /// @param _ptr The shared_ptr to wrap explicit Ref(const std::shared_ptr& _ptr) : ptr_(_ptr) {} private: - /// The underlying shared_ptr_ + /// The underlying shared_ptr. std::shared_ptr ptr_; }; -/// Generates a new Ref. +/// Generates a new Ref by forwarding arguments to T's constructor. +/// @tparam T The type to wrap in a Ref +/// @tparam Args Types of constructor arguments +/// @param _args Arguments to forward to T's constructor +/// @return A new Ref template auto make_ref(Args&&... _args) { return Ref::make(std::forward(_args)...); } +/// Three-way comparison operator for Refs. +/// @tparam T1 Type of the first Ref +/// @tparam T2 Type of the second Ref +/// @param _t1 The first Ref to compare +/// @param _t2 The second Ref to compare +/// @return The ordering relationship between the underlying pointers template inline auto operator<=>(const Ref& _t1, const Ref& _t2) { return _t1.ptr() <=> _t2.ptr(); } +/// Stream insertion operator for Ref. +/// @tparam CharT Character type +/// @tparam Traits Character traits +/// @tparam T Type contained in the Ref +/// @param _os The output stream +/// @param _b The Ref to output +/// @return The output stream template inline std::basic_ostream& operator<<( std::basic_ostream& _os, const Ref& _b) { @@ -129,13 +184,24 @@ inline std::basic_ostream& operator<<( } // namespace rfl namespace std { + +/// Specialization of std::hash for Ref. +/// Allows Ref to be used in unordered containers. +/// @tparam T The type contained in the Ref template struct hash> { + /// Computes hash of the Ref by hashing its underlying shared_ptr. + /// @param _r The Ref to hash + /// @return The hash value size_t operator()(const rfl::Ref& _r) const { return std::hash>{}(_r.ptr()); } }; +/// Specialization of std::swap for Ref. +/// @tparam T The type contained in the Ref +/// @param _r1 The first Ref to swap +/// @param _r2 The second Ref to swap template inline void swap(rfl::Ref& _r1, rfl::Ref& _r2) { return swap(_r1.ptr(), _r2.ptr()); diff --git a/include/rfl/Rename.hpp b/include/rfl/Rename.hpp index c3bd79d9..5074feee 100644 --- a/include/rfl/Rename.hpp +++ b/include/rfl/Rename.hpp @@ -13,85 +13,128 @@ namespace rfl { -/// Used to assign a new name to a field, which is different from the name -/// inside the struct. +/// Used to assign a new name to a field for serialization/deserialization. +/// This allows the field name in the struct to differ from the name used in serialized formats. +/// For example, a C++ field 'firstName' can be serialized as 'first_name' in JSON. +/// @tparam _name The compile-time string literal name to use in serialized formats +/// @tparam T The type of the value stored in the field template struct Rename { /// The underlying type. using Type = T; - /// The name of the field. + /// The name of the field as a Literal type. using Name = rfl::Literal<_name>; + /// Default constructor - creates a Rename with a default-constructed value. Rename() : value_(Type()) {} + /// Constructs from a const reference to the value. + /// @param _value The value to store Rename(const Type& _value) : value_(_value) {} + /// Constructs from an rvalue reference to the value. + /// @param _value The value to store (will be moved) Rename(Type&& _value) noexcept : value_(std::move(_value)) {} + /// Move constructor. + /// @param _field The Rename to move from Rename(Rename<_name, T>&& _field) noexcept = default; + /// Copy constructor. + /// @param _field The Rename to copy from Rename(const Rename<_name, Type>& _field) = default; + /// Copy constructor from Rename with compatible type. + /// @tparam U Type compatible with T + /// @param _field The Rename to copy the value from template Rename(const Rename<_name, U>& _field) : value_(_field.get()) {} + /// Move constructor from Rename with compatible type. + /// @tparam U Type compatible with T + /// @param _field The Rename to move the value from template Rename(Rename<_name, U>&& _field) : value_(_field.get()) {} + /// Constructs from any type convertible to Type (copy). + /// @tparam U Type convertible to T + /// @param _value The value to convert and store template requires std::is_convertible_v Rename(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 requires std::is_convertible_v Rename(U&& _value) noexcept : value_(std::forward(_value)) {} + /// Constructs from a Rename with compatible type. + /// @tparam U Type convertible to T + /// @param _field The Rename to copy the value from template requires std::is_convertible_v Rename(const Rename<_name, U>& _field) : value_(_field.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 template requires std::is_default_constructible_v Rename(const Default&) : value_(Type()) {} + /// Destructor. ~Rename() = default; - /// The name of the field, for internal use. + /// The name of the field as a compile-time string literal, for internal use. constexpr static const internal::StringLiteral name_ = _name; - /// 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 Rename 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 Rename 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 Rename template requires std::is_convertible_v auto& operator=(const U& _value) { @@ -99,7 +142,10 @@ struct Rename { 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 + /// @return Reference to this Rename template requires std::is_default_constructible_v auto& operator=(const Default&) { @@ -107,36 +153,50 @@ struct Rename { return *this; } - /// Assigns the underlying object. + /// Copy assignment operator. + /// @param _field The Rename to copy from + /// @return Reference to this Rename Rename<_name, T>& operator=(const Rename<_name, T>& _field) = default; - /// Assigns the underlying object. + /// Move assignment operator. + /// @param _field The Rename to move from + /// @return Reference to this Rename Rename<_name, T>& operator=(Rename<_name, T>&& _field) = default; - /// Assigns the underlying object. + /// Assigns from another Rename with compatible type (copy). + /// @tparam U Type compatible with T + /// @param _field The Rename to copy the value from + /// @return Reference to this Rename template auto& operator=(const Rename<_name, U>& _field) { value_ = _field.get(); return *this; } - /// Assigns the underlying object. + /// Assigns from another Rename with compatible type (move). + /// @tparam U Type compatible with T + /// @param _field The Rename to move the value from + /// @return Reference to this Rename template auto& operator=(Rename<_name, U>&& _field) { value_ = std::forward(_field.value_); return *this; } - /// 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. diff --git a/include/rfl/Result.hpp b/include/rfl/Result.hpp index d0351720..adc52505 100644 --- a/include/rfl/Result.hpp +++ b/include/rfl/Result.hpp @@ -14,21 +14,40 @@ namespace rfl { -/// Defines the error class to be returned when something went wrong +/// Defines the error class to be returned when something went wrong. +/// This is used throughout reflect-cpp for error handling. class Error { public: + /// Default constructor - creates an empty error. Error() = default; + /// Constructs an error with a message (copy). + /// @param _what The error message describing what went wrong Error(const std::string& _what) : what_(_what) {} + + /// Constructs an error with a message (move). + /// @param _what The error message describing what went wrong (will be moved) Error(std::string&& _what) : what_(std::move(_what)) {} + /// Destructor. ~Error() = default; + /// Copy constructor. + /// @param e The error to copy from Error(const Error& e) = default; + + /// Move constructor. + /// @param e The error to move from Error(Error&& e) noexcept = default; + /// Copy assignment operator. + /// @param _other The error to copy from + /// @return Reference to this error Error& operator=(const Error& _other) = default; + /// Move assignment operator. + /// @param _other The error to move from + /// @return Reference to this error Error& operator=(Error&& _other) noexcept = default; /// Returns the error message, equivalent to .what() in std::exception. diff --git a/include/rfl/Size.hpp b/include/rfl/Size.hpp index 72f13333..3b6845e7 100644 --- a/include/rfl/Size.hpp +++ b/include/rfl/Size.hpp @@ -9,8 +9,14 @@ namespace rfl { +/// Validates the size of a container or string using a validator V. +/// The validator V is applied to the size() method of the container. template struct Size { + /// Validates that the size of the container satisfies the validator V. + /// @tparam T The type of the container to validate + /// @param _t The container whose size will be validated + /// @return The container if validation passes, otherwise an error template static rfl::Result validate(const T& _t) { const auto to_t = [&](const auto&) { return _t; }; @@ -21,6 +27,9 @@ struct Size { embellish_error); } + /// Converts the size validator to a JSON schema type. + /// @tparam T The type of the container being validated + /// @return A ValidationType representing size constraints template static parsing::schema::ValidationType to_schema() { using ValidationType = parsing::schema::ValidationType; diff --git a/include/rfl/Skip.hpp b/include/rfl/Skip.hpp index 9adc8b60..587772a4 100644 --- a/include/rfl/Skip.hpp +++ b/include/rfl/Skip.hpp @@ -5,12 +5,22 @@ namespace rfl { +/// Type alias for skipping a field in both serialization and deserialization. +/// When a struct field is wrapped in Skip, it will be completely ignored during +/// reading and writing of serialized formats. +/// @tparam T The type of the field to skip template using Skip = internal::Skip; +/// Type alias for skipping a field only during serialization (writing). +/// The field will be read from serialized data but not written to it. +/// @tparam T The type of the field to skip during serialization template using SkipSerialization = internal::Skip; +/// Type alias for skipping a field only during deserialization (reading). +/// The field will be written to serialized data but not read from it. +/// @tparam T The type of the field to skip during deserialization template using SkipDeserialization = internal::Skip; diff --git a/include/rfl/SnakeCaseToCamelCase.hpp b/include/rfl/SnakeCaseToCamelCase.hpp index 17746b29..d073b0b4 100644 --- a/include/rfl/SnakeCaseToCamelCase.hpp +++ b/include/rfl/SnakeCaseToCamelCase.hpp @@ -10,6 +10,10 @@ namespace rfl { struct SnakeCaseToCamelCase { public: /// Replaces all instances of snake_case field names with camelCase. + /// A named tuple is a tuple-like structure where each element has a name/key. + /// @tparam StructType The type of the struct being processed + /// @param _named_tuple The named tuple containing the struct's fields + /// @return A new named tuple with field names converted to camelCase template static auto process(const auto& _named_tuple) { return _named_tuple.transform([](const FieldType& _f) { @@ -23,7 +27,10 @@ struct SnakeCaseToCamelCase { } private: - /// Applies the logic to a single field. + /// Applies the snake_case to camelCase transformation to a single field. + /// @tparam FieldType The type of the field being transformed + /// @param _f The field to transform + /// @return A new field with the transformed name and the same value template static auto handle_one_field(const FieldType& _f) { using NewFieldType = diff --git a/include/rfl/SnakeCaseToKebabCase.hpp b/include/rfl/SnakeCaseToKebabCase.hpp index 2350e8f8..4b9d09a6 100644 --- a/include/rfl/SnakeCaseToKebabCase.hpp +++ b/include/rfl/SnakeCaseToKebabCase.hpp @@ -10,6 +10,10 @@ namespace rfl { struct SnakeCaseToKebabCase { public: /// Replaces all instances of snake_case field names with kebab-case. + /// A named tuple is a tuple-like structure where each element has a name/key. + /// @tparam StructType The type of the struct being processed + /// @param _named_tuple The named tuple containing the struct's fields + /// @return A new named tuple with field names converted to kebab-case template static auto process(const auto& _named_tuple) { return _named_tuple.transform([](const FieldType& _f) { @@ -25,6 +29,10 @@ struct SnakeCaseToKebabCase { } private: + /// Applies the snake_case to kebab-case transformation to a single field. + /// @tparam FieldType The type of the field being transformed + /// @param _f The field to transform + /// @return A new field with the transformed name and the same value template static auto handle_one_field(const FieldType& _f) { using NewFieldType = diff --git a/include/rfl/SnakeCaseToPascalCase.hpp b/include/rfl/SnakeCaseToPascalCase.hpp index b53b714f..f10361da 100644 --- a/include/rfl/SnakeCaseToPascalCase.hpp +++ b/include/rfl/SnakeCaseToPascalCase.hpp @@ -10,6 +10,10 @@ namespace rfl { struct SnakeCaseToPascalCase { public: /// Replaces all instances of snake_case field names with PascalCase. + /// A named tuple is a tuple-like structure where each element has a name/key. + /// @tparam StructType The type of the struct being processed + /// @param _named_tuple The named tuple containing the struct's fields + /// @return A new named tuple with field names converted to PascalCase template static auto process(const auto& _named_tuple) { const auto handle_one = [](const FieldType& _f) { @@ -24,7 +28,10 @@ struct SnakeCaseToPascalCase { } private: - /// Applies the logic to a single field. + /// Applies the snake_case to PascalCase transformation to a single field. + /// @tparam FieldType The type of the field being transformed + /// @param _f The field to transform + /// @return A new field with the transformed name and the same value template static auto handle_one_field(const FieldType& _f) { using NewFieldType = diff --git a/include/rfl/TaggedUnion.hpp b/include/rfl/TaggedUnion.hpp index e4e7d869..52b08914 100644 --- a/include/rfl/TaggedUnion.hpp +++ b/include/rfl/TaggedUnion.hpp @@ -9,7 +9,9 @@ namespace rfl { -// https://serde.rs/enum-representations.html +/// A tagged union (also known as discriminated union) that serializes with an explicit discriminator field. +/// The discriminator field is used to identify which variant alternative is active. +/// See: https://serde.rs/enum-representations.html template struct TaggedUnion { static constexpr internal::StringLiteral discriminator_ = _discriminator; @@ -17,27 +19,43 @@ struct TaggedUnion { /// The type of the underlying variant. using VariantType = rfl::Variant; + /// Default constructor. TaggedUnion() = default; + /// Constructs from a variant (copy). + /// @param _variant The variant to wrap TaggedUnion(const VariantType& _variant) : variant_(_variant) {} + /// Constructs from a variant (move). + /// @param _variant The variant to wrap (will be moved) TaggedUnion(VariantType&& _variant) noexcept : variant_(std::move(_variant)) {} + /// Copy constructor. + /// @param _tagged_union The tagged union to copy from TaggedUnion(const TaggedUnion<_discriminator, Ts...>& _tagged_union) = default; + /// Move constructor. + /// @param _tagged_union The tagged union to move from TaggedUnion(TaggedUnion<_discriminator, Ts...>&& _tagged_union) noexcept = default; + /// Constructs from any type convertible to the underlying variant (copy). + /// @tparam T The type to convert from + /// @param _t The value to convert and wrap template requires std::is_convertible_v TaggedUnion(const T& _t) : variant_(_t) {} + /// Constructs from any type convertible to the underlying variant (move). + /// @tparam T The type to convert from + /// @param _t The value to convert and wrap (will be moved) template requires std::is_convertible_v TaggedUnion(T&& _t) noexcept : variant_(std::forward(_t)) {} + /// Destructor. ~TaggedUnion() = default; /// Assigns the underlying object. @@ -82,14 +100,22 @@ struct TaggedUnion { /// Returns the underlying variant. const VariantType& variant() const { return variant_; } - /// Applies function _f to all underlying alternatives. + /// Applies function _f to all underlying alternatives (mutable version). + /// This is the visitor pattern - the function will be called with the currently active variant alternative. + /// @tparam F The type of the visitor function + /// @param _f The function to apply to the active alternative + /// @return The result of applying _f to the active alternative template auto visit(F&& _f) -> decltype(std::declval().visit(std::declval())) { return variant_.visit(std::forward(_f)); } - /// Applies function _f to all underlying alternatives. + /// Applies function _f to all underlying alternatives (const version). + /// This is the visitor pattern - the function will be called with the currently active variant alternative. + /// @tparam F The type of the visitor function + /// @param _f The function to apply to the active alternative + /// @return The result of applying _f to the active alternative template auto visit(F&& _f) const -> decltype(std::declval().visit(std::declval())) { @@ -101,23 +127,36 @@ struct TaggedUnion { VariantType variant_; }; +/// Concept to check if a type is based on TaggedUnion. template concept TaggedUnionBased = requires(T t) { []( TaggedUnion<_discriminator, Args...> const&) {}(t); }; +/// Helper to extract possible tag values from a TaggedUnion. template struct PossibleTags; +/// Specialization for TaggedUnion - extracts all possible discriminator tags. +/// @tparam _discriminator The name of the discriminator field +/// @tparam Ts The types of the alternatives in the tagged union template struct PossibleTags> { using Type = define_literal_t...>; }; +/// Type alias for extracting possible tags from a TaggedUnion type. template using possible_tags_t = typename PossibleTags::Type; +/// Equality operator for TaggedUnion. +/// Two tagged unions are equal if they hold the same alternative and the values are equal. +/// @tparam _discriminator The name of the discriminator field +/// @tparam Ts The types of the alternatives in the tagged union +/// @param lhs The left-hand side tagged union +/// @param rhs The right-hand side tagged union +/// @return true if both tagged unions hold the same alternative with equal values template bool operator==(const TaggedUnion<_discriminator, Ts...>& lhs, const TaggedUnion<_discriminator, Ts...>& rhs) { diff --git a/include/rfl/Timestamp.hpp b/include/rfl/Timestamp.hpp index fe78e85f..a43c07ef 100644 --- a/include/rfl/Timestamp.hpp +++ b/include/rfl/Timestamp.hpp @@ -13,7 +13,11 @@ namespace rfl { -/// For serializing and deserializing time stamps. +/// For serializing and deserializing timestamps with a specific format. +/// This class wraps a std::tm structure and provides parsing/formatting +/// using a compile-time format string (strptime/strftime format). +/// Useful for handling dates and times in various formats (ISO8601, RFC3339, custom formats). +/// @tparam _format The compile-time format string (e.g., "%Y-%m-%d %H:%M:%S") template class Timestamp { constexpr static const internal::StringLiteral format_ = _format; @@ -23,8 +27,12 @@ class Timestamp { using ReflectionType = std::string; + /// Default constructor - initializes with zero time. Timestamp() : tm_(std::tm{}) {} + /// Constructs a timestamp from a C-string matching the format. + /// @param _str The string to parse + /// @throws std::runtime_error if the string doesn't match the format Timestamp(const char* _str) : tm_(std::tm{}) { const auto r = strptime(_str, _format.str().c_str(), &tm_); if (r == NULL) { @@ -34,10 +42,17 @@ class Timestamp { } } + /// Constructs a timestamp from a std::string matching the format. + /// @param _str The string to parse + /// @throws std::runtime_error if the string doesn't match the format Timestamp(const std::string& _str) : Timestamp(_str.c_str()) {} + /// Constructs a timestamp from a std::tm structure. + /// @param _tm The time structure to wrap Timestamp(const std::tm& _tm) : tm_(_tm) {} + /// Constructs a timestamp from a time_t value. + /// @param _t The time_t value representing seconds since epoch Timestamp(const time_t _t) : tm_(std::tm{}) { auto t = _t; #if defined(_MSC_VER) || defined(__MINGW32__) @@ -47,10 +62,13 @@ class Timestamp { #endif } + /// Destructor. ~Timestamp() = default; - /// Returns a result containing the timestamp when successful or an Error - /// otherwise. + /// Returns a result containing the timestamp when successful or an Error otherwise. + /// This is an alternative to the throwing constructor for error handling without exceptions. + /// @param _str The string to parse in the format specified by the template parameter + /// @return Result containing the Timestamp if parsing succeeded, or an error otherwise static Result from_string(const char* _str) noexcept { try { return Timestamp(_str); @@ -59,14 +77,18 @@ class Timestamp { } } - /// Returns a result containing the timestamp when successful or an Error - /// otherwise. + /// Returns a result containing the timestamp when successful or an Error otherwise. + /// This is an alternative to the throwing constructor for error handling without exceptions. + /// @param _str The string to parse in the format specified by the template parameter + /// @return Result containing the Timestamp if parsing succeeded, or an error otherwise static Result from_string(const std::string& _str) { return from_string(_str.c_str()); } - /// Returns a result containing the timestamp when successful or an Error - /// otherwise. + /// Generic factory method for creating a Timestamp from a string. + /// Returns a result containing the timestamp when successful or an Error otherwise. + /// @param _str The string to parse (can be const char* or std::string) + /// @return Result containing the Timestamp if parsing succeeded, or an error otherwise static Result make(const auto& _str) noexcept { return from_string(_str); } @@ -95,23 +117,31 @@ class Timestamp { /// Returns the underlying object. const std::tm& value() const noexcept { return tm_; } - /// Necessary for the serialization to work. + /// Returns the underlying std::tm structure for reflection/serialization. + /// Formats the timestamp according to the format string and returns it as a string. + /// This method is called by the serialization framework. + /// @return The formatted timestamp string ReflectionType reflection() const { char outstr[200]; strftime(outstr, 200, format_.str().c_str(), &tm_); return std::string(outstr); } - /// Expresses the underlying timestamp as a string. + /// Expresses the underlying timestamp as a formatted string. + /// Uses the format specified in the template parameter. + /// @return The formatted timestamp string std::string str() const { return reflection(); } - /// Trivial accessor to the underlying time stamp. + /// Accessor to the underlying std::tm structure. + /// @return Reference to the internal std::tm std::tm& tm() { return tm_; } - /// Trivial (const) accessor to the underlying time stamp. + /// Accessor to the underlying std::tm structure (const). + /// @return Const reference to the internal std::tm const std::tm& tm() const { return tm_; } - /// Returns a UTC time represented by a time_t type. + /// Converts the timestamp to a time_t value (seconds since Unix epoch in UTC). + /// @return The time_t representation of this timestamp time_t to_time_t() const { auto tm = tm_; #if defined(_MSC_VER) || defined(__MINGW32__) diff --git a/include/rfl/Tuple.hpp b/include/rfl/Tuple.hpp index fe0a2699..c08a4c03 100644 --- a/include/rfl/Tuple.hpp +++ b/include/rfl/Tuple.hpp @@ -16,12 +16,15 @@ namespace rfl { template class Tuple; +/// Specialization for empty Tuple. template <> class Tuple<> { public: + /// Default constructor for empty Tuple. Tuple() {} }; +/// Tuple class template for arbitrary types. template class Tuple { static constexpr size_t size_ = sizeof...(Types); @@ -36,33 +39,50 @@ class Tuple { using DataType = std::array; public: + /// Constructs a Tuple by copying from the provided arguments. + /// @param _t The values to copy into the Tuple. Tuple(const Types&... _t) { copy_from_types(_t..., seq_); } + /// Constructs a Tuple by moving from the provided arguments. + /// @param _t The values to move into the Tuple. Tuple(Types&&... _t) noexcept { move_from_types(std::move(_t)..., seq_); } + /// Default constructor. Initializes each element with its default + /// constructor. Tuple() : Tuple(Types()...) {} + /// Copy constructor. Copies all elements from another Tuple. + /// @param _other The Tuple to copy from. Tuple(const Tuple& _other) { copy_from_other(_other, seq_); } + /// Move constructor. Moves all elements from another Tuple. + /// @param _other The Tuple to move from. Tuple(Tuple&& _other) noexcept { move_from_other(std::move(_other), seq_); } + /// Destructor. Destroys all elements if necessary. ~Tuple() { destroy_if_necessary(seq_); } - /// Gets an element by index. + /// Gets an element by index (mutable). + /// @tparam _index The index of the element to access. + /// @return Reference to the element at the specified index. template constexpr auto& get() { using Type = internal::nth_element_t<_index, Types...>; return *internal::ptr_cast(data_.data() + pos<_index>()); } - /// Gets an element by index. + /// Gets an element by index (const). + /// @tparam _index The index of the element to access. + /// @return Const reference to the element at the specified index. template constexpr const auto& get() const { using Type = internal::nth_element_t<_index, Types...>; return *internal::ptr_cast(data_.data() + pos<_index>()); } - /// Assigns the underlying object. + /// Copy assignment operator. Assigns from another Tuple by copy. + /// @param _other The Tuple to copy from. + /// @return Reference to this Tuple. Tuple& operator=(const Tuple& _other) { if (this == &_other) { return *this; @@ -73,7 +93,9 @@ class Tuple { return *this; } - /// Assigns the underlying object. + /// Move assignment operator. Assigns from another Tuple by move. + /// @param _other The Tuple to move from. + /// @return Reference to this Tuple. Tuple& operator=(Tuple&& _other) noexcept { if (this == &_other) { return *this; @@ -83,7 +105,10 @@ class Tuple { return *this; } - /// Equality operator. + /// Equality operator. Compares two Tuples for equality. + /// @tparam OtherTypes The types of the other Tuple. + /// @param _other The Tuple to compare with. + /// @return True if all elements are equal, false otherwise. template bool operator==(const Tuple& _other) const noexcept { static_assert(sizeof...(Types) == sizeof...(OtherTypes), @@ -96,7 +121,10 @@ class Tuple { }(std::make_integer_sequence()); } - /// Three-way comparison operator. + /// Three-way comparison operator. Compares two Tuples lexicographically. + /// @tparam OtherTypes The types of the other Tuple. + /// @param _other The Tuple to compare with. + /// @return The comparison result according to the common comparison category. template auto operator<=>(const Tuple& _other) const noexcept { static_assert(sizeof...(Types) == sizeof...(OtherTypes), @@ -108,8 +136,8 @@ class Tuple { auto ordering = OrderingType::equivalent; const auto compare = [&](std::integral_constant) { - ordering = static_cast( - this->get<_i>() <=> _other.template get<_i>()); + ordering = static_cast(this->get<_i>() <=> + _other.template get<_i>()); return ordering != 0; }; @@ -120,6 +148,9 @@ class Tuple { } private: + /// Copies all elements from another Tuple. + /// @param _other The Tuple to copy from. + /// @param seq_ Integer sequence for element indices. template void copy_from_other(const Tuple& _other, std::integer_sequence) { @@ -132,6 +163,9 @@ class Tuple { (copy_one(_other, std::integral_constant{}), ...); } + /// Copies all elements from provided arguments. + /// @param _types The values to copy. + /// @param seq_ Integer sequence for element indices. template void copy_from_types(const Types&... _types, std::integer_sequence) { @@ -143,6 +177,8 @@ class Tuple { (copy_one(_types, std::integral_constant{}), ...); } + /// Destroys all elements if they are destructible. + /// @param seq_ Integer sequence for element indices. template void destroy_if_necessary(std::integer_sequence) { const auto destroy_one = [](auto& _t) { @@ -154,6 +190,9 @@ class Tuple { (destroy_one(get<_is>()), ...); } + /// Moves all elements from another Tuple. + /// @param _other The Tuple to move from. + /// @param seq_ Integer sequence for element indices. template void move_from_other(Tuple&& _other, std::integer_sequence) { const auto move_one = [this](auto&& _other, @@ -165,6 +204,9 @@ class Tuple { (move_one(_other, std::integral_constant{}), ...); } + /// Moves all elements from provided arguments. + /// @param _types The values to move. + /// @param seq_ Integer sequence for element indices. template void move_from_types(Types&&... _types, std::integer_sequence) { const auto move_one = [this](auto&& _t, @@ -175,6 +217,9 @@ class Tuple { (move_one(std::move(_types), std::integral_constant{}), ...); } + /// Returns the byte offset of the element at index _i. + /// @tparam _i The index of the element. + /// @return The byte offset of the element. template static consteval unsigned int pos() { return std::get<_i>(positions_); @@ -185,65 +230,105 @@ class Tuple { alignas(Types...) DataType data_; }; -/// Gets an element by index. +/// Gets an element by index from an rfl::Tuple (mutable). +/// @tparam _index The index of the element. +/// @tparam Types The types in the Tuple. +/// @param _tup The Tuple to access. +/// @return Reference to the element at the specified index. template constexpr auto& get(rfl::Tuple& _tup) { return _tup.template get<_index>(); } -/// Gets an element by index. +/// Gets an element by index from an rfl::Tuple (const). +/// @tparam _index The index of the element. +/// @tparam Types The types in the Tuple. +/// @param _tup The Tuple to access. +/// @return Const reference to the element at the specified index. template constexpr const auto& get(const rfl::Tuple& _tup) { return _tup.template get<_index>(); } -/// Gets an element by index. +/// Gets an element by index from a std::tuple (mutable). +/// @tparam _index The index of the element. +/// @tparam Types The types in the tuple. +/// @param _tup The tuple to access. +/// @return Reference to the element at the specified index. template constexpr auto& get(std::tuple& _tup) { return std::get<_index>(_tup); } -/// Gets an element by index. +/// Gets an element by index from a std::tuple (const). +/// @tparam _index The index of the element. +/// @tparam Types The types in the tuple. +/// @param _tup The tuple to access. +/// @return Const reference to the element at the specified index. template constexpr const auto& get(const std::tuple& _tup) { return std::get<_index>(_tup); } +/// Creates an rfl::Tuple from the provided arguments, decaying their types. +/// @tparam Types The types of the arguments. +/// @param _args The arguments to store in the Tuple. +/// @return An rfl::Tuple containing the arguments. template auto make_tuple(Types&&... _args) { return rfl::Tuple...>(std::forward(_args)...); } +/// Provides the type of the N-th element of a Tuple. +/// @tparam N The index of the element. +/// @tparam T The Tuple type. template struct tuple_element; +/// Specialization for rfl::Tuple. +/// @tparam N The index of the element. +/// @tparam Ts The types in the Tuple. template struct tuple_element> { using type = internal::nth_element_t; }; +/// Specialization for std::tuple. +/// @tparam N The index of the element. +/// @tparam Ts The types in the tuple. template struct tuple_element> { using type = internal::nth_element_t; }; +/// Alias for the type of the N-th element of a Tuple. +/// @tparam N The index of the element. +/// @tparam T The Tuple type. template using tuple_element_t = typename rfl::tuple_element>::type; +/// Provides the size (number of elements) of a Tuple. +/// @tparam T The Tuple type. template struct tuple_size; +/// Specialization for rfl::Tuple. +/// @tparam Ts The types in the Tuple. template struct tuple_size> { static constexpr auto value = sizeof...(Ts); }; +/// Specialization for std::tuple. +/// @tparam Ts The types in the tuple. template struct tuple_size> { static constexpr auto value = sizeof...(Ts); }; +/// Alias for the size (number of elements) of a Tuple. +/// @tparam T The Tuple type. template inline constexpr auto tuple_size_v = rfl::tuple_size>::value; @@ -252,13 +337,21 @@ inline constexpr auto tuple_size_v = namespace std { -/// Gets an element by index. +/// Gets an element by index from an rfl::Tuple (mutable). +/// @tparam _index The index of the element. +/// @tparam Types The types in the Tuple. +/// @param _tup The Tuple to access. +/// @return Reference to the element at the specified index. template constexpr auto& get(rfl::Tuple& _tup) { return _tup.template get<_index>(); } -/// Gets an element by index. +/// Gets an element by index from an rfl::Tuple (const). +/// @tparam _index The index of the element. +/// @tparam Types The types in the Tuple. +/// @param _tup The Tuple to access. +/// @return Const reference to the element at the specified index. template constexpr const auto& get(const rfl::Tuple& _tup) { return _tup.template get<_index>(); diff --git a/include/rfl/Validator.hpp b/include/rfl/Validator.hpp index ffb5d08e..7ced2daa 100644 --- a/include/rfl/Validator.hpp +++ b/include/rfl/Validator.hpp @@ -13,6 +13,12 @@ namespace rfl { +/// A wrapper that validates a value against one or more validation rules. +/// The value is checked on construction and assignment, and will throw if +/// validation fails. +/// @tparam T The underlying type to validate +/// @tparam V The primary validator type +/// @tparam Vs Additional validator types (combined with AllOf) template requires internal::HasValidation, T> struct Validator { @@ -21,7 +27,10 @@ struct Validator { using ValidationType = std::conditional_t>; - /// Exception-free validation. + /// Exception-free validation from a value. + /// @param _value The value to validate + /// @return Result containing a Validator if validation succeeds, or an error + /// if it fails static Result from_value(const T& _value) noexcept { try { return Validator(_value); @@ -30,56 +39,95 @@ struct Validator { } } + /// Default constructor - validates a default-constructed T. + /// @throws std::exception if validation of the default value fails Validator() : value_(ValidationType::validate(T()).value()) {} + /// Move constructor. + /// @param _other The validator to move from Validator(Validator&& _other) noexcept = default; + /// Copy constructor. + /// @param _other The validator to copy from Validator(const Validator& _other) = default; + /// Constructs from an rvalue of T (validates the value). + /// @param _value The value to validate and wrap + /// @throws std::exception if validation fails Validator(T&& _value) : value_(ValidationType::validate(_value).value()) {} + /// Constructs from a const reference to T (validates the value). + /// @param _value The value to validate and wrap + /// @throws std::exception if validation fails Validator(const T& _value) : value_(ValidationType::validate(_value).value()) {} + /// Constructs from a type convertible to T (validates after conversion). + /// @tparam U Type convertible to T + /// @param _value The value to convert, validate, and wrap + /// @throws std::exception if validation fails template requires std::is_convertible_v Validator(U&& _value) : value_(ValidationType::validate(T(std::forward(_value))).value()) {} + /// Constructs from a const reference to a type convertible to T. + /// @tparam U Type convertible to T + /// @param _value The value to convert, validate, and wrap + /// @throws std::exception if validation fails template requires std::is_convertible_v Validator(const U& _value) : value_(ValidationType::validate(T(_value)).value()) {} + /// Destructor. ~Validator() = default; - /// Assigns the underlying object. + /// Assigns a new value (validates before assigning). + /// @param _value The value to validate and assign + /// @return Reference to this validator + /// @throws std::exception if validation fails auto& operator=(const T& _value) { value_ = ValidationType::validate(_value).value(); return *this; } - /// Assigns the underlying object. + /// Assigns a new value (move version, validates before assigning). + /// @param _value The value to validate and assign + /// @return Reference to this validator + /// @throws std::exception if validation fails auto& operator=(T&& _value) { value_ = ValidationType::validate(std::forward(_value)).value(); return *this; } - /// Assigns the underlying object. + /// Copy assignment operator. + /// @param _other The validator to copy from + /// @return Reference to this validator Validator& operator=(const Validator& _other) = default; - /// Assigns the underlying object. + /// Move assignment operator. + /// @param _other The validator to move from + /// @return Reference to this validator Validator& operator=(Validator&& _other) noexcept = default; - /// Assigns the underlying object. + /// Assigns from a convertible type (validates after conversion). + /// @tparam U Type convertible to T + /// @param _value The value to convert, validate, and assign + /// @return Reference to this validator + /// @throws std::exception if validation fails template requires std::is_convertible_v - auto& operator=(U&& _value) noexcept { + auto& operator=(U&& _value) { value_ = ValidationType::validate(T(std::forward(_value))).value(); return *this; } - /// Assigns the underlying object. + /// Assigns from a const reference to a convertible type. + /// @tparam U Type convertible to T + /// @param _value The value to convert, validate, and assign + /// @return Reference to this validator + /// @throws std::exception if validation fails template requires std::is_convertible_v auto& operator=(const U& _value) { @@ -87,7 +135,9 @@ struct Validator { return *this; } - /// Equality operator other Validators. + /// Equality operator for comparing with other Validators. + /// @param _other The other validator to compare with + /// @return true if the underlying values are equal bool operator==(const Validator& _other) const { return value() == _other.value(); } @@ -124,12 +174,27 @@ struct Validator { T value_; }; +/// Three-way comparison operator for validators with the same validation rules. +/// @tparam T The underlying type +/// @tparam V The primary validator type +/// @tparam Vs Additional validator types +/// @param _v1 The first validator to compare +/// @param _v2 The second validator to compare +/// @return The ordering relationship between the underlying values template inline auto operator<=>(const Validator& _v1, const Validator& _v2) { return _v1.value() <=> _v2.value(); } +/// Three-way comparison operator for comparing a validator with a raw value. +/// @tparam T The underlying type +/// @tparam V The primary validator type +/// @tparam Vs Additional validator types +/// @param _v The validator to compare +/// @param _t The raw value to compare with +/// @return The ordering relationship between the validator's value and the raw +/// value template inline auto operator<=>(const Validator& _v, const T& _t) { return _v.value() <=> _t; @@ -139,8 +204,13 @@ inline auto operator<=>(const Validator& _v, const T& _t) { namespace std { +/// Specialization of std::hash for Validator. +/// Allows Validator to be used in unordered containers. template struct hash> { + /// Computes hash of the validator by hashing its underlying value. + /// @param _v The validator to hash + /// @return The hash value size_t operator()(const rfl::Validator& _v) const { return hash()(_v.value()); } diff --git a/include/rfl/Variant.hpp b/include/rfl/Variant.hpp index 6b92f947..018edca7 100644 --- a/include/rfl/Variant.hpp +++ b/include/rfl/Variant.hpp @@ -17,7 +17,6 @@ #include "internal/variant/result_t.hpp" namespace rfl { - template class Variant { static constexpr auto max_size_wrapper_ = @@ -44,34 +43,61 @@ class Variant { struct TypeWrapper {}; public: + /// @brief Default-constructs the Variant, initializing it with the first + /// alternative type. + /// @details The first alternative type is default-constructed and stored in + /// the variant. Variant() : index_(IndexType()), data_(DataType()) { using FirstAlternative = internal::nth_element_t<0, AlternativeTypes...>; move_from_type(FirstAlternative()); } + /// @brief Copy-constructs the Variant from another Variant. + /// @param _other The Variant to copy from. + /// @details The contained value is copied from the other Variant, preserving + /// the alternative type. Variant(const Variant& _other) : index_(IndexType()), data_(DataType()) { copy_from_other(_other); } + /// @brief Move-constructs the Variant from another Variant. + /// @param _other The Variant to move from. + /// @details The contained value is moved from the other Variant, preserving + /// the alternative type. Variant(Variant&& _other) noexcept : index_(IndexType()), data_(DataType()) { move_from_other(std::move(_other)); } + /// @brief Constructs the Variant from a value of an alternative type (copy). + /// @tparam T The type of the value to store. + /// @param _t The value to copy into the Variant. + /// @details Only enabled if T is one of the alternative types. template requires internal::variant::is_alternative_type_v Variant(const T& _t) : index_(IndexType()), data_(DataType()) { copy_from_type(_t); } + /// @brief Constructs the Variant from a value of an alternative type (move). + /// @tparam T The type of the value to store. + /// @param _t The value to move into the Variant. + /// @details Only enabled if T is one of the alternative types. template requires internal::variant::is_alternative_type_v Variant(T&& _t) noexcept : index_(IndexType()), data_(DataType()) { move_from_type(std::forward(_t)); } + /// @brief Destroys the contained value if necessary. + /// @details Calls the destructor of the contained alternative type if it is + /// destructible. ~Variant() { destroy_if_necessary(); } - /// Emplaces a new element into the variant. + /// @brief Emplaces a new element of type T into the variant. + /// @tparam T The type to emplace. + /// @tparam Args The argument types for T's constructor. + /// @param _args The arguments to forward to T's constructor. + /// @return Reference to the newly emplaced value. template constexpr T& emplace(Args&&... _args) { auto t = T{std::forward(_args)...}; @@ -80,17 +106,26 @@ class Variant { return *internal::ptr_cast(data_.data()); } - /// Emplaces a new element into the variant. + /// @brief Emplaces a new element of the N-th alternative type into the + /// variant. + /// @tparam _i The index of the alternative type. + /// @tparam Args The argument types for the constructor. + /// @param _args The arguments to forward to the constructor. + /// @return Reference to the newly emplaced value. template constexpr auto& emplace(Args&&... _args) { using T = internal::nth_element_t<_i, AlternativeTypes...>; return emplace(std::move(_args)...); } - /// Returns the index of the element currently held. + /// @brief Returns the index of the currently held alternative. + /// @return The index of the contained alternative type. constexpr int index() const noexcept { return index_; } - /// Assigns the underlying object. + /// @brief Assigns a value of an alternative type to the Variant (copy). + /// @tparam T The type of the value to assign. + /// @param _t The value to assign. + /// @return Reference to this Variant. template requires internal::variant::is_alternative_type_v Variant& operator=(const T& _t) { @@ -100,7 +135,10 @@ class Variant { return *this; } - /// Assigns the underlying object. + /// @brief Assigns a value of an alternative type to the Variant (move). + /// @tparam T The type of the value to assign. + /// @param _t The value to assign. + /// @return Reference to this Variant. template requires internal::variant::is_alternative_type_v Variant& operator=(T&& _t) noexcept { @@ -109,7 +147,9 @@ class Variant { return *this; } - /// Assigns the underlying object. + /// @brief Copy-assigns from another Variant. + /// @param _other The Variant to copy from. + /// @return Reference to this Variant. Variant& operator=(const Variant& _other) { if (this == &_other) { return *this; @@ -120,7 +160,9 @@ class Variant { return *this; } - /// Assigns the underlying object. + /// @brief Move-assigns from another Variant. + /// @param _other The Variant to move from. + /// @return Reference to this Variant. Variant& operator=(Variant&& _other) noexcept { if (this == &_other) { return *this; @@ -130,7 +172,10 @@ class Variant { return *this; } - /// Swaps the content with the other variant. + /// @brief Swaps the contents of this Variant with another. + /// @param _other The Variant to swap with. + /// @details Exchanges the contained values and types between the two + /// Variants. void swap(Variant& _other) noexcept { if (this == &_other) { return; @@ -140,6 +185,10 @@ class Variant { _other = std::move(temp); } + /// @brief Visits the contained value with a visitor function. + /// @tparam F The visitor type. + /// @param _f The visitor function or functor. + /// @return The result of the visitor, or void. template result_t visit(F&& _f) { using ResultType = result_t; @@ -160,6 +209,11 @@ class Variant { } } + /// @brief Visits the contained value with a visitor function (const + /// overload). + /// @tparam F The visitor type. + /// @param _f The visitor function or functor. + /// @return The result of the visitor, or void. template result_t visit(F&& _f) const { using ResultType = result_t; @@ -181,11 +235,19 @@ class Variant { } private: + /// @brief Copies the value from another Variant. + /// @param _other The Variant to copy from. void copy_from_other(const Variant& _other) { const auto copy_one = [this](const auto& _t) { this->copy_from_type(_t); }; _other.visit(copy_one); } + /// @brief Copies a value of type T from another type. + /// @tparam T The type to copy from. + /// @param _t The value to copy. + /// @details Tries to copy the value from T to each alternative type, and if + /// successful, stores it in the Variant. Only the first successful copy is + /// performed. template void copy_from_other_type(const T& _t) { bool set = false; @@ -201,6 +263,9 @@ class Variant { (copy_one(_t, TypeWrapper{}), ...); } + /// @brief Copies a value of type T into the Variant. + /// @tparam T The type to copy from. + /// @param _t The value to copy. template void copy_from_type(const T& _t) noexcept { using CurrentType = std::remove_cvref_t; @@ -210,6 +275,7 @@ class Variant { new (data_.data()) CurrentType(_t); } + /// @brief Destroys the contained value if it is destructible. void destroy_if_necessary() { const auto destroy_one = [](auto& _t) { using T = std::remove_cvref_t; @@ -220,11 +286,15 @@ class Variant { visit(destroy_one); } + /// @brief Helper for visiting without result (non-const). + /// @tparam F The visitor type. + /// @tparam _is Index sequence. + /// @param _f The visitor. + /// @param _visited Pointer to visitation flag. template void do_visit_no_result(F& _f, bool* _visited, std::integer_sequence) { - auto visit_one = [this](F& _f, bool* _visited, - Index<_i>) { + auto visit_one = [this](F& _f, bool* _visited, Index<_i>) { if (!*_visited && index_ == _i) { _f(get_alternative<_i>()); *_visited = true; @@ -233,11 +303,15 @@ class Variant { (visit_one(_f, _visited, Index<_is>{}), ...); } + /// @brief Helper for visiting without result (const). + /// @tparam F The visitor type. + /// @tparam _is Index sequence. + /// @param _f The visitor. + /// @param _visited Pointer to visitation flag. template void do_visit_no_result(F& _f, bool* _visited, std::integer_sequence) const { - auto visit_one = [this](F& _f, bool* _visited, - Index<_i>) { + auto visit_one = [this](F& _f, bool* _visited, Index<_i>) { if (!*_visited && index_ == _i) { _f(get_alternative<_i>()); *_visited = true; @@ -246,6 +320,11 @@ class Variant { (visit_one(_f, _visited, Index<_is>{}), ...); } + /// @brief Helper for visiting without result (non-const, const visitor). + /// @tparam F The visitor type. + /// @tparam _is Index sequence. + /// @param _f The visitor. + /// @param _visited Pointer to visitation flag. template void do_visit_no_result(const F& _f, bool* _visited, std::integer_sequence) { @@ -259,6 +338,11 @@ class Variant { (visit_one(_f, _visited, Index<_is>{}), ...); } + /// @brief Helper for visiting without result (const, const visitor). + /// @tparam F The visitor type. + /// @tparam _is Index sequence. + /// @param _f The visitor. + /// @param _visited Pointer to visitation flag. template void do_visit_no_result(const F& _f, bool* _visited, std::integer_sequence) const { @@ -272,12 +356,17 @@ class Variant { (visit_one(_f, _visited, Index<_is>{}), ...); } + /// @brief Helper for visiting with result (non-const). + /// @tparam F The visitor type. + /// @tparam ResultType The result type. + /// @tparam _is Index sequence. + /// @param _f The visitor. + /// @param _result Pointer to optional result. template void do_visit_with_result(F& _f, std::optional* _result, std::integer_sequence) { - auto visit_one = [this](F& _f, - std::optional* _result, - Index<_i>) { + auto visit_one = [this]( + F& _f, std::optional* _result, Index<_i>) { if (!*_result && index_ == _i) { _result->emplace(_f(get_alternative<_i>())); } @@ -285,12 +374,17 @@ class Variant { (visit_one(_f, _result, Index<_is>{}), ...); } + /// @brief Helper for visiting with result (const). + /// @tparam F The visitor type. + /// @tparam ResultType The result type. + /// @tparam _is Index sequence. + /// @param _f The visitor. + /// @param _result Pointer to optional result. template void do_visit_with_result(F& _f, std::optional* _result, std::integer_sequence) const { - auto visit_one = [this](F& _f, - std::optional* _result, - Index<_i>) { + auto visit_one = [this]( + F& _f, std::optional* _result, Index<_i>) { if (!*_result && index_ == _i) { _result->emplace(_f(get_alternative<_i>())); } @@ -298,6 +392,12 @@ class Variant { (visit_one(_f, _result, Index<_is>{}), ...); } + /// @brief Helper for visiting with result (non-const, const visitor). + /// @tparam F The visitor type. + /// @tparam ResultType The result type. + /// @tparam _is Index sequence. + /// @param _f The visitor. + /// @param _result Pointer to optional result. template void do_visit_with_result(const F& _f, std::optional* _result, std::integer_sequence) { @@ -311,6 +411,12 @@ class Variant { (visit_one(_f, _result, Index<_is>{}), ...); } + /// @brief Helper for visiting with result (const, const visitor). + /// @tparam F The visitor type. + /// @tparam ResultType The result type. + /// @tparam _is Index sequence. + /// @param _f The visitor. + /// @param _result Pointer to optional result. template void do_visit_with_result(const F& _f, std::optional* _result, std::integer_sequence) const { @@ -324,11 +430,17 @@ class Variant { (visit_one(_f, _result, Index<_is>{}), ...); } + /// @brief Helper for visiting with reference result (non-const). + /// @tparam F The visitor type. + /// @tparam ResultType The result type. + /// @tparam _is Index sequence. + /// @param _f The visitor. + /// @param _result Pointer to result pointer. template void do_visit_with_reference(F& _f, ResultType** _result, std::integer_sequence) { - const auto visit_one = [this]( - F& _f, ResultType** _result, Index<_i>) { + const auto visit_one = [this](F& _f, ResultType** _result, + Index<_i>) { if (!*_result && index_ == _i) { *_result = &_f(get_alternative<_i>()); } @@ -336,11 +448,17 @@ class Variant { (visit_one(_f, _result, Index<_is>{}), ...); } + /// @brief Helper for visiting with reference result (const). + /// @tparam F The visitor type. + /// @tparam ResultType The result type. + /// @tparam _is Index sequence. + /// @param _f The visitor. + /// @param _result Pointer to result pointer. template void do_visit_with_reference(F& _f, ResultType** _result, std::integer_sequence) const { - const auto visit_one = [this]( - F& _f, ResultType** _result, Index<_i>) { + const auto visit_one = [this](F& _f, ResultType** _result, + Index<_i>) { if (!*_result && index_ == _i) { *_result = &_f(get_alternative<_i>()); } @@ -348,6 +466,13 @@ class Variant { (visit_one(_f, _result, Index<_is>{}), ...); } + /// @brief Helper for visiting with reference result (non-const, const + /// visitor). + /// @tparam F The visitor type. + /// @tparam ResultType The result type. + /// @tparam _is Index sequence. + /// @param _f The visitor. + /// @param _result Pointer to result pointer. template void do_visit_with_reference(const F& _f, ResultType** _result, std::integer_sequence) { @@ -360,6 +485,12 @@ class Variant { (visit_one(_f, _result, Index<_is>{}), ...); } + /// @brief Helper for visiting with reference result (const, const visitor). + /// @tparam F The visitor type. + /// @tparam ResultType The result type. + /// @tparam _is Index sequence. + /// @param _f The visitor. + /// @param _result Pointer to result pointer. template void do_visit_with_reference(const F& _f, ResultType** _result, std::integer_sequence) const { @@ -372,18 +503,28 @@ class Variant { (visit_one(_f, _result, Index<_is>{}), ...); } + /// @brief Returns a reference to the contained value of the _i-th alternative + /// type. + /// @tparam _i The index of the alternative type. + /// @return Reference to the contained value. template auto& get_alternative() noexcept { using CurrentType = internal::nth_element_t<_i, AlternativeTypes...>; return *internal::ptr_cast(data_.data()); } + /// @brief Returns a const reference to the contained value of the _i-th + /// alternative type. + /// @tparam _i The index of the alternative type. + /// @return Const reference to the contained value. template const auto& get_alternative() const noexcept { using CurrentType = internal::nth_element_t<_i, AlternativeTypes...>; return *internal::ptr_cast(data_.data()); } + /// @brief Moves the value from another Variant into this Variant. + /// @param _other The Variant to move from. void move_from_other(Variant&& _other) noexcept { const auto move_one = [this](auto&& _t) { this->move_from_type(std::forward>(_t)); @@ -391,6 +532,9 @@ class Variant { std::move(_other).visit(move_one); } + /// @brief Moves a value of type T into the Variant. + /// @tparam T The type to move from. + /// @param _t The value to move. template void move_from_type(T&& _t) noexcept { using CurrentType = std::remove_cvref_t; @@ -409,11 +553,19 @@ class Variant { alignas(AlternativeTypes...) DataType data_; }; +/// @brief Concept to check if a type is Variant-based. +/// @tparam V The type to check. template concept VariantBased = requires(std::decay_t v) { [](Variant const&) {}(v); }; +/// @brief Returns a pointer to the contained value if it is of type T, +/// otherwise nullptr. +/// @tparam T The type to check for. +/// @tparam Types The alternative types. +/// @param _v Pointer to the Variant. +/// @return Pointer to the contained value or nullptr. template constexpr T* get_if(Variant* _v) noexcept { const auto get = [](auto& _v) -> T* { @@ -427,6 +579,12 @@ constexpr T* get_if(Variant* _v) noexcept { return _v->visit(get); } +/// @brief Returns a const pointer to the contained value if it is of type T, +/// otherwise nullptr. +/// @tparam T The type to check for. +/// @tparam Types The alternative types. +/// @param _v Pointer to the Variant. +/// @return Const pointer to the contained value or nullptr. template constexpr const T* get_if(const Variant* _v) noexcept { const auto get = [](const auto& _v) -> const T* { @@ -440,18 +598,37 @@ constexpr const T* get_if(const Variant* _v) noexcept { return _v->visit(get); } +/// @brief Returns a pointer to the contained value if it is of the N-th +/// alternative type, otherwise nullptr. +/// @tparam _i The index of the alternative type. +/// @tparam Types The alternative types. +/// @param _v Pointer to the Variant. +/// @return Pointer to the contained value or nullptr. template constexpr auto* get_if(Variant* _v) noexcept { using T = internal::nth_element_t<_i, Types...>; return get_if(_v); } +/// @brief Returns a const pointer to the contained value if it is of the N-th +/// alternative type, otherwise nullptr. +/// @tparam _i The index of the alternative type. +/// @tparam Types The alternative types. +/// @param _v Pointer to the Variant. +/// @return Const pointer to the contained value or nullptr. template constexpr auto* get_if(const Variant* _v) noexcept { using T = internal::nth_element_t<_i, Types...>; return get_if(_v); } +/// @brief Returns a reference to the contained value if it is of type T, throws +/// otherwise. +/// @tparam T The type to get. +/// @tparam Types The alternative types. +/// @param _v Reference to the Variant. +/// @return Reference to the contained value. +/// @throws std::runtime_error if the contained value is not of type T. template constexpr T& get(Variant& _v) { auto ptr = get_if(&_v); @@ -461,6 +638,13 @@ constexpr T& get(Variant& _v) { return *ptr; } +/// @brief Returns an rvalue reference to the contained value if it is of type +/// T, throws otherwise. +/// @tparam T The type to get. +/// @tparam Types The alternative types. +/// @param _v Rvalue reference to the Variant. +/// @return Rvalue reference to the contained value. +/// @throws std::runtime_error if the contained value is not of type T. template constexpr T&& get(Variant&& _v) { auto ptr = get_if(&_v); @@ -470,6 +654,13 @@ constexpr T&& get(Variant&& _v) { return std::move(*ptr); } +/// @brief Returns a const reference to the contained value if it is of type T, +/// throws otherwise. +/// @tparam T The type to get. +/// @tparam Types The alternative types. +/// @param _v Const reference to the Variant. +/// @return Const reference to the contained value. +/// @throws std::runtime_error if the contained value is not of type T. template constexpr const T& get(const Variant& _v) { auto ptr = get_if(&_v); @@ -479,6 +670,13 @@ constexpr const T& get(const Variant& _v) { return *ptr; } +/// @brief Returns a reference to the contained value if it is of the N-th +/// alternative type, throws otherwise. +/// @tparam _i The index of the alternative type. +/// @tparam Types The alternative types. +/// @param _v Reference to the Variant. +/// @return Reference to the contained value. +/// @throws std::runtime_error if the contained value is not of the N-th type. template constexpr auto& get(Variant& _v) { auto ptr = get_if<_i>(&_v); @@ -488,6 +686,13 @@ constexpr auto& get(Variant& _v) { return *ptr; } +/// @brief Returns an rvalue reference to the contained value if it is of the +/// N-th alternative type, throws otherwise. +/// @tparam _i The index of the alternative type. +/// @tparam Types The alternative types. +/// @param _v Rvalue reference to the Variant. +/// @return Rvalue reference to the contained value. +/// @throws std::runtime_error if the contained value is not of the N-th type. template constexpr auto&& get(Variant&& _v) { auto ptr = get_if<_i>(&_v); @@ -497,6 +702,13 @@ constexpr auto&& get(Variant&& _v) { return std::move(*ptr); } +/// @brief Returns a const reference to the contained value if it is of the N-th +/// alternative type, throws otherwise. +/// @tparam _i The index of the alternative type. +/// @tparam Types The alternative types. +/// @param _v Const reference to the Variant. +/// @return Const reference to the contained value. +/// @throws std::runtime_error if the contained value is not of the N-th type. template constexpr const auto& get(const Variant& _v) { auto ptr = get_if<_i>(&_v); @@ -506,6 +718,11 @@ constexpr const auto& get(const Variant& _v) { return *ptr; } +/// @brief Checks if the Variant currently holds a value of type T. +/// @tparam T The type to check for. +/// @tparam Types The alternative types. +/// @param _v Const reference to the Variant. +/// @return True if the Variant holds T, false otherwise. template constexpr bool holds_alternative(const Variant& _v) noexcept { constexpr auto ix = internal::element_index, @@ -514,6 +731,9 @@ constexpr bool holds_alternative(const Variant& _v) noexcept { return ix == _v.index(); } +/// @brief Provides the type of the N-th alternative in a Variant. +/// @tparam N The index of the alternative. +/// @tparam T The Variant type. template struct variant_alternative; @@ -522,10 +742,15 @@ struct variant_alternative> { using type = internal::nth_element_t; }; +/// @brief Alias for the type of the N-th alternative in a Variant. +/// @tparam N The index of the alternative. +/// @tparam VariantType The Variant type. template using variant_alternative_t = typename variant_alternative>::type; +/// @brief Provides the number of alternatives in a Variant. +/// @tparam T The Variant type. template struct variant_size; @@ -533,6 +758,8 @@ template struct variant_size> : std::integral_constant {}; +/// @brief Alias for the number of alternatives in a Variant. +/// @tparam VariantType The Variant type. template constexpr size_t variant_size_v = variant_size>(); @@ -540,6 +767,10 @@ constexpr size_t variant_size_v = } // namespace rfl namespace std { +/// @brief Swaps two Variants. +/// @tparam Types The alternative types. +/// @param _lhs The first Variant. +/// @param _rhs The second Variant. template void swap(rfl::Variant& _lhs, rfl::Variant& _rhs) noexcept { _lhs.swap(_rhs); diff --git a/include/rfl/always_false.hpp b/include/rfl/always_false.hpp index 78041ea2..f8dadcbe 100644 --- a/include/rfl/always_false.hpp +++ b/include/rfl/always_false.hpp @@ -3,7 +3,11 @@ namespace rfl { -/// To be used inside visitor patterns +/// Helper for static_assert with dependent types in templates. +/// This is useful in constexpr if branches to ensure compilation fails +/// when an unexpected branch is taken. Always evaluates to false but +/// depends on the template parameter so compilation is delayed. +/// @tparam T The template parameter (used to make the value dependent) template inline constexpr bool always_false_v = false; diff --git a/include/rfl/apply.hpp b/include/rfl/apply.hpp index 6f2f4963..fbda8263 100644 --- a/include/rfl/apply.hpp +++ b/include/rfl/apply.hpp @@ -8,18 +8,30 @@ namespace rfl { +/// Applies a function to a tuple (const reference version). +/// @param _f The function to apply +/// @param _tup The tuple to apply the function to +/// @return The result of applying the function to the tuple elements template auto apply(F&& _f, const rfl::Tuple& _tup) { return internal::tuple::apply( _f, _tup, std::make_integer_sequence()); } +/// Applies a function to a tuple (mutable reference version). +/// @param _f The function to apply +/// @param _tup The tuple to apply the function to +/// @return The result of applying the function to the tuple elements template auto apply(F&& _f, rfl::Tuple& _tup) { return internal::tuple::apply( _f, _tup, std::make_integer_sequence()); } +/// Applies a function to a tuple (rvalue reference version). +/// @param _f The function to apply +/// @param _tup The tuple to apply the function to +/// @return The result of applying the function to the tuple elements template auto apply(F&& _f, rfl::Tuple&& _tup) { return internal::tuple::apply( diff --git a/include/rfl/avro/Reader.hpp b/include/rfl/avro/Reader.hpp index 71cff92b..747bb0d0 100644 --- a/include/rfl/avro/Reader.hpp +++ b/include/rfl/avro/Reader.hpp @@ -48,10 +48,19 @@ struct Reader { static constexpr bool has_custom_constructor = (requires(InputVarType var) { T::from_avro_obj(var); }); + /// Checks if the given Avro value is empty (null type). + /// @param _var The Avro value to check + /// @return true if the value is of type AVRO_NULL, false otherwise bool is_empty(const InputVarType& _var) const noexcept { return avro_value_get_type(_var.val_) == AVRO_NULL; } + /// Converts an Avro value to a basic C++ type. + /// Supports strings, byte containers, booleans, floating-point numbers, + /// integers, and literal types (enums). + /// @tparam T The target C++ type to convert to + /// @param _var The Avro value to convert + /// @return A Result containing the converted value or an error template rfl::Result to_basic_type(const InputVarType& _var) const noexcept { const auto type = avro_value_get_type(_var.val_); @@ -145,6 +154,9 @@ struct Reader { } } + /// Converts an Avro value to an array type. + /// @param _var The Avro value to convert + /// @return A Result containing an InputArrayType or an error if the value is not an array rfl::Result to_array( const InputVarType& _var) const noexcept { if (avro_value_get_type(_var.val_) != AVRO_ARRAY) { @@ -153,6 +165,10 @@ struct Reader { return InputArrayType{_var.val_}; } + /// Converts an Avro value to an object (record) type. + /// In Avro, objects are represented as records with named fields. + /// @param _var The Avro value to convert + /// @return A Result containing an InputObjectType or an error if the value is not a record rfl::Result to_object( const InputVarType& _var) const noexcept { const auto type = avro_value_get_type(_var.val_); @@ -162,6 +178,10 @@ struct Reader { return InputObjectType{_var.val_}; } + /// Converts an Avro value to a map type. + /// Avro maps are key-value containers where keys are strings. + /// @param _var The Avro value to convert + /// @return A Result containing an InputMapType or an error if the value is not a map rfl::Result to_map(const InputVarType& _var) const noexcept { const auto type = avro_value_get_type(_var.val_); if (type != AVRO_MAP) { @@ -170,6 +190,10 @@ struct Reader { return InputMapType{_var.val_}; } + /// Converts an Avro value to a union type. + /// Avro unions allow a value to be one of several types. + /// @param _var The Avro value to convert + /// @return A Result containing an InputUnionType or an error if the value is not a union rfl::Result to_union( const InputVarType& _var) const noexcept { const auto type = avro_value_get_type(_var.val_); @@ -179,6 +203,11 @@ struct Reader { return InputUnionType{_var.val_}; } + /// Reads all elements from an Avro array using the provided array reader. + /// @tparam ArrayReader The type of reader that processes individual array elements + /// @param _array_reader The reader object that processes each element + /// @param _arr The Avro array to read from + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_array(const ArrayReader& _array_reader, const InputArrayType& _arr) const noexcept { @@ -203,6 +232,11 @@ struct Reader { return std::nullopt; } + /// Reads all key-value pairs from an Avro map using the provided map reader. + /// @tparam MapReader The type of reader that processes individual map entries + /// @param _map_reader The reader object that processes each key-value pair + /// @param _map The Avro map to read from + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_map(const MapReader& _map_reader, const InputMapType& _map) const noexcept { @@ -225,6 +259,12 @@ struct Reader { return std::nullopt; } + /// Reads all fields from an Avro record (object) using the provided object reader. + /// Fields are accessed by their index in the schema definition. + /// @tparam ObjectReader The type of reader that processes individual object fields + /// @param _object_reader The reader object that processes each field + /// @param _obj The Avro record to read from + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_object(const ObjectReader& _object_reader, const InputObjectType& _obj) const noexcept { @@ -246,6 +286,12 @@ struct Reader { return std::nullopt; } + /// Reads an Avro union value and converts it to the appropriate variant type. + /// Determines which branch of the union is active and reads that value. + /// @tparam VariantType The C++ variant type to construct + /// @tparam UnionReaderType The type of reader that handles union alternatives + /// @param _union The Avro union to read from + /// @return A Result containing the variant or an error template rfl::Result read_union( const InputUnionType& _union) const noexcept { @@ -263,6 +309,11 @@ struct Reader { InputVarType{&value}); } + /// Uses a custom constructor to create an object from an Avro value. + /// The type T must provide a static method T::from_avro_obj(InputVarType). + /// @tparam T The type to construct + /// @param _var The Avro value to construct from + /// @return A Result containing the constructed object or an error template rfl::Result use_custom_constructor( const InputVarType& _var) const noexcept { diff --git a/include/rfl/avro/Writer.hpp b/include/rfl/avro/Writer.hpp index 6a6f1528..3c22c973 100644 --- a/include/rfl/avro/Writer.hpp +++ b/include/rfl/avro/Writer.hpp @@ -45,18 +45,35 @@ class RFL_API Writer { using OutputUnionType = AVROOutputUnion; using OutputVarType = AVROOutputVar; + /// Constructs a Writer with a root Avro value. + /// @param _root Pointer to the root avro_value_t that will be written to Writer(avro_value_t* _root); ~Writer(); + /// Creates an array as the root element of the Avro document. + /// @param _size The number of elements in the array + /// @return An OutputArrayType representing the array OutputArrayType array_as_root(const size_t _size) const; + /// Creates a map as the root element of the Avro document. + /// Avro maps are key-value containers where keys are strings. + /// @param _size The number of entries in the map + /// @return An OutputMapType representing the map OutputMapType map_as_root(const size_t _size) const; + /// Creates an object (record) as the root element of the Avro document. + /// @param _size The number of fields in the object + /// @return An OutputObjectType representing the object OutputObjectType object_as_root(const size_t _size) const; + /// Creates a null value as the root element of the Avro document. + /// @return An OutputVarType representing the null value OutputVarType null_as_root() const; + /// Creates a union as the root element of the Avro document. + /// Avro unions allow a value to be one of several types. + /// @return An OutputUnionType representing the union OutputUnionType union_as_root() const; template @@ -65,67 +82,154 @@ class RFL_API Writer { return OutputVarType{*root_}; } + /// Adds a nested array to an existing array. + /// @param _size The number of elements in the new array + /// @param _parent Pointer to the parent array + /// @return An OutputArrayType representing the new array OutputArrayType add_array_to_array(const size_t _size, OutputArrayType* _parent) const; + /// Adds an array to a map with the specified key. + /// @param _name The key name for the array in the map + /// @param _size The number of elements in the array + /// @param _parent Pointer to the parent map + /// @return An OutputArrayType representing the new array OutputArrayType add_array_to_map(const std::string_view& _name, const size_t _size, OutputMapType* _parent) const; + /// Adds an array to an object (record) field. + /// @param _name The field name for the array + /// @param _size The number of elements in the array + /// @param _parent Pointer to the parent object + /// @return An OutputArrayType representing the new array OutputArrayType add_array_to_object(const std::string_view& _name, const size_t _size, OutputObjectType* _parent) const; + /// Adds an array to a specific branch of a union. + /// @param _index The index of the union branch to use + /// @param _size The number of elements in the array + /// @param _parent Pointer to the parent union + /// @return An OutputArrayType representing the new array OutputArrayType add_array_to_union(const size_t _index, const size_t _size, OutputUnionType* _parent) const; + /// Adds a nested map to an existing array. + /// @param _size The number of entries in the new map + /// @param _parent Pointer to the parent array + /// @return An OutputMapType representing the new map OutputMapType add_map_to_array(const size_t _size, OutputArrayType* _parent) const; + /// Adds a map to another map with the specified key. + /// @param _name The key name for the map in the parent map + /// @param _size The number of entries in the new map + /// @param _parent Pointer to the parent map + /// @return An OutputMapType representing the new map OutputMapType add_map_to_map(const std::string_view& _name, const size_t _size, OutputMapType* _parent) const; + /// Adds a map to an object (record) field. + /// @param _name The field name for the map + /// @param _size The number of entries in the map + /// @param _parent Pointer to the parent object + /// @return An OutputMapType representing the new map OutputMapType add_map_to_object(const std::string_view& _name, const size_t _size, OutputObjectType* _parent) const; + /// Adds a map to a specific branch of a union. + /// @param _index The index of the union branch to use + /// @param _size The number of entries in the map + /// @param _parent Pointer to the parent union + /// @return An OutputMapType representing the new map OutputMapType add_map_to_union(const size_t _index, const size_t _size, OutputUnionType* _parent) const; + /// Adds a nested object (record) to an existing array. + /// @param _size The number of fields in the new object + /// @param _parent Pointer to the parent array + /// @return An OutputObjectType representing the new object OutputObjectType add_object_to_array(const size_t _size, OutputArrayType* _parent) const; + /// Adds an object to a map with the specified key. + /// @param _name The key name for the object in the map + /// @param _size The number of fields in the object + /// @param _parent Pointer to the parent map + /// @return An OutputObjectType representing the new object OutputObjectType add_object_to_map(const std::string_view& _name, const size_t _size, OutputMapType* _parent) const; + /// Adds an object to another object's field. + /// @param _name The field name for the new object + /// @param _size The number of fields in the new object + /// @param _parent Pointer to the parent object + /// @return An OutputObjectType representing the new object OutputObjectType add_object_to_object(const std::string_view& _name, const size_t _size, OutputObjectType* _parent) const; + /// Adds an object to a specific branch of a union. + /// @param _index The index of the union branch to use + /// @param _size The number of fields in the object + /// @param _parent Pointer to the parent union + /// @return An OutputObjectType representing the new object OutputObjectType add_object_to_union(const size_t _index, const size_t _size, OutputUnionType* _parent) const; + /// Adds a union to an existing array. + /// @param _parent Pointer to the parent array + /// @return An OutputUnionType representing the new union OutputUnionType add_union_to_array(OutputArrayType* _parent) const; + /// Adds a union to a map with the specified key. + /// @param _name The key name for the union in the map + /// @param _parent Pointer to the parent map + /// @return An OutputUnionType representing the new union OutputUnionType add_union_to_map(const std::string_view& _name, OutputMapType* _parent) const; + /// Adds a union to an object (record) field. + /// @param _name The field name for the union + /// @param _parent Pointer to the parent object + /// @return An OutputUnionType representing the new union OutputUnionType add_union_to_object(const std::string_view& _name, OutputObjectType* _parent) const; + /// Adds a union to a specific branch of another union. + /// @param _index The index of the parent union's branch to use + /// @param _parent Pointer to the parent union + /// @return An OutputUnionType representing the new union OutputUnionType add_union_to_union(const size_t _index, OutputUnionType* _parent) const; + /// Adds a null value to an array. + /// @param _parent Pointer to the parent array + /// @return An OutputVarType representing the null value OutputVarType add_null_to_array(OutputArrayType* _parent) const; + /// Adds a null value to a map with the specified key. + /// @param _name The key name for the null value + /// @param _parent Pointer to the parent map + /// @return An OutputVarType representing the null value OutputVarType add_null_to_map(const std::string_view& _name, OutputMapType* _parent) const; + /// Adds a null value to an object (record) field. + /// @param _name The field name for the null value + /// @param _parent Pointer to the parent object + /// @return An OutputVarType representing the null value OutputVarType add_null_to_object(const std::string_view& _name, OutputObjectType* _parent) const; + /// Adds a null value to a specific branch of a union. + /// @param _index The index of the union branch to use + /// @param _parent Pointer to the parent union + /// @return An OutputVarType representing the null value OutputVarType add_null_to_union(const size_t _index, OutputUnionType* _parent) const; @@ -194,10 +298,19 @@ class RFL_API Writer { return OutputVarType{new_value}; } + /// Finalizes an array after all elements have been added. + /// This is a no-op for Avro but required by the Writer interface. + /// @param _arr Pointer to the array to finalize (unused) void end_array(OutputArrayType* /*_arr*/) const noexcept {} + /// Finalizes a map after all entries have been added. + /// This is a no-op for Avro but required by the Writer interface. + /// @param _obj Pointer to the map to finalize (unused) void end_map(OutputMapType* /*_obj*/) const noexcept {} + /// Finalizes an object after all fields have been added. + /// This is a no-op for Avro but required by the Writer interface. + /// @param _obj Pointer to the object to finalize (unused) void end_object(OutputObjectType* /*_obj*/) const noexcept {} private: diff --git a/include/rfl/avro/load.hpp b/include/rfl/avro/load.hpp index 8c0857e4..0b4b5bda 100644 --- a/include/rfl/avro/load.hpp +++ b/include/rfl/avro/load.hpp @@ -9,6 +9,12 @@ namespace rfl { namespace avro { +/// Loads and parses an Avro object from a file. +/// Reads the file as binary data and deserializes it using Avro. +/// @tparam T The type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _fname The path to the file to load +/// @return A Result containing the deserialized object or an error template Result load(const std::string& _fname) { const auto read_bytes = [](const auto& _bytes) { diff --git a/include/rfl/avro/read.hpp b/include/rfl/avro/read.hpp index 2c5f7500..45b5d54b 100644 --- a/include/rfl/avro/read.hpp +++ b/include/rfl/avro/read.hpp @@ -21,14 +21,26 @@ namespace rfl::avro { using InputObjectType = typename Reader::InputObjectType; using InputVarType = typename Reader::InputVarType; -/// Parses an object from a AVRO var. +/// Parses an object from an Avro value (internal representation). +/// This is typically used when you already have an Avro value structure. +/// @tparam T The type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _obj The Avro value to parse +/// @return The deserialized object or an error template auto read(const InputVarType& _obj) { const auto r = Reader(); return Parser>::read(r, _obj); } -/// Parses an object from AVRO using reflection. +/// Parses an object from Avro binary data with an explicit schema. +/// This version uses a pre-defined schema for deserialization. +/// @tparam T The type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _bytes Pointer to the Avro binary data +/// @param _size Size of the binary data in bytes +/// @param _schema The Avro schema to use for deserialization +/// @return A Result containing the deserialized object or an error template Result> read( const concepts::ByteLike auto* _bytes, const size_t _size, @@ -54,27 +66,47 @@ Result> read( return result; } -/// Parses an object from AVRO using reflection. +/// Parses an object from Avro binary data using reflection to infer the schema. +/// This automatically generates the Avro schema from the C++ type. +/// @tparam T The type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _bytes Pointer to the Avro binary data +/// @param _size Size of the binary data in bytes +/// @return A Result containing the deserialized object or an error template auto read(const concepts::ByteLike auto* _bytes, const size_t _size) { const auto schema = to_schema, Ps...>(); return read(_bytes, _size, schema); } -/// Parses an object from AVRO using reflection. +/// Parses an object from an Avro binary container with an explicit schema. +/// @tparam T The type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _bytes A contiguous container (e.g., std::vector, std::string) containing Avro data +/// @param _schema The Avro schema to use for deserialization +/// @return A Result containing the deserialized object or an error template auto read(const concepts::ContiguousByteContainer auto& _bytes, const Schema& _schema) noexcept { return read(_bytes.data(), _bytes.size(), _schema); } -/// Parses an object from AVRO using reflection. +/// Parses an object from an Avro binary container using reflection to infer the schema. +/// @tparam T The type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _bytes A contiguous container (e.g., std::vector, std::string) containing Avro data +/// @return A Result containing the deserialized object or an error template auto read(const concepts::ContiguousByteContainer auto& _bytes) { return read(_bytes.data(), _bytes.size()); } -/// Parses an object from a stream. +/// Parses an object from an input stream containing Avro binary data. +/// Reads the entire stream into memory before deserializing. +/// @tparam T The type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _stream The input stream to read from +/// @return A Result containing the deserialized object or an error template auto read(std::istream& _stream) { std::istreambuf_iterator begin(_stream), end; diff --git a/include/rfl/avro/save.hpp b/include/rfl/avro/save.hpp index 6bd37967..09461fbc 100644 --- a/include/rfl/avro/save.hpp +++ b/include/rfl/avro/save.hpp @@ -11,6 +11,12 @@ namespace rfl::avro { +/// Saves an object to a file in Avro binary format. +/// Serializes the object and writes it to the specified file path. +/// @tparam Ps Optional processors to apply during serialization +/// @param _fname The path to the file to save to +/// @param _obj The object to serialize +/// @return A Result containing Nothing on success or an error template Result save(const std::string& _fname, const auto& _obj) { const auto write_func = [](const auto& _obj, diff --git a/include/rfl/avro/to_schema.hpp b/include/rfl/avro/to_schema.hpp index 3e9adc40..1865f6a3 100644 --- a/include/rfl/avro/to_schema.hpp +++ b/include/rfl/avro/to_schema.hpp @@ -12,10 +12,18 @@ namespace rfl::avro { +/// Converts an internal schema definition to JSON representation. +/// This is used internally to generate Avro schema JSON. +/// @param internal_schema The internal schema definition +/// @return A JSON string representing the Avro schema RFL_API std::string to_json_representation( const parsing::schema::Definition& internal_schema); -/// Returns the Avro schema for a class. +/// Generates an Avro schema for the given C++ type. +/// Uses reflection to analyze the type structure and creates a corresponding Avro schema. +/// @tparam T The C++ type to generate a schema for +/// @tparam Ps Optional processors that may affect schema generation +/// @return A Schema object that can be used for reading/writing Avro data template Schema to_schema() noexcept { const auto internal_schema = diff --git a/include/rfl/avro/write.hpp b/include/rfl/avro/write.hpp index 44f4f979..a8d752f8 100644 --- a/include/rfl/avro/write.hpp +++ b/include/rfl/avro/write.hpp @@ -14,7 +14,11 @@ namespace rfl::avro { -/// Returns AVRO bytes. +/// Serializes an object to Avro binary format with an explicit schema. +/// @tparam Ps Optional processors to apply during serialization +/// @param _obj The object to serialize +/// @param _schema The Avro schema to use (must match the object type) +/// @return A vector of bytes containing the Avro binary data template std::vector write(const auto& _obj, const auto& _schema) { using T = std::remove_cvref_t; @@ -59,7 +63,11 @@ std::vector write(const auto& _obj, const auto& _schema) { return buffer.value(); } -/// Returns AVRO bytes. +/// Serializes an object to Avro binary format, inferring the schema from the type. +/// This automatically generates the Avro schema from the C++ type. +/// @tparam Ps Optional processors to apply during serialization +/// @param _obj The object to serialize +/// @return A vector of bytes containing the Avro binary data template std::vector write(const auto& _obj) { using T = std::remove_cvref_t; @@ -67,7 +75,11 @@ std::vector write(const auto& _obj) { return write(_obj, schema); } -/// Writes a AVRO into an ostream. +/// Writes an object in Avro binary format to an output stream. +/// @tparam Ps Optional processors to apply during serialization +/// @param _obj The object to serialize +/// @param _stream The output stream to write to +/// @return The output stream (for chaining) template std::ostream& write(const auto& _obj, std::ostream& _stream) { auto buffer = write(_obj); diff --git a/include/rfl/boost_serialization/Reader.hpp b/include/rfl/boost_serialization/Reader.hpp index 03bc0087..d4dc30b4 100644 --- a/include/rfl/boost_serialization/Reader.hpp +++ b/include/rfl/boost_serialization/Reader.hpp @@ -47,8 +47,17 @@ struct Reader { template static constexpr bool has_custom_constructor = false; + /// Checks if the given Boost archive value is empty. + /// Always returns false for Boost.Serialization as it doesn't have a null concept. + /// @param _var The archive variable (unused) + /// @return Always false bool is_empty(const InputVarType& /*_var*/) const noexcept { return false; } + /// Converts a value from the Boost archive to a basic C++ type. + /// Supports strings, booleans, floating-point numbers, integers, and literal types. + /// @tparam T The target C++ type to convert to + /// @param _var The archive variable containing the value + /// @return A Result containing the converted value or an error template rfl::Result to_basic_type(const InputVarType& _var) const noexcept { try { @@ -85,6 +94,10 @@ struct Reader { } } + /// Converts an archive value to an array type. + /// Reads the size first, then prepares to read array elements. + /// @param _var The archive variable + /// @return A Result containing an InputArrayType or an error rfl::Result to_array( const InputVarType& _var) const noexcept { try { @@ -96,6 +109,10 @@ struct Reader { } } + /// Converts an archive value to an object type. + /// Reads the size first, then prepares to read object fields. + /// @param _var The archive variable + /// @return A Result containing an InputObjectType or an error rfl::Result to_object( const InputVarType& _var) const noexcept { try { @@ -107,6 +124,10 @@ struct Reader { } } + /// Converts an archive value to a map type. + /// Reads the size first, then prepares to read key-value pairs. + /// @param _var The archive variable + /// @return A Result containing an InputMapType or an error rfl::Result to_map(const InputVarType& _var) const noexcept { try { std::uint64_t size = 0; @@ -117,11 +138,19 @@ struct Reader { } } + /// Converts an archive value to a union (variant) type. + /// @param _var The archive variable + /// @return A Result containing an InputUnionType rfl::Result to_union( const InputVarType& _var) const noexcept { return InputUnionType{_var.ar}; } + /// Reads all elements from an array using the provided array reader. + /// @tparam ArrayReader The type of reader that processes individual array elements + /// @param _array_reader The reader object that processes each element + /// @param _arr The array structure containing size information + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_array(const ArrayReader& _array_reader, const InputArrayType& _arr) const noexcept { @@ -135,6 +164,12 @@ struct Reader { return std::nullopt; } + /// Reads all key-value pairs from a map using the provided map reader. + /// Keys are read as strings from the archive. + /// @tparam MapReader The type of reader that processes individual map entries + /// @param _map_reader The reader object that processes each key-value pair + /// @param _map The map structure containing size information + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_map(const MapReader& _map_reader, const InputMapType& _map) const noexcept { @@ -151,6 +186,12 @@ struct Reader { } } + /// Reads all fields from an object using the provided object reader. + /// Fields are accessed by their index. + /// @tparam ObjectReader The type of reader that processes individual object fields + /// @param _object_reader The reader object that processes each field + /// @param _obj The object structure containing size information + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_object(const ObjectReader& _object_reader, const InputObjectType& _obj) const noexcept { @@ -161,6 +202,12 @@ struct Reader { return std::nullopt; } + /// Reads a union (variant) value and converts it to the appropriate variant type. + /// Reads the discriminant first to determine which alternative is active. + /// @tparam VariantType The C++ variant type to construct + /// @tparam UnionReaderType The type of reader that handles union alternatives + /// @param _union The union structure + /// @return A Result containing the variant or an error template rfl::Result read_union( const InputUnionType& _union) const noexcept { @@ -174,6 +221,10 @@ struct Reader { } } + /// Custom constructors are not supported for Boost.Serialization. + /// @tparam T The type to construct (unused) + /// @param _var The archive variable (unused) + /// @return Always returns an error template rfl::Result use_custom_constructor( const InputVarType& /*_var*/) const noexcept { diff --git a/include/rfl/boost_serialization/Writer.hpp b/include/rfl/boost_serialization/Writer.hpp index 3a6b9b1d..8f77628d 100644 --- a/include/rfl/boost_serialization/Writer.hpp +++ b/include/rfl/boost_serialization/Writer.hpp @@ -30,29 +30,52 @@ class Writer { using OutputUnionType = BoostOutputUnion; using OutputVarType = BoostOutputVar; + /// Constructs a Writer with a Boost output archive. + /// @param _ar Pointer to the Boost output archive to write to Writer(OArchive* _ar) : ar_(_ar) {} ~Writer() = default; + /// Creates an array as the root element. + /// Writes the size to the archive first. + /// @param _size The number of elements in the array + /// @return An OutputArrayType OutputArrayType array_as_root(const size_t _size) const { write_size(_size); return OutputArrayType{}; } + /// Creates a map as the root element. + /// Writes the size to the archive first. + /// @param _size The number of entries in the map + /// @return An OutputMapType OutputMapType map_as_root(const size_t _size) const { write_size(_size); return OutputMapType{}; } + /// Creates an object as the root element. + /// Writes the size to the archive first. + /// @param _size The number of fields in the object + /// @return An OutputObjectType OutputObjectType object_as_root(const size_t _size) const { write_size(_size); return OutputObjectType{}; } + /// Creates a null value as the root element. + /// This is a no-op for Boost.Serialization. + /// @return An OutputVarType OutputVarType null_as_root() const { return OutputVarType{}; } + /// Creates a union as the root element. + /// @return An OutputUnionType OutputUnionType union_as_root() const { return OutputUnionType{}; } + /// Writes a value as the root element. + /// @tparam T The type of the value + /// @param _var The value to write + /// @return An OutputVarType template OutputVarType value_as_root(const T& _var) const { new_value(_var); @@ -216,10 +239,19 @@ class Writer { return OutputVarType{}; } + /// Finalizes an array after all elements have been added. + /// This is a no-op for Boost.Serialization. + /// @param _arr Pointer to the array (unused) void end_array(OutputArrayType* /*_arr*/) const {} + /// Finalizes a map after all entries have been added. + /// This is a no-op for Boost.Serialization. + /// @param _obj Pointer to the map (unused) void end_map(OutputMapType* /*_obj*/) const {} + /// Finalizes an object after all fields have been added. + /// This is a no-op for Boost.Serialization. + /// @param _obj Pointer to the object (unused) void end_object(OutputObjectType* /*_obj*/) const {} private: diff --git a/include/rfl/boost_serialization/load.hpp b/include/rfl/boost_serialization/load.hpp index e487e009..31a43cfb 100644 --- a/include/rfl/boost_serialization/load.hpp +++ b/include/rfl/boost_serialization/load.hpp @@ -8,6 +8,12 @@ namespace rfl { namespace boost_serialization { +/// Loads and parses an object from a file using Boost.Serialization. +/// Reads the file as binary data and deserializes it using a Boost binary archive. +/// @tparam T The type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _fname The path to the file to load +/// @return A Result containing the deserialized object or an error template Result load(const std::string& _fname) { const auto read_bytes = [](const auto& _bytes) { diff --git a/include/rfl/boost_serialization/read.hpp b/include/rfl/boost_serialization/read.hpp index 1773f82e..a89a3540 100644 --- a/include/rfl/boost_serialization/read.hpp +++ b/include/rfl/boost_serialization/read.hpp @@ -37,13 +37,26 @@ class MemBuf : public std::streambuf { } // namespace detail -/// Reads from an existing Boost input archive. +/// Reads an object from an existing Boost input archive. +/// This allows you to use a custom archive type (e.g., text, XML, binary). +/// @tparam T The type to deserialize into +/// @tparam IArchive The Boost input archive type +/// @tparam OArchive The corresponding Boost output archive type +/// @tparam Ps Optional processors to apply during deserialization +/// @param _ar The Boost input archive to read from +/// @return A Result containing the deserialized object or an error template auto read_from_archive(IArchive& _ar) { return detail::read_from_archive(_ar); } -/// Parses an object from bytes using a binary archive. +/// Parses an object from raw bytes using Boost binary archive. +/// Creates a memory stream from the bytes and deserializes using Boost.Serialization. +/// @tparam T The type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _bytes Pointer to the binary data +/// @param _size Size of the binary data in bytes +/// @return A Result containing the deserialized object or an error template Result> read( const concepts::ByteLike auto* _bytes, const size_t _size) { @@ -60,13 +73,21 @@ Result> read( } } -/// Parses an object from a byte container using a binary archive. +/// Parses an object from a byte container using Boost binary archive. +/// @tparam T The type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _bytes A contiguous container (e.g., std::vector, std::string) containing the data +/// @return A Result containing the deserialized object or an error template auto read(const concepts::ContiguousByteContainer auto& _bytes) { return read(_bytes.data(), _bytes.size()); } -/// Parses an object from a stream using a binary archive. +/// Parses an object from an input stream using Boost binary archive. +/// @tparam T The type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _stream The input stream to read from +/// @return A Result containing the deserialized object or an error template auto read(std::istream& _stream) { try { diff --git a/include/rfl/boost_serialization/save.hpp b/include/rfl/boost_serialization/save.hpp index fd5229e5..6283d9ab 100644 --- a/include/rfl/boost_serialization/save.hpp +++ b/include/rfl/boost_serialization/save.hpp @@ -11,6 +11,12 @@ namespace rfl::boost_serialization { +/// Saves an object to a file using Boost.Serialization binary format. +/// Serializes the object and writes it to the specified file path. +/// @tparam Ps Optional processors to apply during serialization +/// @param _fname The path to the file to save to +/// @param _obj The object to serialize +/// @return A Result containing Nothing on success or an error template Result save(const std::string& _fname, const auto& _obj) { const auto write_func = [](const auto& _obj, diff --git a/include/rfl/boost_serialization/write.hpp b/include/rfl/boost_serialization/write.hpp index 88e8595c..32da60dc 100644 --- a/include/rfl/boost_serialization/write.hpp +++ b/include/rfl/boost_serialization/write.hpp @@ -16,7 +16,13 @@ namespace rfl::boost_serialization { -/// Writes into an existing Boost output archive. +/// Writes an object directly into an existing Boost output archive. +/// This allows you to use custom archive types and integrate with existing Boost.Serialization code. +/// @tparam IArchive The corresponding Boost input archive type (for type info) +/// @tparam OArchive The Boost output archive type +/// @tparam Ps Optional processors to apply during serialization +/// @param _ar The Boost output archive to write to +/// @param _obj The object to serialize template void write(OArchive& _ar, const auto& _obj) { @@ -28,7 +34,10 @@ void write(OArchive& _ar, const auto& _obj) { w, _obj, typename ParentType::Root{}); } -/// Returns serialized bytes using a binary archive. +/// Serializes an object to bytes using Boost binary archive format. +/// @tparam Ps Optional processors to apply during serialization +/// @param _obj The object to serialize +/// @return A vector of bytes containing the serialized data template std::vector write(const auto& _obj) { std::ostringstream stream; @@ -42,7 +51,11 @@ std::vector write(const auto& _obj) { return std::vector(str.begin(), str.end()); } -/// Writes into an ostream using a binary archive. +/// Writes an object to an output stream using Boost binary archive format. +/// @tparam Ps Optional processors to apply during serialization +/// @param _obj The object to serialize +/// @param _stream The output stream to write to +/// @return The output stream (for chaining) template std::ostream& write(const auto& _obj, std::ostream& _stream) { boost::archive::binary_oarchive ar( diff --git a/include/rfl/bson/load.hpp b/include/rfl/bson/load.hpp index 05cd9b78..2f69dacb 100644 --- a/include/rfl/bson/load.hpp +++ b/include/rfl/bson/load.hpp @@ -8,6 +8,13 @@ namespace rfl { namespace bson { +/// Loads an object from a BSON file. +/// Reads a binary file from disk and parses its BSON content into a C++ object using compile-time reflection. +/// BSON (Binary JSON) is the binary serialization format used by MongoDB. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _fname The filename/path of the BSON file to load +/// @return Result containing either the parsed object of type T or an error message template Result load(const std::string& _fname) { const auto read_bytes = [](const auto& _bytes) { diff --git a/include/rfl/bson/read.hpp b/include/rfl/bson/read.hpp index a04da5ca..310b3918 100644 --- a/include/rfl/bson/read.hpp +++ b/include/rfl/bson/read.hpp @@ -19,7 +19,12 @@ namespace bson { using InputObjectType = typename Reader::InputObjectType; using InputVarType = typename Reader::InputVarType; -/// Parses an object from a BSON var. +/// Parses an object from a BSON var (internal BSON value representation). +/// A BSON var is the internal representation used by the libbson library. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _obj The BSON variant object to parse from +/// @return Result containing the parsed object of type T template Result> read(const InputVarType& _obj) { const auto r = Reader(); @@ -30,7 +35,13 @@ Result> read(const InputVarType& _obj) { return Parser::read(r, _obj); } -/// Parses an BSON object using reflection. +/// Parses a BSON object from raw bytes using reflection. +/// BSON (Binary JSON) is the binary serialization format used by MongoDB. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _bytes Pointer to byte-like data containing BSON +/// @param _size The size of the byte array +/// @return Result containing the parsed object (or array of objects) template auto read(const concepts::ByteLike auto* _bytes, const size_t _size) { bson_value_t val; @@ -41,13 +52,22 @@ auto read(const concepts::ByteLike auto* _bytes, const size_t _size) { return read(Reader::InputVarType{&val}); } -/// Parses an object from BSON using reflection. +/// Parses an object from BSON using reflection (contiguous container version). +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _bytes A contiguous byte container (e.g., std::vector, std::string) containing BSON data +/// @return Result containing the parsed object (or array of objects) template auto read(const concepts::ContiguousByteContainer auto& _bytes) { return read(_bytes.data(), _bytes.size()); } -/// Parses an object from a stream. +/// Parses an object from a stream containing BSON data. +/// Reads BSON binary data from the stream and constructs a C++ object. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _stream The input stream containing BSON binary data +/// @return Result containing the parsed object (or array of objects) template auto read(std::istream& _stream) { std::istreambuf_iterator begin(_stream), end; diff --git a/include/rfl/bson/save.hpp b/include/rfl/bson/save.hpp index 1f4202c6..16aacecc 100644 --- a/include/rfl/bson/save.hpp +++ b/include/rfl/bson/save.hpp @@ -10,6 +10,13 @@ namespace rfl { namespace bson { +/// Saves an object to a BSON file. +/// Serializes a C++ object to BSON binary format and writes it to a file using compile-time reflection. +/// BSON (Binary JSON) is the binary serialization format used by MongoDB. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _fname The filename/path where the BSON file will be saved +/// @param _obj The object to serialize to BSON +/// @return Result containing Nothing on success or an error message on failure template Result save(const std::string& _fname, const auto& _obj) { const auto write_func = [](const auto& _obj, auto& _stream) -> auto& { diff --git a/include/rfl/bson/write.hpp b/include/rfl/bson/write.hpp index 8cd6f0b6..9f9374d2 100644 --- a/include/rfl/bson/write.hpp +++ b/include/rfl/bson/write.hpp @@ -18,8 +18,12 @@ namespace rfl { namespace bson { -/// Returns BSON bytes. Careful: It is the responsibility of the caller to call -/// bson_free on the returned pointer. +/// Converts an object to BSON and returns a buffer pointer. +/// WARNING: It is the caller's responsibility to call bson_free() on the returned pointer. +/// This is a low-level function; prefer write() for automatic memory management. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to BSON +/// @return Result containing a pair of (buffer pointer, buffer size) or an error template Result> to_buffer(const auto& _obj) noexcept { using T = std::remove_cvref_t; @@ -55,7 +59,12 @@ Result> to_buffer(const auto& _obj) noexcept { }); } -/// Returns BSON bytes. +/// Returns BSON bytes representation of the object. +/// BSON (Binary JSON) is the binary serialization format used by MongoDB. +/// Uses compile-time reflection to serialize a C++ object to BSON format. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to BSON +/// @return A vector of chars containing the BSON binary representation template std::vector write(const auto& _obj) { return to_buffer(_obj) @@ -69,7 +78,12 @@ std::vector write(const auto& _obj) { .value(); } -/// Writes a BSON into an ostream. +/// Writes a BSON representation into an ostream. +/// Uses compile-time reflection to serialize a C++ object to BSON and write to a stream. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to BSON +/// @param _stream The output stream to write BSON binary data to +/// @return The output stream (for chaining) template std::ostream& write(const auto& _obj, std::ostream& _stream) { to_buffer(_obj) diff --git a/include/rfl/cbor/Reader.hpp b/include/rfl/cbor/Reader.hpp index 59092fe5..f7f705af 100644 --- a/include/rfl/cbor/Reader.hpp +++ b/include/rfl/cbor/Reader.hpp @@ -16,16 +16,27 @@ namespace rfl::cbor { +/// Reader class for deserializing CBOR (Concise Binary Object Representation) data. +/// This class provides the interface for parsing CBOR format into C++ objects. +/// CBOR is a binary data serialization format that is more compact than JSON while +/// maintaining similar data model capabilities. class Reader { public: + /// Represents a CBOR array during deserialization. + /// Wraps a pointer to the underlying jsoncons JSON value representing the array. struct CBORInputArray { jsoncons::json* val_; }; + /// Represents a CBOR object during deserialization. + /// Wraps a pointer to the underlying jsoncons JSON value representing the object. struct CBORInputObject { jsoncons::json* val_; }; + /// Represents a variant CBOR value during deserialization. + /// Can hold any CBOR type (array, object, primitive, etc.). + /// Wraps a pointer to the underlying jsoncons JSON value. struct CBORInputVar { jsoncons::json* val_; }; @@ -34,14 +45,21 @@ class Reader { using InputObjectType = CBORInputObject; using InputVarType = CBORInputVar; + /// Constructs a new CBOR Reader. Reader() {} ~Reader() = default; + /// Compile-time flag indicating whether type T has a custom constructor from CBOR. + /// If true, the type provides a static from_cbor_obj() method for custom deserialization. template static constexpr bool has_custom_constructor = (requires(InputVarType var) { T::from_cbor_obj(var); }); + /// Retrieves a field from a CBOR array by index. + /// @param _idx The zero-based index of the element to retrieve + /// @param _arr The CBOR array to read from + /// @return Result containing the field value, or an error if index is out of bounds rfl::Result get_field_from_array( const size_t _idx, const InputArrayType& _arr) const noexcept { if (_idx >= _arr.val_->size()) { @@ -50,6 +68,10 @@ class Reader { return InputVarType{&_arr.val_->at(_idx)}; } + /// Retrieves a field from a CBOR object by name. + /// @param _name The name of the field to retrieve + /// @param _obj The CBOR object to read from + /// @return Result containing the field value, or an error if field is not found rfl::Result get_field_from_object( const std::string& _name, const InputObjectType& _obj) const noexcept { for (auto& kv : _obj.val_->object_range()) { @@ -60,10 +82,18 @@ class Reader { return error("Field name '" + _name + "' not found."); } + /// Checks if a CBOR value is empty or null. + /// @param _var The CBOR value to check + /// @return true if the value is null, false otherwise bool is_empty(const InputVarType& _var) const noexcept { return _var.val_->is_null(); } + /// Converts a CBOR value to a basic C++ type. + /// Supports strings, bytesstrings, booleans, floating-point numbers, and integers. + /// @tparam T The target C++ type + /// @param _var The CBOR value to convert + /// @return Result containing the converted value, or an error if conversion fails template rfl::Result to_basic_type(const InputVarType& _var) const noexcept { if constexpr (std::is_same, std::string>()) { @@ -116,6 +146,9 @@ class Reader { } } + /// Converts a CBOR value to an array. + /// @param _var The CBOR value to convert + /// @return Result containing the array, or an error if value is not an array rfl::Result to_array( const InputVarType& _var) const noexcept { if (!_var.val_->is_array()) { @@ -124,6 +157,9 @@ class Reader { return InputArrayType{_var.val_}; } + /// Converts a CBOR value to an object. + /// @param _var The CBOR value to convert + /// @return Result containing the object, or an error if value is not an object rfl::Result to_object( const InputVarType& _var) const noexcept { if (!_var.val_->is_object()) { @@ -132,6 +168,12 @@ class Reader { return InputObjectType{_var.val_}; } + /// Reads all elements from a CBOR array using a provided array reader. + /// The array reader's read() method is called for each element in the array. + /// @tparam ArrayReader Type that provides a read() method for processing elements + /// @param _array_reader The reader object used to process each array element + /// @param _arr The CBOR array to read from + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_array(const ArrayReader& _array_reader, const InputArrayType& _arr) const noexcept { @@ -144,6 +186,12 @@ class Reader { return std::nullopt; } + /// Reads all key-value pairs from a CBOR object using a provided object reader. + /// The object reader's read() method is called for each key-value pair. + /// @tparam ObjectReader Type that provides a read() method for processing key-value pairs + /// @param _object_reader The reader object used to process each field + /// @param _obj The CBOR object to read from + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_object(const ObjectReader& _object_reader, const InputObjectType& _obj) const noexcept { @@ -153,6 +201,11 @@ class Reader { return std::nullopt; } + /// Uses a type's custom constructor to deserialize from CBOR. + /// Calls the type's static from_cbor_obj() method for custom deserialization logic. + /// @tparam T The type to construct, must have a from_cbor_obj() static method + /// @param _var The CBOR value to deserialize from + /// @return Result containing the constructed object, or an error if construction fails template rfl::Result use_custom_constructor( const InputVarType& _var) const noexcept { diff --git a/include/rfl/cbor/Writer.hpp b/include/rfl/cbor/Writer.hpp index d509b5a3..a934497e 100644 --- a/include/rfl/cbor/Writer.hpp +++ b/include/rfl/cbor/Writer.hpp @@ -14,55 +14,110 @@ namespace rfl::cbor { +/// Writer class for serializing C++ objects to CBOR (Concise Binary Object Representation) format. +/// This class provides the interface for converting C++ objects into compact binary CBOR data. +/// CBOR is a binary data serialization format designed to be smaller and faster than JSON. class RFL_API Writer { using Encoder = jsoncons::cbor::cbor_bytes_encoder; public: + /// Represents a CBOR array being constructed during serialization. + /// This is a placeholder type as the actual array data is managed by the encoder. struct CBOROutputArray {}; + /// Represents a CBOR object being constructed during serialization. + /// This is a placeholder type as the actual object data is managed by the encoder. struct CBOROutputObject {}; + /// Represents a CBOR value being constructed during serialization. + /// This is a placeholder type as the actual value data is managed by the encoder. struct CBOROutputVar {}; using OutputArrayType = CBOROutputArray; using OutputObjectType = CBOROutputObject; using OutputVarType = CBOROutputVar; + /// Constructs a CBOR Writer with the specified encoder. + /// @param _encoder Pointer to the CBOR encoder that will write the binary output Writer(Encoder* _encoder); ~Writer(); + /// Creates a CBOR array as the root element of the output. + /// @param _size The expected size of the array (may be used for optimization) + /// @return An output array that can be populated with elements OutputArrayType array_as_root(const size_t _size) const; + /// Creates a CBOR object as the root element of the output. + /// @param The expected number of fields (unused, reserved for future optimization) + /// @return An output object that can be populated with key-value pairs OutputObjectType object_as_root(const size_t) const; + /// Creates a null value as the root element of the output. + /// @return An output variable representing null OutputVarType null_as_root() const; + /// Creates a value as the root element of the output. + /// Supports basic types like strings, numbers, booleans, and byte strings. + /// @tparam T The type of the value to serialize + /// @param _var The value to write as the root element + /// @return An output variable representing the serialized value template OutputVarType value_as_root(const T& _var) const { return new_value(_var); } + /// Adds a nested array to a parent array. + /// @param _size The expected size of the nested array + /// @param _parent Pointer to the parent array to add to + /// @return An output array that can be populated with elements OutputArrayType add_array_to_array(const size_t _size, OutputArrayType* _parent) const; + /// Adds a nested array to a parent object with the specified field name. + /// @param _name The name of the field in the parent object + /// @param _size The expected size of the nested array + /// @param _parent Pointer to the parent object to add to + /// @return An output array that can be populated with elements OutputArrayType add_array_to_object(const std::string_view& _name, const size_t _size, OutputObjectType* _parent) const; + /// Adds a nested object to a parent array. + /// @param The expected number of fields (unused, reserved for future optimization) + /// @param _parent Pointer to the parent array to add to + /// @return An output object that can be populated with key-value pairs OutputObjectType add_object_to_array(const size_t, OutputArrayType* _parent) const; + /// Adds a nested object to a parent object with the specified field name. + /// @param _name The name of the field in the parent object + /// @param The expected number of fields (unused, reserved for future optimization) + /// @param _parent Pointer to the parent object to add to + /// @return An output object that can be populated with key-value pairs OutputObjectType add_object_to_object(const std::string_view& _name, const size_t, OutputObjectType* _parent) const; + /// Adds a value to a parent array. + /// Supports basic types like strings, numbers, booleans, and byte strings. + /// @tparam T The type of the value to add + /// @param _var The value to add to the array + /// @param _parent Pointer to the parent array (unused as encoder tracks context) + /// @return An output variable representing the added value template OutputVarType add_value_to_array(const T& _var, OutputArrayType* /*_parent*/) const { return new_value(_var); } + /// Adds a value to a parent object with the specified field name. + /// Supports basic types like strings, numbers, booleans, and byte strings. + /// @tparam T The type of the value to add + /// @param _name The name of the field in the parent object + /// @param _var The value to add to the object + /// @param _parent Pointer to the parent object (unused as encoder tracks context) + /// @return An output variable representing the added value template OutputVarType add_value_to_object(const std::string_view& _name, const T& _var, @@ -71,13 +126,24 @@ class RFL_API Writer { return new_value(_var); } + /// Adds a null value to a parent array. + /// @param _parent Pointer to the parent array to add to + /// @return An output variable representing the null value OutputVarType add_null_to_array(OutputArrayType* _parent) const; + /// Adds a null value to a parent object with the specified field name. + /// @param _name The name of the field in the parent object + /// @param _parent Pointer to the parent object to add to + /// @return An output variable representing the null value OutputVarType add_null_to_object(const std::string_view& _name, OutputObjectType* _parent) const; + /// Finalizes a CBOR array after all elements have been added. + /// @param _arr Pointer to the array to finalize void end_array(OutputArrayType* _arr) const; + /// Finalizes a CBOR object after all fields have been added. + /// @param _obj Pointer to the object to finalize void end_object(OutputObjectType* _obj) const; private: diff --git a/include/rfl/cbor/load.hpp b/include/rfl/cbor/load.hpp index f4979248..6a784283 100644 --- a/include/rfl/cbor/load.hpp +++ b/include/rfl/cbor/load.hpp @@ -8,6 +8,12 @@ namespace rfl::cbor { +/// Loads an object from a CBOR file. +/// Reads a binary file from disk and parses its CBOR content into a C++ object using compile-time reflection. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _fname The filename/path of the CBOR file to load +/// @return Result containing either the parsed object of type T or an error message template Result load(const std::string& _fname) { const auto read_bytes = [](const auto& _bytes) { diff --git a/include/rfl/cbor/read.hpp b/include/rfl/cbor/read.hpp index 1939b1f9..c60fdbeb 100644 --- a/include/rfl/cbor/read.hpp +++ b/include/rfl/cbor/read.hpp @@ -17,7 +17,13 @@ namespace rfl::cbor { using InputObjectType = typename Reader::InputObjectType; using InputVarType = typename Reader::InputVarType; -/// Parses an object from CBOR using reflection. +/// Parses an object from CBOR bytes using reflection. +/// CBOR (Concise Binary Object Representation) is a binary data format similar to JSON. +/// This function reads CBOR bytes and constructs a C++ object using compile-time reflection. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _bytes A contiguous byte container (e.g., std::vector, std::string) containing CBOR data +/// @return Result containing either the parsed object (or array of objects) or an error message template Result> read( const concepts::ContiguousByteContainer auto& _bytes) { @@ -30,7 +36,12 @@ Result> read( } } -/// Parses an object from a stream. +/// Parses an object from a stream containing CBOR data. +/// Reads CBOR binary data from the stream and constructs a C++ object. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _stream The input stream containing CBOR binary data +/// @return Result containing either the parsed object (or array of objects) or an error message template Result> read(std::istream& _stream) { auto result = jsoncons::cbor::try_decode_cbor(_stream); diff --git a/include/rfl/cbor/save.hpp b/include/rfl/cbor/save.hpp index 97f0961f..9a904857 100644 --- a/include/rfl/cbor/save.hpp +++ b/include/rfl/cbor/save.hpp @@ -9,6 +9,12 @@ namespace rfl::cbor { +/// Saves an object to a CBOR file. +/// Serializes a C++ object to CBOR binary format and writes it to a file using compile-time reflection. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _fname The filename/path where the CBOR file will be saved +/// @param _obj The object to serialize to CBOR +/// @return Result containing Nothing on success or an error message on failure template Result save(const std::string& _fname, const auto& _obj) { const auto write_func = [](const auto& _obj, auto& _stream) -> auto& { diff --git a/include/rfl/cbor/write.hpp b/include/rfl/cbor/write.hpp index 162eea89..97cecb29 100644 --- a/include/rfl/cbor/write.hpp +++ b/include/rfl/cbor/write.hpp @@ -11,7 +11,12 @@ namespace rfl::cbor { -/// Returns CBOR bytes. +/// Returns CBOR bytes representation of the object. +/// CBOR (Concise Binary Object Representation) is a binary data format similar to JSON but more compact. +/// Uses compile-time reflection to serialize a C++ object to CBOR format. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to CBOR +/// @return A vector of chars containing the CBOR binary representation template std::vector write(const auto& _obj) { using T = std::remove_cvref_t; @@ -26,7 +31,12 @@ std::vector write(const auto& _obj) { internal::ptr_cast(buffer.data() + buffer.size())); } -/// Writes a CBOR into an ostream. +/// Writes a CBOR representation into an ostream. +/// Uses compile-time reflection to serialize a C++ object to CBOR and write to a stream. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to CBOR +/// @param _stream The output stream to write CBOR binary data to +/// @return The output stream (for chaining) template std::ostream& write(const auto& _obj, std::ostream& _stream) { auto buffer = write(_obj); diff --git a/include/rfl/cereal/Reader.hpp b/include/rfl/cereal/Reader.hpp index dd8420a3..85d1ab09 100644 --- a/include/rfl/cereal/Reader.hpp +++ b/include/rfl/cereal/Reader.hpp @@ -18,6 +18,9 @@ namespace rfl::cereal { +/// Reader for Cereal serialization library integration. +/// Cereal is a C++11 serialization library that supports multiple archive formats. +/// This reader uses Cereal's portable binary archive format for cross-platform compatibility. struct Reader { using CerealArchive = ::cereal::PortableBinaryInputArchive; @@ -49,8 +52,16 @@ struct Reader { static constexpr bool has_custom_constructor = (requires(InputVarType var) { T::from_cereal_obj(var); }); + /// Checks if the Cereal value is empty (null). + /// @param _var The Cereal archive variable to check + /// @return true if empty/null, false otherwise bool is_empty(const InputVarType& _var) const noexcept; + /// Converts a value from the Cereal archive to a basic C++ type. + /// Supports strings, literals, byte containers, and all standard types Cereal can serialize. + /// @tparam T The target C++ type to convert to + /// @param _var The Cereal archive variable containing the value + /// @return A Result containing the converted value or an error template rfl::Result to_basic_type(const InputVarType& _var) const noexcept { try { @@ -79,17 +90,36 @@ struct Reader { } } + /// Converts a Cereal archive value to an array type. + /// Reads the size tag first, then prepares to read array elements. + /// @param _var The Cereal archive variable + /// @return A Result containing an InputArrayType or an error rfl::Result to_array( const InputVarType& _var) const noexcept; + /// Converts a Cereal archive value to an object (struct) type. + /// @param _var The Cereal archive variable + /// @return A Result containing an InputObjectType or an error rfl::Result to_object( const InputVarType& _var) const noexcept; + /// Converts a Cereal archive value to a map type. + /// @param _var The Cereal archive variable + /// @return A Result containing an InputMapType or an error rfl::Result to_map(const InputVarType& _var) const noexcept; + /// Converts a Cereal archive value to a union (variant) type. + /// @param _var The Cereal archive variable + /// @return A Result containing an InputUnionType or an error rfl::Result to_union( const InputVarType& _var) const noexcept; + /// Reads all elements from a Cereal array using the provided array reader. + /// Cereal stores the size as a size tag before the elements. + /// @tparam ArrayReader The type of reader that processes individual array elements + /// @param _array_reader The reader object that processes each element + /// @param _arr The Cereal array structure + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_array(const ArrayReader& _array_reader, const InputArrayType& _arr) const noexcept { @@ -108,6 +138,12 @@ struct Reader { } } + /// Reads all key-value pairs from a Cereal map using the provided map reader. + /// Keys are stored as strings in the archive. + /// @tparam MapReader The type of reader that processes individual map entries + /// @param _map_reader The reader object that processes each key-value pair + /// @param _map The Cereal map structure + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_map(const MapReader& _map_reader, const InputMapType& _map) const noexcept { @@ -125,6 +161,12 @@ struct Reader { } } + /// Reads all fields from a Cereal object using the provided object reader. + /// Fields are read in declaration order by index. + /// @tparam ObjectReader The type of reader that processes individual object fields + /// @param _object_reader The reader object that processes each field + /// @param _obj The Cereal object structure + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_object(const ObjectReader& _object_reader, const InputObjectType& _obj) const noexcept { @@ -138,6 +180,12 @@ struct Reader { } } + /// Reads a union (variant) value and converts it to the appropriate variant type. + /// Reads the discriminant index first to determine which alternative is active. + /// @tparam T The C++ variant type to construct + /// @tparam UnionReader The type of reader that handles union alternatives + /// @param _union The Cereal union structure + /// @return A Result containing the variant or an error template rfl::Result read_union(const InputUnionType& _union) const noexcept { try { @@ -149,6 +197,11 @@ struct Reader { } } + /// Uses a custom constructor to create an object from a Cereal archive value. + /// The type T must provide a static method T::from_cereal_obj(InputVarType). + /// @tparam T The type to construct + /// @param _var The Cereal archive variable to construct from + /// @return A Result containing the constructed object or an error template rfl::Result use_custom_constructor( const InputVarType& _var) const noexcept { diff --git a/include/rfl/cereal/Writer.hpp b/include/rfl/cereal/Writer.hpp index 84c3d4a0..ee6e6ebb 100644 --- a/include/rfl/cereal/Writer.hpp +++ b/include/rfl/cereal/Writer.hpp @@ -18,6 +18,8 @@ namespace rfl::cereal { +/// Writer for Cereal serialization library integration. +/// Writes data to Cereal's portable binary archive format for cross-platform serialization. class Writer { public: using CerealArchive = ::cereal::PortableBinaryOutputArchive; @@ -38,18 +40,35 @@ class Writer { using OutputUnionType = CerealOutputUnion; using OutputVarType = CerealOutputVar; + /// Constructs a Writer with a Cereal output archive. + /// @param _archive Pointer to the Cereal output archive to write to Writer(CerealArchive* _archive); ~Writer() = default; + /// Creates an array as the root element. + /// Writes the size tag to the archive first. + /// @param _size The number of elements in the array + /// @return An OutputArrayType OutputArrayType array_as_root(const size_t _size) const; + /// Creates a map as the root element. + /// Writes the size tag to the archive first. + /// @param _size The number of entries in the map + /// @return An OutputMapType OutputMapType map_as_root(const size_t _size) const; + /// Creates an object as the root element. + /// @param _size The number of fields in the object + /// @return An OutputObjectType OutputObjectType object_as_root(const size_t _size) const; + /// Creates a union as the root element. + /// @return An OutputUnionType OutputUnionType union_as_root() const; + /// Creates a null value as the root element. + /// @return An OutputVarType OutputVarType null_as_root() const; template diff --git a/include/rfl/cereal/load.hpp b/include/rfl/cereal/load.hpp index c026375e..357e4411 100644 --- a/include/rfl/cereal/load.hpp +++ b/include/rfl/cereal/load.hpp @@ -8,6 +8,12 @@ namespace rfl { namespace cereal { +/// Loads and parses an object from a file using Cereal serialization. +/// Reads the file as binary data and deserializes it using Cereal's portable binary archive. +/// @tparam T The type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _fname The path to the file to load +/// @return A Result containing the deserialized object or an error template Result load(const std::string& _fname) { const auto read_bytes = [](const auto& _bytes) { diff --git a/include/rfl/cereal/read.hpp b/include/rfl/cereal/read.hpp index ceca8406..42ed0712 100644 --- a/include/rfl/cereal/read.hpp +++ b/include/rfl/cereal/read.hpp @@ -16,7 +16,12 @@ namespace rfl::cereal { using InputVarType = Reader::InputVarType; -/// Parses an object from a Cereal InputArchive. +/// Parses an object from a Cereal input archive. +/// This allows direct integration with existing Cereal-based code. +/// @tparam T The type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _archive The Cereal input archive to read from +/// @return A Result containing the deserialized object or an error template auto read(Reader::CerealArchive& _archive) { const auto r = Reader(); @@ -24,7 +29,13 @@ auto read(Reader::CerealArchive& _archive) { return Parser>::read(r, var); } -/// Parses an object from Cereal binary format using reflection. +/// Parses an object from raw bytes using Cereal portable binary format. +/// Creates a memory stream and deserializes using Cereal. +/// @tparam T The type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _bytes Pointer to the binary data +/// @param _size Size of the binary data in bytes +/// @return A Result containing the deserialized object or an error template Result> read( const concepts::ByteLike auto* _bytes, const size_t _size) { @@ -38,13 +49,21 @@ Result> read( } } -/// Parses an object from Cereal binary format using reflection. +/// Parses an object from a byte container using Cereal portable binary format. +/// @tparam T The type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _bytes A contiguous container containing the Cereal binary data +/// @return A Result containing the deserialized object or an error template auto read(const concepts::ContiguousByteContainer auto& _bytes) { return read(_bytes.data(), _bytes.size()); } -/// Parses an object from a stream using Cereal binary format. +/// Parses an object from an input stream using Cereal portable binary format. +/// @tparam T The type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _stream The input stream to read from +/// @return A Result containing the deserialized object or an error template auto read(std::istream& _stream) { try { diff --git a/include/rfl/cereal/save.hpp b/include/rfl/cereal/save.hpp index 09a9f662..9107e0a8 100644 --- a/include/rfl/cereal/save.hpp +++ b/include/rfl/cereal/save.hpp @@ -10,6 +10,12 @@ namespace rfl { namespace cereal { +/// Saves an object to a file using Cereal portable binary format. +/// Serializes the object and writes it to the specified file path. +/// @tparam Ps Optional processors to apply during serialization +/// @param _fname The path to the file to save to +/// @param _obj The object to serialize +/// @return A Result containing Nothing on success or an error template Result save(const std::string& _fname, const auto& _obj) { const auto write_func = [](const auto& _obj, auto& _stream) -> auto& { diff --git a/include/rfl/cereal/write.hpp b/include/rfl/cereal/write.hpp index d219031e..b704f270 100644 --- a/include/rfl/cereal/write.hpp +++ b/include/rfl/cereal/write.hpp @@ -12,7 +12,12 @@ namespace rfl::cereal { -/// Writes an object to a Cereal OutputArchive. +/// Writes an object directly to a Cereal output archive. +/// This allows integration with existing Cereal-based code. +/// @tparam T The type of object to serialize +/// @tparam Ps Optional processors to apply during serialization +/// @param _obj The object to serialize +/// @param _archive The Cereal output archive to write to template void write(const T& _obj, Writer::CerealArchive& _archive) { using ParentType = parsing::Parent; @@ -20,7 +25,10 @@ void write(const T& _obj, Writer::CerealArchive& _archive) { Parser>::write(w, _obj, typename ParentType::Root{}); } -/// Returns Cereal binary bytes. +/// Serializes an object to bytes using Cereal portable binary format. +/// @tparam Ps Optional processors to apply during serialization +/// @param _obj The object to serialize +/// @return A vector of bytes containing the serialized data template std::vector write(const auto& _obj) { std::stringstream ss; @@ -32,7 +40,11 @@ std::vector write(const auto& _obj) { return std::vector(str.begin(), str.end()); } -/// Writes Cereal binary format into an ostream. +/// Writes an object to an output stream using Cereal portable binary format. +/// @tparam Ps Optional processors to apply during serialization +/// @param _obj The object to serialize +/// @param _stream The output stream to write to +/// @return The output stream (for chaining) template std::ostream& write(const auto& _obj, std::ostream& _stream) { ::cereal::PortableBinaryOutputArchive archive(_stream); diff --git a/include/rfl/cli/Reader.hpp b/include/rfl/cli/Reader.hpp index 0ff04b37..1d46e5d6 100644 --- a/include/rfl/cli/Reader.hpp +++ b/include/rfl/cli/Reader.hpp @@ -18,26 +18,43 @@ namespace rfl::cli { +/// Character used to separate nested field names in CLI arguments. +/// Example: `--database.host` for nested field `database::host`. static constexpr char path_separator = '.'; + +/// Character used to delimit array elements in CLI argument values. +/// Example: `--ports=8080,8081,8082` for an array of ports. static constexpr char array_delimiter = ','; +/// Represents a CLI variable that can be a direct value or a path in the argument map. +/// The `path` represents the hierarchical key (e.g., "database.host"). +/// The `direct_value` is used when parsing array elements directly. struct CliVarType { const std::map* const args = nullptr; const std::string path; const std::optional direct_value; }; +/// Represents a CLI object with a prefix path for accessing nested fields. +/// All child fields will be prefixed with this path. struct CliObjectType { const std::map* const args = nullptr; const std::string prefix; }; +/// Represents a CLI array containing multiple string values. +/// Typically created by splitting a comma-delimited argument value. struct CliArrayType { const std::vector values; }; // --- Constrained overloads for string-to-type parsing --- +/// Parses a string value to std::string (identity function). +/// @tparam T Must be std::string +/// @param _str The string to parse +/// @param _path The CLI argument path (unused for strings) +/// @return The string unchanged template requires std::same_as rfl::Result parse_value( const std::string& _str, const std::string& @@ -45,6 +62,12 @@ rfl::Result parse_value( return _str; } +/// Parses a string value to boolean. +/// Accepts: empty/"true"/"1" → true, "false"/"0" → false. +/// @tparam T Must be bool +/// @param _str The string to parse +/// @param _path The CLI argument path (for error messages) +/// @return A Result containing the boolean value or an error template requires std::same_as rfl::Result parse_value( const std::string& _str, const std::string& _path @@ -59,6 +82,12 @@ rfl::Result parse_value( "Could not cast '" + _str + "' to boolean for key '" + _path + "'."); } +/// Parses a string value to a floating-point number. +/// Uses locale-independent parsing (C locale) to ensure "3.14" works consistently. +/// @tparam T Must be a floating-point type (float, double, long double) +/// @param _str The string to parse +/// @param _path The CLI argument path (for error messages) +/// @return A Result containing the parsed number or an error // std::from_chars for float/double is unavailable in Apple libc++. // std::strtod depends on the C locale (LC_NUMERIC), so "3.14" can fail // under locales that use comma as decimal separator. @@ -84,6 +113,12 @@ rfl::Result parse_value( return static_cast(value); } +/// Parses a string value to an integral type (excluding bool). +/// Uses std::from_chars for efficient and locale-independent parsing. +/// @tparam T Must be an integral type other than bool +/// @param _str The string to parse +/// @param _path The CLI argument path (for error messages) +/// @return A Result containing the parsed integer or an error template requires (std::is_integral_v && !std::same_as) rfl::Result parse_value( const std::string& _str, const std::string& _path @@ -98,6 +133,9 @@ rfl::Result parse_value( return value; } +/// Reader for command-line interface arguments. +/// Parses hierarchical key-value pairs from CLI arguments (e.g., --database.host=localhost). +/// Supports arrays through comma-delimited values (e.g., --ports=8080,8081). struct Reader { using InputArrayType = CliArrayType; using InputObjectType = CliObjectType; @@ -106,6 +144,10 @@ struct Reader { template static constexpr bool has_custom_constructor = false; + /// Gets a specific element from a CLI array by index. + /// @param _idx The index of the element to retrieve + /// @param _arr The CLI array + /// @return A Result containing the element as a CliVarType or an error if out of bounds rfl::Result get_field_from_array( const size_t _idx, const InputArrayType& _arr) const noexcept { if (_idx >= _arr.values.size()) { @@ -115,6 +157,11 @@ struct Reader { return InputVarType{nullptr, "", _arr.values[_idx]}; } + /// Gets a specific field from a CLI object by name. + /// Constructs a child path by appending the field name to the object's prefix. + /// @param _name The field name + /// @param _obj The CLI object + /// @return A Result containing a CliVarType for accessing the field rfl::Result get_field_from_object( const std::string& _name, const InputObjectType& _obj) const noexcept { const auto child_path = _obj.prefix.empty() @@ -123,6 +170,10 @@ struct Reader { return InputVarType{_obj.args, child_path, std::nullopt}; } + /// Checks if a CLI variable is empty (has no value). + /// A variable is empty if there's no direct value and no matching key in the argument map. + /// @param _var The CLI variable to check + /// @return true if the variable is empty, false otherwise bool is_empty(const InputVarType& _var) const noexcept { if (_var.direct_value) { return false; @@ -139,6 +190,11 @@ struct Reader { || it->first.substr(0, prefix.size()) != prefix; } + /// Reads all elements from a CLI array using the provided array reader. + /// @tparam ArrayReader The type of reader that processes individual array elements + /// @param _array_reader The reader object that processes each element + /// @param _arr The CLI array to read from + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_array( const ArrayReader& _array_reader, @@ -154,6 +210,12 @@ struct Reader { return std::nullopt; } + /// Reads all fields from a CLI object using the provided object reader. + /// Iterates through all arguments with the object's prefix and extracts child field names. + /// @tparam ObjectReader The type of reader that processes individual object fields + /// @param _object_reader The reader object that processes each field + /// @param _obj The CLI object to read from + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_object( const ObjectReader& _object_reader, @@ -185,6 +247,10 @@ struct Reader { return std::nullopt; } + /// Converts a CLI variable to a basic C++ type by parsing the string value. + /// @tparam T The target type to convert to + /// @param _var The CLI variable containing the string value + /// @return A Result containing the converted value or an error template rfl::Result to_basic_type(const InputVarType& _var) const noexcept { const auto str = get_value(_var); @@ -194,6 +260,9 @@ struct Reader { return parse_value(*str, _var.path); } + /// Converts a CLI variable to an array by splitting the value on commas. + /// @param _var The CLI variable containing a comma-delimited string + /// @return A Result containing a CliArrayType with the split values rfl::Result to_array( const InputVarType& _var) const noexcept { const auto str = get_value(_var); @@ -203,6 +272,10 @@ struct Reader { return InputArrayType{split(*str, array_delimiter)}; } + /// Converts a CLI variable to an object for reading nested fields. + /// Creates a CliObjectType with an appropriate prefix for child field access. + /// @param _var The CLI variable representing the object + /// @return A Result containing a CliObjectType or an error rfl::Result to_object( const InputVarType& _var) const noexcept { if (!_var.args) { @@ -217,6 +290,10 @@ struct Reader { return InputObjectType{_var.args, prefix}; } + /// Custom constructors are not supported for CLI parsing. + /// @tparam T The type to construct (unused) + /// @param _var The CLI variable (unused) + /// @return Always returns an error template rfl::Result use_custom_constructor( const InputVarType& diff --git a/include/rfl/cli/parse_argv.hpp b/include/rfl/cli/parse_argv.hpp index a8b0d13a..721a6819 100644 --- a/include/rfl/cli/parse_argv.hpp +++ b/include/rfl/cli/parse_argv.hpp @@ -15,6 +15,9 @@ namespace rfl::cli { /// Returns true if the token looks like a CLI option (starts with '-' /// followed by a letter), as opposed to a negative number like "-42". +/// This helps distinguish option flags from negative numeric values. +/// @param _token The command-line token to check +/// @return true if it looks like an option, false otherwise inline bool looks_like_option(std::string_view _token) noexcept { return _token.size() >= 2 && _token[0] == '-' @@ -22,7 +25,15 @@ inline bool looks_like_option(std::string_view _token) noexcept { && _token[1] != '.'; } -/// Parses command-line arguments into categorized buckets: +/// Parses command-line arguments into categorized buckets. +/// Handles three types of arguments: +/// - Long options: --key=value or --flag (stored in `named`) +/// - Short options: -x value, -x=value, or -x (stored in `short_args`) +/// - Positional arguments: bare arguments not prefixed with dashes (stored in `positional`) +/// The special argument "--" forces all subsequent arguments to be treated as positional. +/// @param argc Number of command-line arguments +/// @param argv Array of command-line argument strings +/// @return A Result containing ParsedArgs with categorized arguments or an error /// --key=value / --flag → named /// -x value / -x=value / -x → short_args /// bare arguments → positional diff --git a/include/rfl/cli/read.hpp b/include/rfl/cli/read.hpp index e9211b96..f2a7c585 100644 --- a/include/rfl/cli/read.hpp +++ b/include/rfl/cli/read.hpp @@ -11,8 +11,15 @@ namespace rfl::cli { /// Parses command-line arguments into a struct using reflection. -/// Field names are automatically converted from snake_case to kebab-case. -/// Example: struct field `host_name` matches CLI argument `--host-name`. +/// Field names are automatically converted from snake_case to kebab-case for CLI arguments. +/// For example, a struct field named `host_name` will match the CLI argument `--host-name`. +/// Supports nested objects (e.g., --database.host), arrays (e.g., --ports=8080,8081), +/// positional arguments, and short flags. +/// @tparam T The struct type to parse into +/// @tparam Ps Optional processors to apply during parsing +/// @param argc Number of command-line arguments +/// @param argv Array of command-line argument strings +/// @return A Result containing the parsed struct or an error template rfl::Result read(int argc, char* argv[]) { using ProcessorsType = Processors; diff --git a/include/rfl/cli/resolve_args.hpp b/include/rfl/cli/resolve_args.hpp index 549f71c2..9f3d1b50 100644 --- a/include/rfl/cli/resolve_args.hpp +++ b/include/rfl/cli/resolve_args.hpp @@ -13,6 +13,8 @@ namespace rfl::cli { +/// Holds the parsed command-line arguments categorized by type. +/// Used as an intermediate structure before resolving to a flat key-value map. struct ParsedArgs { std::map named; std::map short_args; @@ -150,6 +152,15 @@ void collect_short_bool_names( /// Resolves ParsedArgs into a flat key-value map using compile-time /// metadata from the target struct T. +/// This function: +/// 1. Maps positional arguments to their corresponding field names based on declaration order +/// 2. Expands short arguments (e.g., -p) to long names (e.g., --port) using Short<> annotations +/// 3. Handles special cases like boolean short flags that don't consume values +/// 4. Detects conflicts between different ways of specifying the same field +/// @tparam T The target struct type +/// @tparam ProcessorsType The processors applied to the struct +/// @param _parsed The parsed command-line arguments +/// @return A Result containing a flat map of field names to values or an error template rfl::Result> resolve_args( ParsedArgs _parsed diff --git a/include/rfl/comparisons.hpp b/include/rfl/comparisons.hpp index 2dfb4674..1233f2f0 100644 --- a/include/rfl/comparisons.hpp +++ b/include/rfl/comparisons.hpp @@ -11,6 +11,13 @@ namespace rfl { template struct EqualTo { + /// @brief Validates that the given value is equal to the threshold. + /// @tparam T The type of the value to validate. + /// @param _value The value to validate. + /// @return Result containing the value if valid, or an error if not. + /// @details This function checks if the input value is exactly equal to the + /// compile-time threshold. If not, it returns an error with a descriptive + /// message. template static Result validate(T _value) noexcept { constexpr auto threshold = static_cast(_threshold); @@ -23,6 +30,12 @@ struct EqualTo { return _value; } + /// @brief Converts the validation rule to a schema representation. + /// @tparam T The type for which the schema is generated. + /// @return parsing::schema::ValidationType representing the EqualTo + /// constraint. + /// @details This function creates a schema object that encodes the equality + /// constraint for serialization or documentation purposes. template static parsing::schema::ValidationType to_schema() { using ValidationType = parsing::schema::ValidationType; @@ -36,6 +49,14 @@ struct EqualTo { template struct Minimum { + /// @brief Validates that the given value is greater than or equal to the + /// threshold. + /// @tparam T The type of the value to validate. + /// @param _value The value to validate. + /// @return Result containing the value if valid, or an error if not. + /// @details This function checks if the input value is at least the + /// compile-time threshold. If not, it returns an error with a descriptive + /// message. template static Result validate(T _value) noexcept { constexpr auto threshold = static_cast(_threshold); @@ -48,6 +69,12 @@ struct Minimum { return _value; } + /// @brief Converts the validation rule to a schema representation. + /// @tparam T The type for which the schema is generated. + /// @return parsing::schema::ValidationType representing the Minimum + /// constraint. + /// @details This function creates a schema object that encodes the minimum + /// value constraint for serialization or documentation purposes. template static parsing::schema::ValidationType to_schema() { using ValidationType = parsing::schema::ValidationType; @@ -61,6 +88,14 @@ struct Minimum { template struct ExclusiveMinimum { + /// @brief Validates that the given value is strictly greater than the + /// threshold. + /// @tparam T The type of the value to validate. + /// @param _value The value to validate. + /// @return Result containing the value if valid, or an error if not. + /// @details This function checks if the input value is strictly greater than + /// the compile-time threshold. If not, it returns an error with a descriptive + /// message. template static Result validate(T _value) noexcept { constexpr auto threshold = static_cast(_threshold); @@ -73,6 +108,12 @@ struct ExclusiveMinimum { return _value; } + /// @brief Converts the validation rule to a schema representation. + /// @tparam T The type for which the schema is generated. + /// @return parsing::schema::ValidationType representing the ExclusiveMinimum + /// constraint. + /// @details This function creates a schema object that encodes the exclusive + /// minimum value constraint for serialization or documentation purposes. template static parsing::schema::ValidationType to_schema() { using ValidationType = parsing::schema::ValidationType; @@ -86,6 +127,14 @@ struct ExclusiveMinimum { template struct Maximum { + /// @brief Validates that the given value is less than or equal to the + /// threshold. + /// @tparam T The type of the value to validate. + /// @param _value The value to validate. + /// @return Result containing the value if valid, or an error if not. + /// @details This function checks if the input value is at most the + /// compile-time threshold. If not, it returns an error with a descriptive + /// message. template static Result validate(T _value) noexcept { constexpr auto threshold = static_cast(_threshold); @@ -98,6 +147,12 @@ struct Maximum { return _value; } + /// @brief Converts the validation rule to a schema representation. + /// @tparam T The type for which the schema is generated. + /// @return parsing::schema::ValidationType representing the Maximum + /// constraint. + /// @details This function creates a schema object that encodes the maximum + /// value constraint for serialization or documentation purposes. template static parsing::schema::ValidationType to_schema() { using ValidationType = parsing::schema::ValidationType; @@ -111,6 +166,13 @@ struct Maximum { template struct ExclusiveMaximum { + /// @brief Validates that the given value is strictly less than the threshold. + /// @tparam T The type of the value to validate. + /// @param _value The value to validate. + /// @return Result containing the value if valid, or an error if not. + /// @details This function checks if the input value is strictly less than the + /// compile-time threshold. If not, it returns an error with a descriptive + /// message. template static Result validate(T _value) noexcept { constexpr auto threshold = static_cast(_threshold); @@ -123,6 +185,12 @@ struct ExclusiveMaximum { return _value; } + /// @brief Converts the validation rule to a schema representation. + /// @tparam T The type for which the schema is generated. + /// @return parsing::schema::ValidationType representing the ExclusiveMaximum + /// constraint. + /// @details This function creates a schema object that encodes the exclusive + /// maximum value constraint for serialization or documentation purposes. template static parsing::schema::ValidationType to_schema() { using ValidationType = parsing::schema::ValidationType; @@ -136,6 +204,13 @@ struct ExclusiveMaximum { template struct NotEqualTo { + /// @brief Validates that the given value is not equal to the threshold. + /// @tparam T The type of the value to validate. + /// @param _value The value to validate. + /// @return Result containing the value if valid, or an error if not. + /// @details This function checks if the input value is not equal to the + /// compile-time threshold. If it is, it returns an error with a descriptive + /// message. template static Result validate(T _value) noexcept { constexpr auto threshold = static_cast(_threshold); @@ -148,6 +223,12 @@ struct NotEqualTo { return _value; } + /// @brief Converts the validation rule to a schema representation. + /// @tparam T The type for which the schema is generated. + /// @return parsing::schema::ValidationType representing the NotEqualTo + /// constraint. + /// @details This function creates a schema object that encodes the + /// not-equal-to constraint for serialization or documentation purposes. template static parsing::schema::ValidationType to_schema() { using ValidationType = parsing::schema::ValidationType; diff --git a/include/rfl/csv/load.hpp b/include/rfl/csv/load.hpp index a000070e..9a54eb38 100644 --- a/include/rfl/csv/load.hpp +++ b/include/rfl/csv/load.hpp @@ -8,6 +8,14 @@ namespace rfl::csv { +/// Loads an array of objects from a CSV file. +/// Reads a text file from disk and parses its CSV content into an array of C++ objects using compile-time reflection. +/// CSV (Comma-Separated Values) is a text format for tabular data, where each row represents an object. +/// @tparam T The type to parse into (must be an array of structs) +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _fname The filename/path of the CSV file to load +/// @param _settings Optional CSV parsing settings (delimiter, quoting, etc.) +/// @return Result containing either an array of parsed objects or an error message template Result load(const std::string& _fname, const Settings& _settings = Settings{}) { diff --git a/include/rfl/csv/read.hpp b/include/rfl/csv/read.hpp index 58d9f629..4e6fff4b 100644 --- a/include/rfl/csv/read.hpp +++ b/include/rfl/csv/read.hpp @@ -17,7 +17,16 @@ namespace rfl::csv { -/// Parses an object from CSV using reflection. +/// Parses an object from CSV bytes using reflection (with raw pointer and size). +/// CSV (Comma-Separated Values) is a text format for tabular data where each line represents a row. +/// Uses Apache Arrow for efficient CSV parsing. The input must be an array of structs, where each +/// struct becomes a row and each field becomes a column. +/// @tparam T The type to parse into (must be an array of structs) +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _str Pointer to CSV text data +/// @param _size The size of the CSV data in bytes +/// @param _settings Optional CSV parsing settings (delimiter, quoting, etc.) +/// @return Result containing either an array of parsed objects or an error message template Result> read( const char* _str, const size_t _size, @@ -71,13 +80,24 @@ Result> read( [](const auto& _r) { return _r.read(); }); } -/// Parses an object from CSV using reflection. +/// Parses an object from CSV using reflection (string_view version). +/// @tparam T The type to parse into (must be an array of structs) +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _str The CSV string to parse +/// @param _settings Optional CSV parsing settings (delimiter, quoting, etc.) +/// @return Result containing either an array of parsed objects or an error message template auto read(const std::string_view _str, const Settings& _settings = Settings{}) { return read(_str.data(), _str.size(), _settings); } -/// Parses an object from a stream. +/// Parses an object from a stream containing CSV data. +/// Reads CSV text from the stream and constructs an array of C++ objects. +/// @tparam T The type to parse into (must be an array of structs) +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _stream The input stream containing CSV text +/// @param _settings Optional CSV parsing settings (delimiter, quoting, etc.) +/// @return Result containing either an array of parsed objects or an error message template auto read(std::istream& _stream, const Settings& _settings = Settings{}) { std::istreambuf_iterator begin(_stream), end; diff --git a/include/rfl/csv/save.hpp b/include/rfl/csv/save.hpp index 3cc5709d..cb1ade5f 100644 --- a/include/rfl/csv/save.hpp +++ b/include/rfl/csv/save.hpp @@ -10,6 +10,14 @@ namespace rfl::csv { +/// Saves an array of objects to a CSV file. +/// Serializes an array of C++ objects to CSV text format and writes it to a file using compile-time reflection. +/// CSV (Comma-Separated Values) is a text format for tabular data, where each row represents an object. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _fname The filename/path where the CSV file will be saved +/// @param _obj The array of objects to serialize to CSV +/// @param _settings Optional CSV writing settings (delimiter, quoting style, etc.) +/// @return Result containing Nothing on success or an error message on failure template Result save(const std::string& _fname, const auto& _obj, const Settings& _settings = Settings{}) { diff --git a/include/rfl/csv/write.hpp b/include/rfl/csv/write.hpp index ed47d9c9..9060566b 100644 --- a/include/rfl/csv/write.hpp +++ b/include/rfl/csv/write.hpp @@ -17,7 +17,14 @@ namespace rfl::csv { -/// Returns CSV bytes. +/// Converts an array of objects to CSV and returns an Arrow buffer. +/// CSV (Comma-Separated Values) is a text format for tabular data where each line represents a row. +/// Uses Apache Arrow for efficient CSV generation. Each struct in the array becomes a row, +/// and each field becomes a column. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _arr The array of objects to serialize to CSV +/// @param _settings CSV writing settings (delimiter, quoting style, batch size, etc.) +/// @return A reference-counted Arrow buffer containing the CSV text template Ref to_buffer(const auto& _arr, const Settings& _settings) { using T = std::remove_cvref_t; @@ -56,7 +63,13 @@ Ref to_buffer(const auto& _arr, const Settings& _settings) { return Ref::make(buffer.ValueOrDie()).value(); } -/// Returns CSV bytes. +/// Writes an array of objects to CSV format. +/// Uses compile-time reflection to serialize an array of C++ objects to CSV format. +/// Each struct in the array becomes a row, and each field becomes a column with a header. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _arr The array of objects to serialize to CSV +/// @param _settings Optional CSV writing settings (delimiter, quoting style, etc.) +/// @return A string containing the CSV representation template std::string write(const auto& _arr, const Settings& _settings = Settings{}) { const auto buffer = to_buffer(_arr, _settings); @@ -64,7 +77,13 @@ std::string write(const auto& _arr, const Settings& _settings = Settings{}) { return std::string(view); } -/// Writes a CSV into an ostream. +/// Writes a CSV representation into an ostream. +/// Uses compile-time reflection to serialize an array of C++ objects to CSV and write to a stream. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _arr The array of objects to serialize to CSV +/// @param _stream The output stream to write CSV text to +/// @param _settings Optional CSV writing settings (delimiter, quoting style, etc.) +/// @return The output stream (for chaining) template std::ostream& write(const auto& _arr, std::ostream& _stream, const Settings& _settings = Settings{}) { diff --git a/include/rfl/default.hpp b/include/rfl/default.hpp index fa6b1df1..752d1edf 100644 --- a/include/rfl/default.hpp +++ b/include/rfl/default.hpp @@ -3,10 +3,12 @@ namespace rfl { -/// Helper class that can be passed to a field -/// to trigger the default value of the type. +/// Helper class that can be passed to a field to trigger the default value of the type. +/// Used as a sentinel value to indicate that the default-constructed value should be used. struct Default {}; +/// Convenience constant for the Default type. +/// Can be used like: MyField field = rfl::default_value; inline static const auto default_value = Default{}; } // namespace rfl diff --git a/include/rfl/define_literal.hpp b/include/rfl/define_literal.hpp index 27f62a8c..cc559cf4 100644 --- a/include/rfl/define_literal.hpp +++ b/include/rfl/define_literal.hpp @@ -6,7 +6,11 @@ namespace rfl { -/// Allows you to combine several literal types. +/// Combines several Literal types into a single union Literal type. +/// This is useful when you want to create a Literal that accepts values from multiple +/// different Literal types. For example, combining Literal<"A", "B"> and Literal<"C", "D"> +/// results in Literal<"A", "B", "C", "D">. +/// @tparam LiteralTypes The Literal types to combine into a single union type template using define_literal_t = typename internal::define_literal::type; diff --git a/include/rfl/define_named_tuple.hpp b/include/rfl/define_named_tuple.hpp index 81340c34..86cbb079 100644 --- a/include/rfl/define_named_tuple.hpp +++ b/include/rfl/define_named_tuple.hpp @@ -6,6 +6,11 @@ namespace rfl { +/// Combines several Field types into a NamedTuple type. +/// This is a type alias for creating NamedTuple types from a list of Field types. +/// A NamedTuple is like a struct but with compile-time field name reflection and runtime access. +/// Example: define_named_tuple_t, Field<"y", double>> creates a NamedTuple with fields x and y. +/// @tparam FieldTypes The Field types that will make up the NamedTuple template using define_named_tuple_t = typename internal::define_named_tuple::type; diff --git a/include/rfl/define_tagged_union.hpp b/include/rfl/define_tagged_union.hpp index 735e693b..fd5f6c77 100644 --- a/include/rfl/define_tagged_union.hpp +++ b/include/rfl/define_tagged_union.hpp @@ -7,6 +7,14 @@ namespace rfl { +/// Defines a tagged union type by combining multiple variant types into a +/// single std::variant. Each alternative from the provided variant types is +/// included in the resulting union variant. For example, combining +/// std::variant and std::variant produces +/// std::variant. +/// @tparam _discriminator A string literal used to distinguish this tagged +/// union type +/// @tparam TaggedUnionTypes The variant types to merge into the tagged union template using define_tagged_union_t = typename internal::define_tagged_union<_discriminator, diff --git a/include/rfl/define_variant.hpp b/include/rfl/define_variant.hpp index 161a75ee..ab3fb169 100644 --- a/include/rfl/define_variant.hpp +++ b/include/rfl/define_variant.hpp @@ -7,6 +7,11 @@ namespace rfl { +/// Combines several variant types into a single union variant type. +/// This merges multiple std::variant types into one variant containing all the alternatives. +/// For example, combining std::variant and std::variant +/// results in std::variant. +/// @tparam Vars The variant types to combine into a single union variant type template using define_variant_t = typename internal::define_variant::type; diff --git a/include/rfl/field_names_t.hpp b/include/rfl/field_names_t.hpp index b37eebbf..c30ddc58 100644 --- a/include/rfl/field_names_t.hpp +++ b/include/rfl/field_names_t.hpp @@ -9,6 +9,9 @@ namespace rfl { /// Returns a rfl::Literal containing the field names of struct T. +/// The literal contains all field names as compile-time strings that can be used +/// for iteration, validation, or other metaprogramming tasks. +/// @tparam T The struct type to extract field names from template using field_names_t = typename std::invoke_result< decltype(internal::get_field_names>)>::type; diff --git a/include/rfl/flexbuf/load.hpp b/include/rfl/flexbuf/load.hpp index ec0a4e72..343967b4 100644 --- a/include/rfl/flexbuf/load.hpp +++ b/include/rfl/flexbuf/load.hpp @@ -8,6 +8,13 @@ namespace rfl { namespace flexbuf { +/// Loads an object from a FlexBuffers file. +/// Reads a binary file from disk and parses its FlexBuffers content into a C++ object using compile-time reflection. +/// FlexBuffers is a schema-less binary format from Google's FlatBuffers project. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _fname The filename/path of the FlexBuffers file to load +/// @return Result containing either the parsed object of type T or an error message template Result load(const std::string& _fname) { const auto read_bytes = [](const auto& _bytes) { diff --git a/include/rfl/flexbuf/read.hpp b/include/rfl/flexbuf/read.hpp index 4a87952c..5021ea1b 100644 --- a/include/rfl/flexbuf/read.hpp +++ b/include/rfl/flexbuf/read.hpp @@ -17,14 +17,27 @@ namespace flexbuf { using InputVarType = typename Reader::InputVarType; -/// Parses an object from flexbuf var. +/// Parses an object from a FlexBuffers var (internal FlexBuffers reference). +/// FlexBuffers is a schema-less binary format from Google's FlatBuffers project. +/// A FlexBuffers var is the internal reference type used by the flexbuffers library. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _obj The FlexBuffers reference object to parse from +/// @return The parsed object of type T template auto read(const InputVarType& _obj) { const auto r = Reader(); return Parser>::read(r, _obj); } -/// Parses an object from flexbuf using reflection. +/// Parses an object from FlexBuffers bytes using reflection. +/// FlexBuffers is a schema-less, self-describing binary format that supports dynamic typing. +/// It's part of Google's FlatBuffers project and is more flexible than regular FlatBuffers. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _bytes Pointer to byte-like data containing FlexBuffers +/// @param _size The size of the byte array +/// @return The parsed object of type T template auto read(const concepts::ByteLike auto* _bytes, const size_t _size) { const InputVarType root = @@ -32,13 +45,22 @@ auto read(const concepts::ByteLike auto* _bytes, const size_t _size) { return read(root); } -/// Parses an object from flexbuf using reflection. +/// Parses an object from FlexBuffers using reflection (contiguous container version). +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _bytes A contiguous byte container (e.g., std::vector, std::string) containing FlexBuffers data +/// @return The parsed object of type T template auto read(const concepts::ContiguousByteContainer auto& _bytes) { return read(_bytes.data(), _bytes.size()); } -/// Parses an object directly from a stream. +/// Parses an object from a stream containing FlexBuffers data. +/// Reads FlexBuffers binary data from the stream and constructs a C++ object. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _stream The input stream containing FlexBuffers binary data +/// @return The parsed object of type T template auto read(std::istream& _stream) { std::istreambuf_iterator begin(_stream), end; diff --git a/include/rfl/flexbuf/save.hpp b/include/rfl/flexbuf/save.hpp index 9cd0a645..c9d3f654 100644 --- a/include/rfl/flexbuf/save.hpp +++ b/include/rfl/flexbuf/save.hpp @@ -10,6 +10,13 @@ namespace rfl { namespace flexbuf { +/// Saves an object to a FlexBuffers file. +/// Serializes a C++ object to FlexBuffers binary format and writes it to a file using compile-time reflection. +/// FlexBuffers is a schema-less binary format from Google's FlatBuffers project. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _fname The filename/path where the FlexBuffers file will be saved +/// @param _obj The object to serialize to FlexBuffers +/// @return Result containing Nothing on success or an error message on failure template Result save(const std::string& _fname, const auto& _obj) { const auto write_func = [](const auto& _obj, auto& _stream) -> auto& { diff --git a/include/rfl/flexbuf/write.hpp b/include/rfl/flexbuf/write.hpp index aa52d18c..22dd829b 100644 --- a/include/rfl/flexbuf/write.hpp +++ b/include/rfl/flexbuf/write.hpp @@ -15,6 +15,11 @@ namespace rfl { namespace flexbuf { +/// Converts an object to FlexBuffers and returns a byte buffer. +/// FlexBuffers is a schema-less binary format from Google's FlatBuffers project. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to FlexBuffers +/// @return A vector of uint8_t containing the FlexBuffers binary representation template std::vector to_buffer(const auto& _obj) { using T = std::remove_cvref_t; @@ -26,7 +31,12 @@ std::vector to_buffer(const auto& _obj) { return fbb->GetBuffer(); } -/// Writes an object to flexbuf. +/// Writes an object to FlexBuffers format. +/// FlexBuffers is a schema-less, self-describing binary format that supports dynamic typing. +/// Uses compile-time reflection to serialize a C++ object to FlexBuffers format. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to FlexBuffers +/// @return A vector of chars containing the FlexBuffers binary representation template std::vector write(const auto& _obj) { const auto buffer = to_buffer(_obj); @@ -34,7 +44,12 @@ std::vector write(const auto& _obj) { return std::vector(data, data + buffer.size()); } -/// Writes an object to an ostream. +/// Writes a FlexBuffers representation into an ostream. +/// Uses compile-time reflection to serialize a C++ object to FlexBuffers and write to a stream. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to FlexBuffers +/// @param _stream The output stream to write FlexBuffers binary data to +/// @return The output stream (for chaining) template std::ostream& write(const auto& _obj, std::ostream& _stream) { const auto buffer = to_buffer(_obj); diff --git a/include/rfl/from_named_tuple.hpp b/include/rfl/from_named_tuple.hpp index 63a29838..f477d0ce 100644 --- a/include/rfl/from_named_tuple.hpp +++ b/include/rfl/from_named_tuple.hpp @@ -12,7 +12,15 @@ namespace rfl { -/// Generates the struct T from a named tuple. +/// Generates the struct T from a named tuple (rvalue reference version). +/// This converts a named tuple (tuple-like structure with compile-time string names) +/// back into the original struct type. If the named tuple type doesn't match exactly, +/// it will be converted first. For structs with rfl::Field members, values are moved/copied +/// to the fields; for plain structs, values are used for aggregate initialization. +/// @tparam T The struct type to construct +/// @tparam NamedTupleType The type of the named tuple +/// @param _n The named tuple to convert from (will be moved if rvalue) +/// @return An instance of struct T template auto from_named_tuple(NamedTupleType&& _n) { using RequiredType = std::remove_cvref_t>; @@ -34,7 +42,14 @@ auto from_named_tuple(NamedTupleType&& _n) { } } -/// Generates the struct T from a named tuple. +/// Generates the struct T from a named tuple (const reference version). +/// This converts a named tuple (tuple-like structure with compile-time string names) +/// back into the original struct type. For structs with rfl::Field members, values are copied +/// to the fields; for plain structs, values are used for aggregate initialization. +/// @tparam T The struct type to construct +/// @tparam NamedTupleType The type of the named tuple +/// @param _n The named tuple to convert from (const reference) +/// @return An instance of struct T template auto from_named_tuple(const NamedTupleType& _n) { using RequiredType = std::remove_cvref_t>; diff --git a/include/rfl/generic/Reader.hpp b/include/rfl/generic/Reader.hpp index 27920825..2d6f3240 100644 --- a/include/rfl/generic/Reader.hpp +++ b/include/rfl/generic/Reader.hpp @@ -12,6 +12,9 @@ namespace rfl::generic { +/// Reader for the Generic type - a dynamic, format-agnostic data structure. +/// The Generic type can represent any JSON-like structure (objects, arrays, primitives) +/// without being tied to a specific serialization format. struct Reader { using InputArrayType = Generic::Array; using InputObjectType = Generic::Object; @@ -20,6 +23,10 @@ struct Reader { template static constexpr bool has_custom_constructor = false; + /// Gets a specific element from a Generic array by index. + /// @param _idx The index of the element to retrieve + /// @param _arr The Generic array + /// @return A Result containing the element or an error if out of bounds rfl::Result get_field_from_array( const size_t _idx, const InputArrayType& _arr) const noexcept { if (_idx >= _arr.size()) { @@ -28,15 +35,27 @@ struct Reader { return _arr[_idx]; } + /// Gets a specific field from a Generic object by name. + /// @param _name The field name + /// @param _obj The Generic object + /// @return A Result containing the field value or an error if not found rfl::Result get_field_from_object( const std::string& _name, const InputObjectType& _obj) const noexcept { return _obj.get(_name); } + /// Checks if the Generic value is empty (null). + /// @param _var The Generic value to check + /// @return true if the value is null, false otherwise bool is_empty(const InputVarType& _var) const noexcept { return _var.is_null(); } + /// Converts a Generic value to a basic C++ type. + /// Supports strings, booleans, floating-point numbers, and integers. + /// @tparam T The target C++ type to convert to + /// @param _var The Generic value to convert + /// @return A Result containing the converted value or an error template rfl::Result to_basic_type(const InputVarType& _var) const noexcept { if constexpr (std::is_same, std::string>()) { @@ -59,6 +78,11 @@ struct Reader { } } + /// Reads all elements from a Generic array using the provided array reader. + /// @tparam ArrayReader The type of reader that processes individual array elements + /// @param _array_reader The reader object that processes each element + /// @param _arr The Generic array to read from + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_array(const ArrayReader& _array_reader, const InputArrayType& _arr) const noexcept { @@ -71,6 +95,11 @@ struct Reader { return std::nullopt; } + /// Reads all key-value pairs from a Generic object using the provided object reader. + /// @tparam ObjectReader The type of reader that processes individual object fields + /// @param _object_reader The reader object that processes each field + /// @param _obj The Generic object to read from + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_object(const ObjectReader& _object_reader, const InputObjectType& _obj) const noexcept { @@ -80,16 +109,26 @@ struct Reader { return std::nullopt; } + /// Converts a Generic value to an array type. + /// @param _var The Generic value to convert + /// @return A Result containing a Generic::Array or an error if not an array rfl::Result to_array( const InputVarType& _var) const noexcept { return _var.to_array(); } + /// Converts a Generic value to an object type. + /// @param _var The Generic value to convert + /// @return A Result containing a Generic::Object or an error if not an object rfl::Result to_object( const InputVarType& _var) const noexcept { return _var.to_object(); } + /// Custom constructors are not supported for generic types. + /// @tparam T The type to construct (unused) + /// @param _var The Generic value (unused) + /// @return Always returns an error template rfl::Result use_custom_constructor( const InputVarType /*_var*/) const noexcept { diff --git a/include/rfl/generic/Writer.hpp b/include/rfl/generic/Writer.hpp index d9e8cd81..88e861e7 100644 --- a/include/rfl/generic/Writer.hpp +++ b/include/rfl/generic/Writer.hpp @@ -13,6 +13,10 @@ namespace rfl::generic { +/// Writer for the Generic type - a dynamic, format-agnostic data structure. +/// Constructs Generic values that can be converted to any serialization format. +/// The Generic type provides a common intermediate representation useful for +/// format conversions and dynamic data manipulation. struct RFL_API Writer { struct OutputArray { Generic::Array* val_; @@ -30,28 +34,58 @@ struct RFL_API Writer { ~Writer() = default; + /// Creates an array as the root element of the Generic structure. + /// @param _size The number of elements (hint, not enforced) + /// @return An OutputArrayType that can be populated with elements OutputArrayType array_as_root(const size_t _size) const noexcept; + /// Creates an object as the root element of the Generic structure. + /// @param _size The number of fields (hint, not enforced) + /// @return An OutputObjectType that can be populated with fields OutputObjectType object_as_root(const size_t _size) const noexcept; + /// Creates a null value as the root element. + /// @return A Generic value representing null OutputVarType null_as_root() const noexcept; + /// Creates a primitive value as the root element. + /// @tparam T The type of the value (string, bool, number) + /// @param _var The value to store + /// @return A Generic value wrapping the primitive template OutputVarType value_as_root(const T& _var) const noexcept { root_ = to_generic(_var); return root_; } + /// Adds a nested array to an existing array. + /// @param _size The number of elements (hint, not enforced) + /// @param _parent Pointer to the parent array + /// @return An OutputArrayType for the new nested array OutputArrayType add_array_to_array(const size_t _size, OutputArrayType* _parent) const noexcept; + /// Adds an array to an object field. + /// @param _name The field name for the array + /// @param _size The number of elements (hint, not enforced) + /// @param _parent Pointer to the parent object + /// @return An OutputArrayType for the new array OutputArrayType add_array_to_object(const std::string_view& _name, const size_t _size, OutputObjectType* _parent) const noexcept; + /// Adds a nested object to an existing array. + /// @param _size The number of fields (hint, not enforced) + /// @param _parent Pointer to the parent array + /// @return An OutputObjectType for the new nested object OutputObjectType add_object_to_array(const size_t _size, OutputArrayType* _parent) const noexcept; + /// Adds an object to an object field (nested object). + /// @param _name The field name for the nested object + /// @param _size The number of fields (hint, not enforced) + /// @param _parent Pointer to the parent object + /// @return An OutputObjectType for the new nested object OutputObjectType add_object_to_object( const std::string_view& _name, const size_t _size, OutputObjectType* _parent) const noexcept; @@ -73,15 +107,30 @@ struct RFL_API Writer { return g; } + /// Adds a null value to an array. + /// @param _parent Pointer to the parent array + /// @return A Generic value representing null OutputVarType add_null_to_array(OutputArrayType* _parent) const noexcept; + /// Adds a null value to an object field. + /// @param _name The field name for the null value + /// @param _parent Pointer to the parent object + /// @return A Generic value representing null OutputVarType add_null_to_object(const std::string_view& _name, OutputObjectType* _parent) const noexcept; + /// Finalizes an array after all elements have been added. + /// This is a no-op for Generic but required by the Writer interface. + /// @param _arr Pointer to the array (unused) void end_array(OutputArrayType*) const noexcept {} + /// Finalizes an object after all fields have been added. + /// This is a no-op for Generic but required by the Writer interface. + /// @param _obj Pointer to the object (unused) void end_object(OutputObjectType*) const noexcept {} + /// Gets a reference to the root Generic value being constructed. + /// @return Reference to the root value OutputVarType& root() { return root_; } private: diff --git a/include/rfl/generic/read.hpp b/include/rfl/generic/read.hpp index 0934c8c3..6d1a4c36 100644 --- a/include/rfl/generic/read.hpp +++ b/include/rfl/generic/read.hpp @@ -9,7 +9,13 @@ namespace rfl { namespace generic { -/// Parses an object from a generic type. +/// Parses a C++ object from a Generic value using reflection. +/// This is useful for converting between different serialization formats: +/// format A → Generic → format B, providing format independence. +/// @tparam T The C++ type to deserialize into +/// @tparam Ps Optional processors to apply during deserialization +/// @param _g The Generic value to parse +/// @return A Result containing the deserialized object or an error template auto read(const Generic& _g) { const auto r = Reader(); diff --git a/include/rfl/generic/write.hpp b/include/rfl/generic/write.hpp index 401c6927..f6668ce8 100644 --- a/include/rfl/generic/write.hpp +++ b/include/rfl/generic/write.hpp @@ -8,7 +8,12 @@ namespace rfl { namespace generic { -/// Writes an object to a generic. +/// Converts a C++ object to a Generic value using reflection. +/// The Generic type is a format-agnostic intermediate representation that +/// can be easily converted to any serialization format (JSON, YAML, etc.). +/// @tparam Ps Optional processors to apply during serialization +/// @param _t The object to convert +/// @return A Generic value representing the object's structure and data template Generic write(const auto& _t) { using T = std::remove_cvref_t; diff --git a/include/rfl/json/Reader.hpp b/include/rfl/json/Reader.hpp index 68d8e614..0c2f7ad3 100644 --- a/include/rfl/json/Reader.hpp +++ b/include/rfl/json/Reader.hpp @@ -19,17 +19,27 @@ namespace rfl { namespace json { +/// Reader class for deserializing JSON (JavaScript Object Notation) data. +/// This class provides the interface for parsing JSON format into C++ objects. +/// Uses the yyjson library for high-performance JSON parsing. struct Reader { + /// Represents a JSON array during deserialization. + /// Wraps a pointer to the underlying yyjson value representing the array. struct YYJSONInputArray { YYJSONInputArray(yyjson_val* _val) : val_(_val) {} yyjson_val* val_; }; + /// Represents a JSON object during deserialization. + /// Wraps a pointer to the underlying yyjson value representing the object. struct YYJSONInputObject { YYJSONInputObject(yyjson_val* _val) : val_(_val) {} yyjson_val* val_; }; + /// Represents a variant JSON value during deserialization. + /// Can hold any JSON type (array, object, string, number, boolean, null). + /// Wraps a pointer to the underlying yyjson value. struct YYJSONInputVar { YYJSONInputVar() : val_(nullptr) {} YYJSONInputVar(yyjson_val* _val) : val_(_val) {} @@ -40,10 +50,16 @@ struct Reader { using InputObjectType = YYJSONInputObject; using InputVarType = YYJSONInputVar; + /// Compile-time flag indicating whether type T has a custom constructor from JSON. + /// If true, the type provides a static from_json_obj() method for custom deserialization. template static constexpr bool has_custom_constructor = (requires(InputVarType var) { T::from_json_obj(var); }); + /// Retrieves an element from a JSON array by index. + /// @param _idx The zero-based index of the element to retrieve + /// @param _arr The JSON array to read from + /// @return Result containing the element value, or an error if index is out of bounds rfl::Result get_field_from_array( const size_t _idx, const InputArrayType _arr) const noexcept { const auto var = InputVarType(yyjson_arr_get(_arr.val_, _idx)); @@ -53,6 +69,10 @@ struct Reader { return var; } + /// Retrieves a field from a JSON object by name. + /// @param _name The name of the field to retrieve + /// @param _obj The JSON object to read from + /// @return Result containing the field value, or an error if field is not found rfl::Result get_field_from_object( const std::string& _name, const InputObjectType _obj) const noexcept { const auto var = InputVarType(yyjson_obj_get(_obj.val_, _name.c_str())); @@ -62,10 +82,19 @@ struct Reader { return var; } + /// Checks if a JSON value is empty or null. + /// @param _var The JSON value to check + /// @return true if the value is null or not set, false otherwise bool is_empty(const InputVarType _var) const noexcept { return !_var.val_ || yyjson_is_null(_var.val_); } + /// Reads all elements from a JSON array using a provided array reader. + /// The array reader's read() method is called for each element in the array. + /// @tparam ArrayReader Type that provides a read() method for processing elements + /// @param _array_reader The reader object used to process each array element + /// @param _arr The JSON array to read from + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_array(const ArrayReader& _array_reader, const InputArrayType& _arr) const noexcept { @@ -81,6 +110,12 @@ struct Reader { return std::nullopt; } + /// Reads all key-value pairs from a JSON object using a provided object reader. + /// The object reader's read() method is called for each key-value pair. + /// @tparam ObjectReader Type that provides a read() method for processing key-value pairs + /// @param _object_reader The reader object used to process each field + /// @param _obj The JSON object to read from + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_object(const ObjectReader& _object_reader, const InputObjectType& _obj) const noexcept { @@ -95,6 +130,11 @@ struct Reader { return std::nullopt; } + /// Converts a JSON value to a basic C++ type. + /// Supports strings, booleans, floating-point numbers, and integers (signed/unsigned). + /// @tparam T The target C++ type + /// @param _var The JSON value to convert + /// @return Result containing the converted value, or an error if conversion fails template rfl::Result to_basic_type(const InputVarType _var) const noexcept { if constexpr (std::is_same, std::string>()) { @@ -133,6 +173,9 @@ struct Reader { } } + /// Converts a JSON value to an array. + /// @param _var The JSON value to convert + /// @return Result containing the array, or an error if value is not an array rfl::Result to_array(const InputVarType _var) const noexcept { if (!yyjson_is_arr(_var.val_)) { return error("Could not cast to array!"); @@ -140,6 +183,9 @@ struct Reader { return InputArrayType(_var.val_); } + /// Converts a JSON value to an object. + /// @param _var The JSON value to convert + /// @return Result containing the object, or an error if value is not an object rfl::Result to_object( const InputVarType _var) const noexcept { if (!yyjson_is_obj(_var.val_)) { @@ -148,6 +194,11 @@ struct Reader { return InputObjectType(_var.val_); } + /// Uses a type's custom constructor to deserialize from JSON. + /// Calls the type's static from_json_obj() method for custom deserialization logic. + /// @tparam T The type to construct, must have a from_json_obj() static method + /// @param _var The JSON value to deserialize from + /// @return Result containing the constructed object, or an error if construction fails template rfl::Result use_custom_constructor( const InputVarType _var) const noexcept { diff --git a/include/rfl/json/Writer.hpp b/include/rfl/json/Writer.hpp index 951752db..af2f3a50 100644 --- a/include/rfl/json/Writer.hpp +++ b/include/rfl/json/Writer.hpp @@ -20,18 +20,28 @@ namespace rfl { namespace json { +/// Writer class for serializing C++ objects to JSON (JavaScript Object Notation) format. +/// This class provides the interface for converting C++ objects into JSON text. +/// Uses the yyjson library for high-performance JSON generation. class RFL_API Writer { public: + /// Represents a JSON array being constructed during serialization. + /// Wraps a pointer to the underlying yyjson mutable value representing the array. struct YYJSONOutputArray { YYJSONOutputArray(yyjson_mut_val* _val) : val_(_val) {} yyjson_mut_val* val_; }; + /// Represents a JSON object being constructed during serialization. + /// Wraps a pointer to the underlying yyjson mutable value representing the object. struct YYJSONOutputObject { YYJSONOutputObject(yyjson_mut_val* _val) : val_(_val) {} yyjson_mut_val* val_; }; + /// Represents a JSON value being constructed during serialization. + /// Can be constructed from an array, object, or primitive value. + /// Wraps a pointer to the underlying yyjson mutable value. struct YYJSONOutputVar { YYJSONOutputVar(yyjson_mut_val* _val) : val_(_val) {} @@ -46,18 +56,35 @@ class RFL_API Writer { using OutputObjectType = YYJSONOutputObject; using OutputVarType = YYJSONOutputVar; + /// Constructs a new JSON Writer, initializing a new mutable document. Writer(); ~Writer() = default; + /// Returns the underlying yyjson mutable document. + /// Used internally for document management. + /// @return Pointer to the yyjson mutable document yyjson_mut_doc* doc() const { return doc_.get(); } + /// Creates a JSON array as the root element of the output. + /// @param The expected size (unused, reserved for future optimization) + /// @return An output array that can be populated with elements OutputArrayType array_as_root(const size_t) const noexcept; + /// Creates a JSON object as the root element of the output. + /// @param The expected size (unused, reserved for future optimization) + /// @return An output object that can be populated with key-value pairs OutputObjectType object_as_root(const size_t) const noexcept; + /// Creates a null value as the root element of the output. + /// @return An output variable representing null OutputVarType null_as_root() const noexcept; + /// Creates a value as the root element of the output. + /// Supports basic types like strings, numbers, and booleans. + /// @tparam T The type of the value to serialize + /// @param _var The value to write as the root element + /// @return An output variable representing the serialized value template OutputVarType value_as_root(const T& _var) const noexcept { const auto val = from_basic_type(_var); @@ -65,20 +92,45 @@ class RFL_API Writer { return OutputVarType(val); } + /// Adds a nested array to a parent array. + /// @param The expected size (unused, reserved for future optimization) + /// @param _parent Pointer to the parent array to add to + /// @return An output array that can be populated with elements OutputArrayType add_array_to_array(const size_t, OutputArrayType* _parent) const; + /// Adds a nested array to a parent object with the specified field name. + /// @param _name The name of the field in the parent object + /// @param The expected size (unused, reserved for future optimization) + /// @param _parent Pointer to the parent object to add to + /// @return An output array that can be populated with elements OutputArrayType add_array_to_object(const std::string_view& _name, const size_t, OutputObjectType* _parent) const; + /// Adds a nested object to a parent array. + /// @param The expected size (unused, reserved for future optimization) + /// @param _parent Pointer to the parent array to add to + /// @return An output object that can be populated with key-value pairs OutputObjectType add_object_to_array(const size_t, OutputArrayType* _parent) const; + /// Adds a nested object to a parent object with the specified field name. + /// @param _name The name of the field in the parent object + /// @param The expected size (unused, reserved for future optimization) + /// @param _parent Pointer to the parent object to add to + /// @return An output object that can be populated with key-value pairs OutputObjectType add_object_to_object(const std::string_view& _name, const size_t, OutputObjectType* _parent) const; + /// Adds a value to a parent array. + /// Supports basic types like strings, numbers, and booleans. + /// @tparam T The type of the value to add + /// @param _var The value to add to the array + /// @param _parent Pointer to the parent array to add to + /// @return An output variable representing the added value + /// @throws std::runtime_error if the value cannot be added template OutputVarType add_value_to_array(const T& _var, OutputArrayType* _parent) const { @@ -90,6 +142,14 @@ class RFL_API Writer { return OutputVarType(val); } + /// Adds a value to a parent object with the specified field name. + /// Supports basic types like strings, numbers, and booleans. + /// @tparam T The type of the value to add + /// @param _name The name of the field in the parent object + /// @param _var The value to add to the object + /// @param _parent Pointer to the parent object to add to + /// @return An output variable representing the added value + /// @throws std::runtime_error if the field cannot be added template OutputVarType add_value_to_object(const std::string_view& _name, const T& _var, @@ -104,13 +164,26 @@ class RFL_API Writer { return OutputVarType(val); } + /// Adds a null value to a parent array. + /// @param _parent Pointer to the parent array to add to + /// @return An output variable representing the null value OutputVarType add_null_to_array(OutputArrayType* _parent) const; + /// Adds a null value to a parent object with the specified field name. + /// @param _name The name of the field in the parent object + /// @param _parent Pointer to the parent object to add to + /// @return An output variable representing the null value OutputVarType add_null_to_object(const std::string_view& _name, OutputObjectType* _parent) const; + /// Finalizes a JSON array after all elements have been added. + /// This is a no-op for yyjson as arrays don't need explicit finalization. + /// @param Pointer to the array (unused) void end_array(OutputArrayType*) const noexcept; + /// Finalizes a JSON object after all fields have been added. + /// This is a no-op for yyjson as objects don't need explicit finalization. + /// @param Pointer to the object (unused) void end_object(OutputObjectType*) const noexcept; private: diff --git a/include/rfl/json/load.hpp b/include/rfl/json/load.hpp index 9c8b1223..0bf3b294 100644 --- a/include/rfl/json/load.hpp +++ b/include/rfl/json/load.hpp @@ -8,6 +8,13 @@ namespace rfl { namespace json { +/// Loads an object from a JSON file. +/// Reads a file from disk and parses its JSON content into a C++ object using compile-time reflection. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _fname The filename/path of the JSON file to load +/// @param _flag Optional yyjson flags for parsing (default: 0) +/// @return Result containing either the parsed object of type T or an error message template Result load(const std::string& _fname, const yyjson_read_flag _flag = 0) { const auto read_string = [_flag](const auto& _str) { diff --git a/include/rfl/json/read.hpp b/include/rfl/json/read.hpp index 35396168..ad3e47b1 100644 --- a/include/rfl/json/read.hpp +++ b/include/rfl/json/read.hpp @@ -22,6 +22,11 @@ using InputObjectType = typename Reader::InputObjectType; using InputVarType = typename Reader::InputVarType; /// Parses an object from a JSON var. +/// A JSON var is the internal representation used by the yyjson library. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _obj The JSON variant object to parse from +/// @return Result containing either the parsed object of type T or an error template auto read(const InputVarType& _obj) { const auto r = Reader(); @@ -29,6 +34,12 @@ auto read(const InputVarType& _obj) { } /// Parses an object from JSON using reflection. +/// This function reads a JSON string and constructs a C++ object using compile-time reflection. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _json_str The JSON string to parse +/// @param _flag Optional yyjson flags for parsing (default: 0). Note: YYJSON_READ_INSITU is not supported. +/// @return Result containing either the parsed object (or array of objects) or an error message template Result> read( const std::string_view _json_str, const yyjson_read_flag _flag = 0) { @@ -51,6 +62,12 @@ Result> read( } /// Parses an object from a stringstream. +/// Reads the entire stream content and parses it as JSON. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _stream The input stream containing JSON data +/// @param _flag Optional yyjson flags for parsing (default: 0) +/// @return Result containing either the parsed object (or array of objects) or an error message template auto read(std::istream& _stream, const yyjson_read_flag _flag = 0) { const auto json_str = std::string(std::istreambuf_iterator(_stream), diff --git a/include/rfl/json/save.hpp b/include/rfl/json/save.hpp index 925df88e..33eb2d03 100644 --- a/include/rfl/json/save.hpp +++ b/include/rfl/json/save.hpp @@ -16,6 +16,13 @@ namespace rfl { namespace json { +/// Saves an object to a JSON file. +/// Serializes a C++ object to JSON and writes it to a file using compile-time reflection. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _fname The filename/path where the JSON file will be saved +/// @param _obj The object to serialize to JSON +/// @param _flag Optional yyjson flags for formatting (use `pretty` for pretty-printing, default: 0) +/// @return Result containing Nothing on success or an error message on failure template Result save(const std::string& _fname, const auto& _obj, const yyjson_write_flag _flag = 0) { diff --git a/include/rfl/json/write.hpp b/include/rfl/json/write.hpp index e921eb55..88e762af 100644 --- a/include/rfl/json/write.hpp +++ b/include/rfl/json/write.hpp @@ -22,7 +22,13 @@ namespace json { /// Convenient alias for the YYJSON pretty flag inline constexpr yyjson_write_flag pretty = YYJSON_WRITE_PRETTY; -/// Returns a JSON string. +/// Returns a JSON string representation of the object. +/// Uses compile-time reflection to serialize a C++ object to JSON format. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to JSON +/// @param _flag Optional yyjson flags for formatting (use `pretty` for pretty-printing, default: 0) +/// @return JSON string representation of the object +/// @throws std::runtime_error if serialization fails template std::string write(const auto& _obj, const yyjson_write_flag _flag = 0) { using T = std::remove_cvref_t; @@ -41,7 +47,14 @@ std::string write(const auto& _obj, const yyjson_write_flag _flag = 0) { return json_str; } -/// Writes a JSON into an ostream. +/// Writes a JSON representation into an ostream. +/// Uses compile-time reflection to serialize a C++ object to JSON and write to a stream. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to JSON +/// @param _stream The output stream to write JSON to +/// @param _flag Optional yyjson flags for formatting (use `pretty` for pretty-printing, default: 0) +/// @return The output stream (for chaining) +/// @throws std::runtime_error if serialization fails template std::ostream& write(const auto& _obj, std::ostream& _stream, const yyjson_write_flag _flag = 0) { diff --git a/include/rfl/make_from_tuple.hpp b/include/rfl/make_from_tuple.hpp index f2872d47..24775da3 100644 --- a/include/rfl/make_from_tuple.hpp +++ b/include/rfl/make_from_tuple.hpp @@ -8,12 +8,18 @@ namespace rfl { +/// Constructs an object of type T from a tuple (const reference version). +/// @param _tup The tuple containing the values to construct T with +/// @return A new object of type T constructed from the tuple elements template auto make_from_tuple(const rfl::Tuple& _tup) { return internal::tuple::make_from_tuple( _tup, std::make_integer_sequence()); } +/// Constructs an object of type T from a tuple (rvalue reference version). +/// @param _tup The tuple containing the values to construct T with +/// @return A new object of type T constructed from the tuple elements template auto make_from_tuple(rfl::Tuple&& _tup) { return internal::tuple::make_from_tuple( diff --git a/include/rfl/make_named_tuple.hpp b/include/rfl/make_named_tuple.hpp index aa78ce69..fac9559d 100644 --- a/include/rfl/make_named_tuple.hpp +++ b/include/rfl/make_named_tuple.hpp @@ -7,22 +7,33 @@ namespace rfl { -/// Convenience constructor that doesn't require you -/// to explitly define the field types. +/// Convenience constructor for creating NamedTuples from rvalue Field arguments. +/// Creates a NamedTuple without requiring explicit template parameter specification. +/// The field types are automatically deduced from the arguments. +/// A NamedTuple is like a std::tuple but with compile-time string names for each field. +/// @tparam FieldTypes The Field types (automatically deduced) +/// @param _args The Field objects to include in the NamedTuple (rvalue references) +/// @return A NamedTuple containing the specified fields template inline auto make_named_tuple(FieldTypes&&... _args) { return NamedTuple...>( std::forward(_args)...); } -/// Convenience constructor that doesn't require you -/// to explitly define the field types. +/// Convenience constructor for creating NamedTuples from const Field arguments. +/// Creates a NamedTuple without requiring explicit template parameter specification. +/// The field types are automatically deduced from the arguments. +/// A NamedTuple is like a std::tuple but with compile-time string names for each field. +/// @tparam FieldTypes The Field types (automatically deduced) +/// @param _args The Field objects to include in the NamedTuple (const references) +/// @return A NamedTuple containing the specified fields template inline auto make_named_tuple(const FieldTypes&... _args) { return NamedTuple(_args...); } -/// Explicit overload for creating empty named tuples. +/// Creates an empty NamedTuple with no fields. +/// @return An empty NamedTuple<> inline auto make_named_tuple() { return NamedTuple<>(); } } // namespace rfl diff --git a/include/rfl/msgpack/Reader.hpp b/include/rfl/msgpack/Reader.hpp index 0b332a15..18309e44 100644 --- a/include/rfl/msgpack/Reader.hpp +++ b/include/rfl/msgpack/Reader.hpp @@ -22,10 +22,20 @@ struct Reader { using InputObjectType = msgpack_object_map; using InputVarType = msgpack_object; + /** + * @brief Checks if type T has a custom constructor from a msgpack object. + * @tparam T The type to check. + */ template static constexpr bool has_custom_constructor = (requires(InputVarType var) { T::from_msgpack_obj(var); }); + /** + * @brief Retrieves a field from a msgpack array by index. + * @param _idx The index of the field to retrieve. + * @param _arr The msgpack array. + * @return The field at the given index or an error if out of bounds. + */ rfl::Result get_field_from_array( const size_t _idx, const InputArrayType _arr) const noexcept { if (_idx >= _arr.size) { @@ -34,6 +44,12 @@ struct Reader { return _arr.ptr[_idx]; } + /** + * @brief Retrieves a field from a msgpack object by name. + * @param _name The name of the field to retrieve. + * @param _obj The msgpack object. + * @return The value of the field or an error if not found. + */ rfl::Result get_field_from_object( const std::string& _name, const InputObjectType& _obj) const noexcept { for (uint32_t i = 0; i < _obj.size; ++i) { @@ -51,10 +67,23 @@ struct Reader { return error("No field named '" + _name + "' was found."); } + /** + * @brief Checks if a msgpack object is empty (nil). + * @param _var The msgpack object to check. + * @return True if the object is nil, false otherwise. + */ bool is_empty(const InputVarType& _var) const noexcept { return _var.type == MSGPACK_OBJECT_NIL; } + /** + * @brief Converts a msgpack object to a basic C++ type. + * Basic types include strings, byte containers, booleans, + * floating-point numbers, integers, and literal types (enums). + * @tparam T The target type. + * @param _var The msgpack object to convert. + * @return The converted value or an error if conversion fails. + */ template rfl::Result to_basic_type(const InputVarType& _var) const noexcept { const auto type = _var.type; @@ -105,6 +134,11 @@ struct Reader { } } + /** + * @brief Converts a msgpack object to an array type. + * @param _var The msgpack object to convert. + * @return The array or an error if conversion fails. + */ rfl::Result to_array( const InputVarType& _var) const noexcept { if (_var.type != MSGPACK_OBJECT_ARRAY) { @@ -113,6 +147,11 @@ struct Reader { return _var.via.array; } + /** + * @brief Converts a msgpack object to a map/object type. + * @param _var The msgpack object to convert. + * @return The object or an error if conversion fails. + */ rfl::Result to_object( const InputVarType& _var) const noexcept { if (_var.type != MSGPACK_OBJECT_MAP) { @@ -121,6 +160,13 @@ struct Reader { return _var.via.map; } + /** + * @brief Reads all elements of a msgpack array using a provided reader. + * @tparam ArrayReader The type of the array reader. + * @param _array_reader The reader to use for each element. + * @param _arr The msgpack array to read. + * @return An optional error if any element fails to be read. + */ template std::optional read_array(const ArrayReader& _array_reader, const InputArrayType& _arr) const noexcept { @@ -133,6 +179,13 @@ struct Reader { return std::nullopt; } + /** + * @brief Reads all fields of a msgpack object using a provided reader. + * @tparam ObjectReader The type of the object reader. + * @param _object_reader The reader to use for each field. + * @param _obj The msgpack object to read. + * @return An optional error if any field fails to be read. + */ template std::optional read_object(const ObjectReader& _object_reader, const InputObjectType& _obj) const noexcept { @@ -149,6 +202,12 @@ struct Reader { return std::nullopt; } + /** + * @brief Uses a custom constructor to convert a msgpack object to type T. + * @tparam T The target type. + * @param _var The msgpack object to convert. + * @return The constructed object or an error if construction fails. + */ template rfl::Result use_custom_constructor( const InputVarType& _var) const noexcept { diff --git a/include/rfl/msgpack/load.hpp b/include/rfl/msgpack/load.hpp index 57802571..4aa9abf6 100644 --- a/include/rfl/msgpack/load.hpp +++ b/include/rfl/msgpack/load.hpp @@ -8,6 +8,12 @@ namespace rfl { namespace msgpack { +/// Loads an object from a MSGPACK file. +/// Reads a binary file from disk and parses its MSGPACK content into a C++ object using compile-time reflection. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _fname The filename/path of the MSGPACK file to load +/// @return Result containing either the parsed object of type T or an error message template Result load(const std::string& _fname) { const auto read_bytes = [](const auto& _bytes) { diff --git a/include/rfl/msgpack/read.hpp b/include/rfl/msgpack/read.hpp index 9cff96d1..af51e2bc 100644 --- a/include/rfl/msgpack/read.hpp +++ b/include/rfl/msgpack/read.hpp @@ -18,14 +18,26 @@ namespace msgpack { using InputObjectType = typename Reader::InputObjectType; using InputVarType = typename Reader::InputVarType; -/// Parses an object from a MSGPACK var. +/// Parses an object from a MSGPACK var (internal msgpack object representation). +/// A MSGPACK var is the internal representation used by the msgpack-c library. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _obj The MSGPACK variant object to parse from +/// @return The parsed object of type T template auto read(const InputVarType& _obj) { const auto r = Reader(); return Parser>::read(r, _obj); } -/// Parses an object from MSGPACK using reflection. +/// Parses an object from MSGPACK bytes using reflection. +/// MessagePack is an efficient binary serialization format similar to JSON but more compact. +/// This function reads MessagePack bytes and constructs a C++ object using compile-time reflection. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _bytes Pointer to byte-like data containing MSGPACK +/// @param _size The size of the byte array +/// @return Result containing either the parsed object (or array of objects) or an error message template Result> read( const concepts::ByteLike auto* _bytes, const size_t _size) { @@ -45,13 +57,22 @@ Result> read( return r; } -/// Parses an object from MSGPACK using reflection. +/// Parses an object from MSGPACK using reflection (contiguous container version). +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _bytes A contiguous byte container (e.g., std::vector, std::string) containing MSGPACK data +/// @return Result containing either the parsed object (or array of objects) or an error message template auto read(const concepts::ContiguousByteContainer auto& _bytes) { return read(_bytes.data(), _bytes.size()); } -/// Parses an object from a stream. +/// Parses an object from a stream containing MSGPACK data. +/// Reads MessagePack binary data from the stream and constructs a C++ object. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _stream The input stream containing MSGPACK binary data +/// @return Result containing either the parsed object (or array of objects) or an error message template auto read(std::istream& _stream) { std::istreambuf_iterator begin(_stream), end; diff --git a/include/rfl/msgpack/save.hpp b/include/rfl/msgpack/save.hpp index 3ceaa718..01ecd5b9 100644 --- a/include/rfl/msgpack/save.hpp +++ b/include/rfl/msgpack/save.hpp @@ -10,6 +10,12 @@ namespace rfl { namespace msgpack { +/// Saves an object to a MSGPACK file. +/// Serializes a C++ object to MSGPACK binary format and writes it to a file using compile-time reflection. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _fname The filename/path where the MSGPACK file will be saved +/// @param _obj The object to serialize to MSGPACK +/// @return Result containing Nothing on success or an error message on failure template Result save(const std::string& _fname, const auto& _obj) { const auto write_func = [](const auto& _obj, auto& _stream) -> auto& { diff --git a/include/rfl/msgpack/write.hpp b/include/rfl/msgpack/write.hpp index 08efd2d8..bf036ee1 100644 --- a/include/rfl/msgpack/write.hpp +++ b/include/rfl/msgpack/write.hpp @@ -12,7 +12,12 @@ namespace rfl::msgpack { -/// Returns msgpack bytes. +/// Returns MSGPACK bytes representation of the object. +/// MessagePack is an efficient binary serialization format similar to JSON but more compact. +/// Uses compile-time reflection to serialize a C++ object to MSGPACK format. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to MSGPACK +/// @return A vector of chars containing the MSGPACK binary representation template std::vector write(const auto& _obj) { using T = std::remove_cvref_t; @@ -34,7 +39,12 @@ std::vector write(const auto& _obj) { return bytes.value(); } -/// Writes a MSGPACK into an ostream. +/// Writes a MSGPACK representation into an ostream. +/// Uses compile-time reflection to serialize a C++ object to MSGPACK and write to a stream. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to MSGPACK +/// @param _stream The output stream to write MSGPACK binary data to +/// @return The output stream (for chaining) template std::ostream& write(const auto& _obj, std::ostream& _stream) { auto buffer = write(_obj); diff --git a/include/rfl/num_fields.hpp b/include/rfl/num_fields.hpp index a65c01af..c4f16776 100644 --- a/include/rfl/num_fields.hpp +++ b/include/rfl/num_fields.hpp @@ -5,7 +5,9 @@ namespace rfl { -/// Returns the number of fields fields. +/// Returns the number of fields in struct T at compile time. +/// This uses structured bindings to count the fields. +/// @tparam T The struct type to count fields for template constexpr std::size_t num_fields = internal::num_fields; diff --git a/include/rfl/parquet/load.hpp b/include/rfl/parquet/load.hpp index e8802ab5..8d3e6640 100644 --- a/include/rfl/parquet/load.hpp +++ b/include/rfl/parquet/load.hpp @@ -7,6 +7,18 @@ namespace rfl::parquet { +/** + * @brief Loads an object of type T from a file. + * + * This function reads the contents of the file specified by _fname, + * then attempts to deserialize it into an object of type T using the + * read function. + * + * @tparam T The type to load from the file. + * @tparam Ps Additional template parameters for the read function. + * @param _fname The name of the file to load. + * @return Result The result of loading and deserializing the file contents. + */ template Result load(const std::string& _fname) { const auto read_bytes = [](const auto& _bytes) { diff --git a/include/rfl/parquet/read.hpp b/include/rfl/parquet/read.hpp index 2e48ec66..e5f8b1d4 100644 --- a/include/rfl/parquet/read.hpp +++ b/include/rfl/parquet/read.hpp @@ -7,7 +7,6 @@ #include #include -//#include "../Processors.hpp" #include "../Result.hpp" #include "../concepts.hpp" #include "../internal/wrap_in_rfl_array_t.hpp" @@ -15,7 +14,12 @@ namespace rfl::parquet { -/// Parses an object from PARQUET using reflection. +/// @brief Parses an object from PARQUET using reflection. +/// @tparam T The type to parse. +/// @tparam Ps Additional parameters for parsing. +/// @param _bytes Pointer to the byte buffer containing the PARQUET data. +/// @param _size Size of the byte buffer. +/// @return Result containing the parsed object or an error message. template Result> read( const concepts::ByteLike auto* _bytes, const size_t _size) { @@ -48,13 +52,21 @@ Result> read( [](const auto& _r) { return _r.read(); }); } -/// Parses an object from PARQUET using reflection. +/// @brief Parses an object from PARQUET using reflection. +/// @tparam T The type to parse. +/// @tparam Ps Additional parameters for parsing. +/// @param _bytes Contiguous byte container holding the PARQUET data. +/// @return Result containing the parsed object or an error message. template auto read(const concepts::ContiguousByteContainer auto& _bytes) { return read(_bytes.data(), _bytes.size()); } -/// Parses an object from a stream. +/// @brief Parses an object from a stream. +/// @tparam T The type to parse. +/// @tparam Ps Additional parameters for parsing. +/// @param _stream Input stream containing the PARQUET data. +/// @return Result containing the parsed object or an error message. template auto read(std::istream& _stream) { std::istreambuf_iterator begin(_stream), end; diff --git a/include/rfl/parquet/save.hpp b/include/rfl/parquet/save.hpp index 8a18c08c..6e2b9e59 100644 --- a/include/rfl/parquet/save.hpp +++ b/include/rfl/parquet/save.hpp @@ -10,9 +10,20 @@ namespace rfl::parquet { +/// @brief Saves an object to a file using the specified settings. +/// @tparam Ps Variadic template parameters for the write function. +/// @param _fname The filename to save to. +/// @param _obj The object to be saved. +/// @param _settings Optional settings for saving (default constructed if not +/// provided). +/// @return Result indicating success or failure. template Result save(const std::string& _fname, const auto& _obj, const Settings& _settings = Settings{}) { + /// @brief Writes the object to the output stream using the provided settings. + /// @param _obj The object to write. + /// @param _stream The output stream to write to. + /// @return Reference to the output stream after writing. const auto write_func = [&](const auto& _obj, auto& _stream) -> auto& { return write(_obj, _stream, _settings); }; diff --git a/include/rfl/parquet/write.hpp b/include/rfl/parquet/write.hpp index f5087762..8c0b9f03 100644 --- a/include/rfl/parquet/write.hpp +++ b/include/rfl/parquet/write.hpp @@ -8,14 +8,17 @@ #include #include -//#include "../Processors.hpp" -//#include "../Ref.hpp" #include "../parsing/tabular/ArrowWriter.hpp" #include "Settings.hpp" namespace rfl::parquet { -/// Returns parquet bytes. +/// @brief Returns parquet bytes as an Arrow buffer. +/// @tparam Ps The processors used for serialization (e.g., transformations +/// applied to the data). +/// @param _arr The input array to serialize. +/// @param _settings Serialization settings. +/// @return Ref containing the parquet bytes. template Ref to_buffer(const auto& _arr, const Settings& _settings) { using T = std::remove_cvref_t; @@ -56,7 +59,12 @@ Ref to_buffer(const auto& _arr, const Settings& _settings) { return Ref::make(buffer.ValueOrDie()).value(); } -/// Returns parquet bytes. +/// @brief Returns parquet bytes as a vector of chars. +/// @tparam Ps The processors used for serialization (e.g., transformations +/// applied to the data). +/// @param _arr The input array to serialize. +/// @param _settings Serialization settings (optional). +/// @return std::vector containing the parquet bytes. template std::vector write(const auto& _arr, const Settings& _settings = Settings{}) { @@ -65,7 +73,13 @@ std::vector write(const auto& _arr, return std::vector(view.begin(), view.end()); } -/// Writes a PARQUET into an ostream. +/// @brief Writes a PARQUET representation of the array into an ostream. +/// @tparam Ps The processors used for serialization (e.g., transformations +/// applied to the data). +/// @param _arr The input array to serialize. +/// @param _stream The output stream to write to. +/// @param _settings Serialization settings (optional). +/// @return Reference to the output stream. template std::ostream& write(const auto& _arr, std::ostream& _stream, const Settings& _settings = Settings{}) { diff --git a/include/rfl/parsing/AreReaderAndWriter.hpp b/include/rfl/parsing/AreReaderAndWriter.hpp index 50893560..16cfd825 100644 --- a/include/rfl/parsing/AreReaderAndWriter.hpp +++ b/include/rfl/parsing/AreReaderAndWriter.hpp @@ -7,6 +7,13 @@ namespace rfl { namespace parsing { +/** + * @brief Checks if R and W are a reader and a writer for type T. + * + * @tparam R The reader type. + * @tparam W The writer type. + * @tparam T The type to be read and written. + */ template concept AreReaderAndWriter = IsReader && IsWriter; diff --git a/include/rfl/parsing/ArrayReader.hpp b/include/rfl/parsing/ArrayReader.hpp index d3b67b29..e4f094b2 100644 --- a/include/rfl/parsing/ArrayReader.hpp +++ b/include/rfl/parsing/ArrayReader.hpp @@ -18,11 +18,20 @@ class ArrayReader { static constexpr size_t size_ = _size; public: + /** + * @brief Constructor. + * @param _r The reader to use. + * @param _array The array to read into. + */ ArrayReader(const R* _r, std::array* _array) : array_(_array), num_set_(0), r_(_r) {} ~ArrayReader() = default; + /** + * @brief Checks if the correct number of elements has been read. + * @return An error if the number of elements is incorrect, std::nullopt otherwise. + */ std::optional check_size() const { if (num_set_ != size_) { return Error("Expected " + std::to_string(size_) + " elements, got " + @@ -31,8 +40,17 @@ class ArrayReader { return std::nullopt; } + /** + * @brief Returns the number of elements that have been set. + * @return The number of elements. + */ size_t num_set() const { return num_set_; } + /** + * @brief Reads a variable from the input and adds it to the array. + * @param _var The input variable to read. + * @return An error if reading fails or if the array is already full, std::nullopt otherwise. + */ std::optional read(const InputVarType& _var) const { if (num_set_ == size_) { return Error("Expected " + std::to_string(size_) + @@ -52,6 +70,13 @@ class ArrayReader { } private: + /** + * @brief Moves the value from Source to Target using placement new. + * @tparam Target The target type. + * @tparam Source The source type. + * @param _t The target pointer. + * @param _s The source pointer. + */ template void move_to(Target* _t, Source* _s) const { if constexpr (std::is_const_v) { diff --git a/include/rfl/parsing/CustomParser.hpp b/include/rfl/parsing/CustomParser.hpp index 2369c113..7e6d3509 100644 --- a/include/rfl/parsing/CustomParser.hpp +++ b/include/rfl/parsing/CustomParser.hpp @@ -17,6 +17,13 @@ template ; + /** + * @brief Reads a value from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read. + * @return A Result containing the parsed value or an error. + */ static Result read(const R& _r, const auto& _var) noexcept { const auto to_class = [](auto&& _h) -> Result { try { @@ -38,12 +45,26 @@ struct CustomParser { .and_then(to_class); } + /** + * @brief Writes a value to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _p The object to write. + * @param _parent The parent object. + */ template static auto write(const W& _w, const OriginalClass& _p, const P& _parent) { Parser::write( _w, HelperStruct::from_class(_p), _parent); } + /** + * @brief Generates the schema for the type. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser::to_schema( diff --git a/include/rfl/parsing/FieldVariantParser.hpp b/include/rfl/parsing/FieldVariantParser.hpp index 7e4483d6..8b68f68d 100644 --- a/include/rfl/parsing/FieldVariantParser.hpp +++ b/include/rfl/parsing/FieldVariantParser.hpp @@ -29,6 +29,13 @@ struct FieldVariantParser { using InputObjectType = typename R::InputObjectType; using InputVarType = typename R::InputVarType; + /** + * @brief Reads a field variant from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed field variant or an error. + */ static ResultType read(const R& _r, const InputVarType& _var) noexcept { static_assert( internal::no_duplicate_field_names>(), @@ -55,6 +62,14 @@ struct FieldVariantParser { return _r.to_object(_var).and_then(to_result); } + /** + * @brief Writes a field variant to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _v The field variant to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const rfl::Variant& _v, const P& _parent) { @@ -71,6 +86,12 @@ struct FieldVariantParser { }); } + /** + * @brief Generates the schema for the field variant. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions, std::vector = {}) { diff --git a/include/rfl/parsing/FieldVariantReader.hpp b/include/rfl/parsing/FieldVariantReader.hpp index 8014fb5b..ec045e5a 100644 --- a/include/rfl/parsing/FieldVariantReader.hpp +++ b/include/rfl/parsing/FieldVariantReader.hpp @@ -23,12 +23,24 @@ class FieldVariantReader { using ResultType = Result; public: + /** + * @brief Constructor. + * + * @param _r The reader to use. + * @param _field_variant The field variant to write to. + */ FieldVariantReader(const R* _r, std::optional>* _field_variant) : r_(_r), field_variant_(_field_variant) {} ~FieldVariantReader() = default; + /** + * @brief Reads a field from the input. + * + * @param _disc_value The name of the field. + * @param _var The input variable to read from. + */ void read(const std::string_view& _disc_value, const InputVarType& _var) const noexcept { try_matching_fields( diff --git a/include/rfl/parsing/IsReader.hpp b/include/rfl/parsing/IsReader.hpp index b80416f0..315e01fd 100644 --- a/include/rfl/parsing/IsReader.hpp +++ b/include/rfl/parsing/IsReader.hpp @@ -17,6 +17,11 @@ namespace rfl { namespace parsing { +/** + * @brief A mock reader for arrays. + * + * @tparam R The reader type. + */ template struct MockArrayReader { std::optional read(typename R::InputVarType&) const { @@ -24,11 +29,22 @@ struct MockArrayReader { } }; +/** + * @brief A mock reader for objects. + * + * @tparam R The reader type. + */ template struct MockObjectReader { void read(const std::string_view&, typename R::InputVarType&) const {} }; +/** + * @brief A reader for a specific format. + * + * @tparam R The reader type. + * @tparam T The type to be read. + */ template concept IsReader = (SupportsTaggedUnions || schemaful::IsSchemafulReader) && diff --git a/include/rfl/parsing/IsWriter.hpp b/include/rfl/parsing/IsWriter.hpp index ff224b93..98ae7285 100644 --- a/include/rfl/parsing/IsWriter.hpp +++ b/include/rfl/parsing/IsWriter.hpp @@ -10,6 +10,12 @@ namespace rfl { namespace parsing { +/** + * @brief A writer for a specific format. + * + * @tparam W The writer type. + * @tparam T The type to be written. + */ template concept IsWriter = requires(W w, T t, std::string_view name, std::string basic_value, diff --git a/include/rfl/parsing/MapParser.hpp b/include/rfl/parsing/MapParser.hpp index 33f21b46..748d6d5c 100644 --- a/include/rfl/parsing/MapParser.hpp +++ b/include/rfl/parsing/MapParser.hpp @@ -32,6 +32,13 @@ struct MapParser { using ParentType = Parent; + /** + * @brief Reads a map from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed map or an error. + */ static Result read(const R& _r, const InputVarType& _var) noexcept { const auto to_map = [&](auto obj) -> Result { return make_map(_r, obj); @@ -43,6 +50,14 @@ struct MapParser { } } + /** + * @brief Writes a map to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _m The map to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const MapType& _m, const P& _parent) { if constexpr (schemaful::IsSchemafulWriter) { @@ -52,6 +67,12 @@ struct MapParser { } } + /** + * @brief Generates the schema for the map. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return schema::Type{schema::Type::StringMap{Ref::make( diff --git a/include/rfl/parsing/MapReader.hpp b/include/rfl/parsing/MapReader.hpp index 3301066a..fe0cd9a1 100644 --- a/include/rfl/parsing/MapReader.hpp +++ b/include/rfl/parsing/MapReader.hpp @@ -23,11 +23,24 @@ class MapReader { std::remove_cvref_t; public: + /** + * @brief Constructor. + * + * @param _r The reader to use. + * @param _map The map to write to. + * @param _errors The vector to collect errors in. + */ MapReader(const R* _r, MapType* _map, std::vector* _errors) : r_(_r), map_(_map), errors_(_errors) {} ~MapReader() = default; + /** + * @brief Reads a single field into the map. + * + * @param _name The name of the field. + * @param _var The input variable to read from. + */ void read(const std::string_view& _name, const InputVarType& _var) const noexcept { auto res = get_pair(_name, _var); diff --git a/include/rfl/parsing/NamedTupleParser.hpp b/include/rfl/parsing/NamedTupleParser.hpp index be2ff594..fd9d3839 100644 --- a/include/rfl/parsing/NamedTupleParser.hpp +++ b/include/rfl/parsing/NamedTupleParser.hpp @@ -76,10 +76,13 @@ struct NamedTupleParser { "including rfl::ExtraFields."); public: - /// The way this works is that we allocate space on the stack in this size of - /// the named tuple in which we then write the individual fields using - /// views and placement new. This is how we deal with the fact that some - /// fields might not be default-constructible. + /** + * @brief Reads a named tuple from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed named tuple or an error. + */ static Result> read( const R& _r, const InputVarType& _var) noexcept { static_assert( @@ -100,7 +103,15 @@ struct NamedTupleParser { return res; } - /// Reads the data into a view assuming no default values. + /** + * @brief Reads the data into a view assuming no default values. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @param _view The view to read into. + * @return A pair containing a boolean array indicating which fields were + * found and an optional error. + */ static std::pair, std::optional> read_view(const R& _r, const InputVarType& _var, @@ -124,7 +135,14 @@ struct NamedTupleParser { } } - /// Reads the data into a view assuming default values. + /** + * @brief Reads the data into a view assuming default values. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @param _view The view to read into. + * @return An optional error. + */ static std::optional read_view_with_default( const R& _r, const InputVarType& _var, NamedTuple* _view) noexcept { @@ -145,6 +163,14 @@ struct NamedTupleParser { } } + /** + * @brief Writes a named tuple to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _tup The named tuple to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const NamedTuple& _tup, const P& _parent) { @@ -159,6 +185,12 @@ struct NamedTupleParser { } } + /** + * @brief Generates the schema for the named tuple. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) noexcept { SchemaType schema; diff --git a/include/rfl/parsing/Parent.hpp b/include/rfl/parsing/Parent.hpp index 8ce99fa4..5d868d4c 100644 --- a/include/rfl/parsing/Parent.hpp +++ b/include/rfl/parsing/Parent.hpp @@ -44,6 +44,15 @@ struct Parent { struct Root {}; + /** + * @brief Adds an array to the parent. + * + * @tparam ParentType The type of the parent. + * @param _w The writer to use. + * @param _size The size of the array. + * @param _parent The parent object. + * @return The new array. + */ template static OutputArrayType add_array(const W& _w, const size_t _size, const ParentType& _parent) { @@ -72,7 +81,14 @@ struct Parent { } } - /// Adds a comment to the parent element, if supported by the writer. + /** + * @brief Adds a comment to the parent. + * + * @tparam ParentType The type of the parent. + * @param _w The writer to use. + * @param _comment The comment to add. + * @param _parent The parent object. + */ template static void add_comment(const W& _w, std::string_view _comment, const ParentType& _parent) { @@ -87,7 +103,15 @@ struct Parent { } } - // For schemaful formats only. + /** + * @brief Adds a map to the parent. + * + * @tparam ParentType The type of the parent. + * @param _w The writer to use. + * @param _size The size of the map. + * @param _parent The parent object. + * @return The new map. + */ template static auto add_map(const W& _w, const size_t _size, const ParentType& _parent) { @@ -113,6 +137,15 @@ struct Parent { } } + /** + * @brief Adds an object to the parent. + * + * @tparam ParentType The type of the parent. + * @param _w The writer to use. + * @param _size The size of the object. + * @param _parent The parent object. + * @return The new object. + */ template static OutputObjectType add_object(const W& _w, const size_t _size, const ParentType& _parent) { @@ -141,6 +174,14 @@ struct Parent { } } + /** + * @brief Adds a null value to the parent. + * + * @tparam ParentType The type of the parent. + * @param _w The writer to use. + * @param _parent The parent object. + * @return The new null value. + */ template static OutputVarType add_null(const W& _w, const ParentType& _parent) { using Type = std::remove_cvref_t; @@ -173,7 +214,14 @@ struct Parent { } } - // For schemaful formats only. + /** + * @brief Adds a union to the parent. + * + * @tparam ParentType The type of the parent. + * @param _w The writer to use. + * @param _parent The parent object. + * @return The new union. + */ template static auto add_union(const W& _w, const ParentType& _parent) { using Type = std::remove_cvref_t; @@ -198,6 +246,16 @@ struct Parent { } } + /** + * @brief Adds a value to the parent. + * + * @tparam ParentType The type of the parent. + * @tparam T The type of the value. + * @param _w The writer to use. + * @param _var The value to add. + * @param _parent The parent object. + * @return The new value. + */ template static OutputVarType add_value(const W& _w, const T& _var, const ParentType& _parent) { diff --git a/include/rfl/parsing/Parser_array.hpp b/include/rfl/parsing/Parser_array.hpp index 8b5bb4fa..00edb70f 100644 --- a/include/rfl/parsing/Parser_array.hpp +++ b/include/rfl/parsing/Parser_array.hpp @@ -26,6 +26,12 @@ struct Parser, ProcessorsType> { using ParentType = Parent; + /** + * @brief Reads a std::array from the input. + * @param _r The reader to use. + * @param _var The input variable to read. + * @return A Result containing the parsed array or an error. + */ static Result> read(const R& _r, const InputVarType& _var) noexcept { const auto parse = @@ -53,6 +59,13 @@ struct Parser, ProcessorsType> { return _r.to_array(_var).and_then(parse); } + /** + * @brief Writes a std::array to the output. + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _arr The array to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const std::array& _arr, const P& _parent) { @@ -65,6 +78,11 @@ struct Parser, ProcessorsType> { _w.end_array(&arr); } + /** + * @brief Generates the schema for std::array. + * @param _definitions The map of definitions to add to. + * @return The schema type for std::array. + */ static schema::Type to_schema( std::map* _definitions) { using U = std::remove_cvref_t; diff --git a/include/rfl/parsing/Parser_atomic.hpp b/include/rfl/parsing/Parser_atomic.hpp index 9bc3e4de..75cfde53 100644 --- a/include/rfl/parsing/Parser_atomic.hpp +++ b/include/rfl/parsing/Parser_atomic.hpp @@ -18,14 +18,26 @@ template struct Parser, ProcessorsType> { using InputVarType = typename R::InputVarType; - /// Read is not supported for atomic types - we must used rfl::atomic instead. - + /** + * @brief Writes an atomic value to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _a The atomic value to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const std::atomic& _a, const P& _parent) { Parser, ProcessorsType>::write( _w, _a.load(std::memory_order_relaxed), _parent); } + /** + * @brief Generates the schema for the atomic value. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { using U = std::remove_cvref_t; diff --git a/include/rfl/parsing/Parser_atomic_flag.hpp b/include/rfl/parsing/Parser_atomic_flag.hpp index 1cbb4e0f..26f45e10 100644 --- a/include/rfl/parsing/Parser_atomic_flag.hpp +++ b/include/rfl/parsing/Parser_atomic_flag.hpp @@ -18,14 +18,26 @@ template struct Parser { using InputVarType = typename R::InputVarType; - /// Read is not supported for atomic types - we must used rfl::atomic instead. - + /** + * @brief Writes an atomic_flag to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _a The atomic_flag to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const std::atomic_flag& _a, const P& _parent) { Parser::write( _w, _a.test(std::memory_order_relaxed), _parent); } + /** + * @brief Generates the schema for the atomic_flag. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return schema::Type{ diff --git a/include/rfl/parsing/Parser_base.hpp b/include/rfl/parsing/Parser_base.hpp index abc0d0bd..d711e1ca 100644 --- a/include/rfl/parsing/Parser_base.hpp +++ b/include/rfl/parsing/Parser_base.hpp @@ -6,6 +6,14 @@ namespace rfl { namespace parsing { +/** + * @brief The main parser struct, which must be specialized for each type. + * + * @tparam R The reader type. + * @tparam W The writer type. + * @tparam T The type to be parsed. + * @tparam ProcessorsType The processors to use. + */ template requires AreReaderAndWriter struct Parser; diff --git a/include/rfl/parsing/Parser_basic_type.hpp b/include/rfl/parsing/Parser_basic_type.hpp index 27264aa6..7140df33 100644 --- a/include/rfl/parsing/Parser_basic_type.hpp +++ b/include/rfl/parsing/Parser_basic_type.hpp @@ -42,17 +42,36 @@ struct Parser { using ParentType = Parent; - /// Expresses the variables as type T. + /** + * @brief Reads a basic type from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed value or an error. + */ static Result read(const R& _r, const InputVarType& _var) noexcept { return _r.template to_basic_type>(_var); } + /** + * @brief Writes a basic type to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _var The value to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const T& _var, const P& _parent) { ParentType::add_value(_w, _var, _parent); } - /// Generates a schema for the underlying type. + /** + * @brief Generates the schema for the basic type. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema(std::map*) { using U = std::remove_cvref_t; using Type = schema::Type; diff --git a/include/rfl/parsing/Parser_box.hpp b/include/rfl/parsing/Parser_box.hpp index 8d26013b..ebdaa5f3 100644 --- a/include/rfl/parsing/Parser_box.hpp +++ b/include/rfl/parsing/Parser_box.hpp @@ -21,6 +21,13 @@ template struct Parser, ProcessorsType> { using InputVarType = typename R::InputVarType; + /** + * @brief Reads a Box from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed Box or an error. + */ static Result> read(const R& _r, const InputVarType& _var) noexcept { if constexpr (atomic::is_atomic_v) { @@ -48,12 +55,26 @@ struct Parser, ProcessorsType> { } } + /** + * @brief Writes a Box to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _box The Box to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const Box& _box, const P& _parent) { Parser, ProcessorsType>::write(_w, *_box, _parent); } + /** + * @brief Generates the schema for the Box. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser, ProcessorsType>::to_schema( diff --git a/include/rfl/parsing/Parser_bytestring.hpp b/include/rfl/parsing/Parser_bytestring.hpp index 3e1f6905..41f0b39e 100644 --- a/include/rfl/parsing/Parser_bytestring.hpp +++ b/include/rfl/parsing/Parser_bytestring.hpp @@ -17,16 +17,37 @@ struct Parser { using InputVarType = typename R::InputVarType; using ParentType = Parent; + /** + * @brief Reads a Bytestring from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed Bytestring or an error. + */ static Result read(const R& _r, const InputVarType& _var) noexcept { return _r.template to_basic_type(_var); } + /** + * @brief Writes a Bytestring to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _b The Bytestring to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const Bytestring& _b, const P& _parent) { ParentType::add_value(_w, _b, _parent); } + /** + * @brief Generates the schema for the Bytestring. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema(std::map*) { return schema::Type{schema::Type::Bytestring{}}; } diff --git a/include/rfl/parsing/Parser_c_array.hpp b/include/rfl/parsing/Parser_c_array.hpp index 58447a00..bc34dfba 100644 --- a/include/rfl/parsing/Parser_c_array.hpp +++ b/include/rfl/parsing/Parser_c_array.hpp @@ -26,12 +26,27 @@ struct Parser { using ParentType = Parent; using CArray = T[_size]; + /** + * @brief Reads a C array from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed C array or an error. + */ static Result> read( const R& _r, const InputVarType& _var) noexcept { using StdArray = internal::to_std_array_t; return Parser::read(_r, _var); } + /** + * @brief Writes a C array to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _arr The C array to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const CArray& _arr, const P& _parent) { auto arr = ParentType::add_array(_w, _size, _parent); @@ -43,6 +58,12 @@ struct Parser { _w.end_array(&arr); } + /** + * @brief Generates the schema for the C array. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { using StdArray = internal::to_std_array_t; diff --git a/include/rfl/parsing/Parser_commented.hpp b/include/rfl/parsing/Parser_commented.hpp index 4720a5d5..01bfe1b9 100644 --- a/include/rfl/parsing/Parser_commented.hpp +++ b/include/rfl/parsing/Parser_commented.hpp @@ -26,6 +26,13 @@ struct Parser, ProcessorsType> { using ParentType = Parent; + /** + * @brief Reads a Commented value from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed Commented value or an error. + */ static Result> read(const R& _r, const InputVarType& _var) noexcept { return Parser, ProcessorsType>::read(_r, _var) @@ -34,6 +41,14 @@ struct Parser, ProcessorsType> { }); } + /** + * @brief Writes a Commented value to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _c The Commented value to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const Commented& _c, const P& _parent) { Parser, ProcessorsType>::write(_w, _c.get(), @@ -45,6 +60,12 @@ struct Parser, ProcessorsType> { } } + /** + * @brief Generates the schema for the Commented value. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser, ProcessorsType>::to_schema( diff --git a/include/rfl/parsing/Parser_default.hpp b/include/rfl/parsing/Parser_default.hpp index e2d6159c..b7de7f7a 100644 --- a/include/rfl/parsing/Parser_default.hpp +++ b/include/rfl/parsing/Parser_default.hpp @@ -44,7 +44,13 @@ struct Parser { using ParentType = Parent; - /// Expresses the variables as type T. + /** + * @brief Reads a value from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed value or an error. + */ static Result read(const R& _r, const InputVarType& _var) noexcept { if constexpr (internal::has_read_reflector) { const auto wrap_in_t = [](auto&& _named_tuple) -> Result { @@ -90,6 +96,14 @@ struct Parser { } } + /** + * @brief Writes a value to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _var The value to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const T& _var, const P& _parent) { if constexpr (internal::has_write_reflector) { @@ -119,7 +133,12 @@ struct Parser { } } - /// Generates a schema for the underlying type. + /** + * @brief Generates the schema for the type. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { using U = std::remove_cvref_t; diff --git a/include/rfl/parsing/Parser_default_val.hpp b/include/rfl/parsing/Parser_default_val.hpp index 38f4b359..1dc47c1d 100644 --- a/include/rfl/parsing/Parser_default_val.hpp +++ b/include/rfl/parsing/Parser_default_val.hpp @@ -19,6 +19,12 @@ struct Parser, ProcessorsType> { using ParentType = Parent; + /** + * @brief Reads a DefaultVal from the input. + * @param _r The reader to use. + * @param _var The input variable to read. + * @return A Result containing the parsed DefaultVal or an error. + */ static Result> read(const R& _r, const InputVarType& _var) noexcept { return Parser, ProcessorsType>::read(_r, _var) @@ -27,12 +33,24 @@ struct Parser, ProcessorsType> { }); } + /** + * @brief Writes a DefaultVal to the output. + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _d The DefaultVal to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const DefaultVal& _d, const P& _parent) { Parser, ProcessorsType>::write(_w, _d.value(), _parent); } + /** + * @brief Generates the schema for DefaultVal. + * @param _definitions The map of definitions to add to. + * @return The schema type for DefaultVal. + */ static schema::Type to_schema( std::map* _definitions) { using U = std::remove_cvref_t; diff --git a/include/rfl/parsing/Parser_duration.hpp b/include/rfl/parsing/Parser_duration.hpp index 2f205ded..7e409024 100644 --- a/include/rfl/parsing/Parser_duration.hpp +++ b/include/rfl/parsing/Parser_duration.hpp @@ -38,6 +38,13 @@ struct Parser, ProcessorsType> { Unit unit; }; + /** + * @brief Reads a duration from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed duration or an error. + */ static Result read(const R& _r, const InputVarType& _var) noexcept { return Parser::read(_r, _var) @@ -49,6 +56,14 @@ struct Parser, ProcessorsType> { }); } + /** + * @brief Writes a duration to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _d The duration to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const DurationType& _d, const P& _parent) { const auto r = @@ -56,6 +71,12 @@ struct Parser, ProcessorsType> { return Parser::write(_w, r, _parent); } + /** + * @brief Generates the schema for the duration. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser::to_schema(_definitions); diff --git a/include/rfl/parsing/Parser_enum.hpp b/include/rfl/parsing/Parser_enum.hpp index 82716131..49e5fe56 100644 --- a/include/rfl/parsing/Parser_enum.hpp +++ b/include/rfl/parsing/Parser_enum.hpp @@ -30,7 +30,13 @@ struct Parser { using ParentType = Parent; - /// Expresses the variables as type T. + /** + * @brief Reads an enum from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed enum or an error. + */ static Result read(const R& _r, const InputVarType& _var) noexcept { if constexpr (internal::has_read_reflector) { const auto wrap_in_t = [](auto&& _named_tuple) -> Result { @@ -58,6 +64,14 @@ struct Parser { } } + /** + * @brief Writes an enum to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _var The enum value to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const T& _var, const P& _parent) { if constexpr (internal::has_write_reflector) { @@ -73,6 +87,12 @@ struct Parser { } } + /** + * @brief Generates the schema for the enum. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { using U = std::remove_cvref_t; diff --git a/include/rfl/parsing/Parser_filepath.hpp b/include/rfl/parsing/Parser_filepath.hpp index a9414417..824debfc 100644 --- a/include/rfl/parsing/Parser_filepath.hpp +++ b/include/rfl/parsing/Parser_filepath.hpp @@ -16,7 +16,12 @@ template struct Parser { using InputVarType = typename R::InputVarType; - /// Expresses the variables as type T. + /** + * @brief Reads a std::filesystem::path from the input. + * @param _r The reader to use. + * @param _var The input variable to read. + * @return A Result containing the parsed path or an error. + */ static Result read(const R& _r, const InputVarType& _var) noexcept { const auto to_path = @@ -31,6 +36,13 @@ struct Parser { to_path); } + /** + * @brief Writes a std::filesystem::path to the output. + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _p The path to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const std::filesystem::path& _p, const P& _parent) { @@ -38,6 +50,11 @@ struct Parser { _parent); } + /** + * @brief Generates the schema for std::filesystem::path. + * @param _definitions The map of definitions to add to. + * @return The schema type for std::filesystem::path. + */ static schema::Type to_schema( std::map* _definitions) { return Parser::to_schema(_definitions); diff --git a/include/rfl/parsing/Parser_map_like.hpp b/include/rfl/parsing/Parser_map_like.hpp index d4b3fe78..f83074de 100644 --- a/include/rfl/parsing/Parser_map_like.hpp +++ b/include/rfl/parsing/Parser_map_like.hpp @@ -15,6 +15,9 @@ namespace rfl { namespace parsing { +/** + * @brief Parser specialization for std::map. + */ template requires AreReaderAndWriter, : public MapParser, ProcessorsType> {}; +/** + * @brief Parser specialization for std::unordered_map. + */ template requires AreReaderAndWriter< @@ -35,11 +41,17 @@ struct Parser, ProcessorsType> {}; +/** + * @brief Parser specialization for rfl::Object. + */ template requires AreReaderAndWriter> struct Parser, ProcessorsType> : public MapParser, ProcessorsType> {}; +/** + * @brief Parser specialization for rfl::ExtraFields. + */ template requires AreReaderAndWriter> struct Parser, ProcessorsType> diff --git a/include/rfl/parsing/Parser_named_tuple.hpp b/include/rfl/parsing/Parser_named_tuple.hpp index 3a03de2d..d3b3c1b0 100644 --- a/include/rfl/parsing/Parser_named_tuple.hpp +++ b/include/rfl/parsing/Parser_named_tuple.hpp @@ -11,6 +11,9 @@ namespace rfl { namespace parsing { +/** + * @brief Parser specialization for rfl::NamedTuple. + */ template requires AreReaderAndWriter> struct Parser, ProcessorsType> diff --git a/include/rfl/parsing/Parser_optional.hpp b/include/rfl/parsing/Parser_optional.hpp index d7f07f7a..921e059e 100644 --- a/include/rfl/parsing/Parser_optional.hpp +++ b/include/rfl/parsing/Parser_optional.hpp @@ -25,6 +25,13 @@ struct Parser, ProcessorsType> { using ParentType = Parent; + /** + * @brief Reads an optional value from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed optional value or an error. + */ static Result> read(const R& _r, const InputVarType& _var) noexcept { if constexpr (schemaful::IsSchemafulReader) { @@ -47,6 +54,14 @@ struct Parser, ProcessorsType> { } } + /** + * @brief Writes an optional value to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _o The optional value to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const std::optional& _o, const P& _parent) { if constexpr (schemaful::IsSchemafulWriter) { @@ -69,6 +84,12 @@ struct Parser, ProcessorsType> { } } + /** + * @brief Generates the schema for the optional value. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { using U = std::remove_cvref_t; diff --git a/include/rfl/parsing/Parser_pair.hpp b/include/rfl/parsing/Parser_pair.hpp index 0cf2336f..296261a5 100644 --- a/include/rfl/parsing/Parser_pair.hpp +++ b/include/rfl/parsing/Parser_pair.hpp @@ -19,7 +19,13 @@ template , ProcessorsType> { using InputVarType = typename R::InputVarType; - /// Expresses the variables as type T. + /** + * @brief Reads a pair from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed pair or an error. + */ static Result> read( const R& _r, const InputVarType& _var) noexcept { const auto to_pair = [&](auto&& _t) { @@ -31,6 +37,14 @@ struct Parser, ProcessorsType> { .transform(to_pair); } + /** + * @brief Writes a pair to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _p The pair to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const std::pair& _p, const P& _parent) { @@ -39,6 +53,12 @@ struct Parser, ProcessorsType> { ProcessorsType>::write(_w, tup, _parent); } + /** + * @brief Generates the schema for the pair. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser, diff --git a/include/rfl/parsing/Parser_positional.hpp b/include/rfl/parsing/Parser_positional.hpp index ffde0c89..14a0e5a0 100644 --- a/include/rfl/parsing/Parser_positional.hpp +++ b/include/rfl/parsing/Parser_positional.hpp @@ -17,6 +17,13 @@ template struct Parser, ProcessorsType> { using InputVarType = typename R::InputVarType; + /** + * @brief Reads a Positional value from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed Positional value or an error. + */ static Result> read(const R& _r, const InputVarType& _var) noexcept { const auto to_positional = [](auto&& _t) { @@ -26,6 +33,14 @@ struct Parser, ProcessorsType> { .transform(to_positional); } + /** + * @brief Writes a Positional value to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _positional The Positional value to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const Positional& _positional, const P& _parent) { @@ -33,6 +48,12 @@ struct Parser, ProcessorsType> { _w, _positional.value(), _parent); } + /** + * @brief Generates the schema for the Positional value. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser, ProcessorsType>::to_schema( diff --git a/include/rfl/parsing/Parser_ptr.hpp b/include/rfl/parsing/Parser_ptr.hpp index b602e64b..9136d8ea 100644 --- a/include/rfl/parsing/Parser_ptr.hpp +++ b/include/rfl/parsing/Parser_ptr.hpp @@ -21,7 +21,13 @@ struct Parser { using ParentType = Parent; - /// Expresses the variables as type T. + /** + * @brief Reads a value into a raw pointer from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed pointer or an error. + */ static Result read(const R& _r, const InputVarType& _var) noexcept { if constexpr (!internal::allow_raw_ptrs_v) { static_assert( @@ -46,6 +52,14 @@ struct Parser { } } + /** + * @brief Writes a value from a raw pointer to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _ptr The pointer to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const T* _ptr, const P& _parent) { if (!_ptr) { @@ -56,6 +70,12 @@ struct Parser { _parent); } + /** + * @brief Generates the schema for the pointer. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser, ProcessorsType>::to_schema( diff --git a/include/rfl/parsing/Parser_ref.hpp b/include/rfl/parsing/Parser_ref.hpp index 9f170e88..20ffb996 100644 --- a/include/rfl/parsing/Parser_ref.hpp +++ b/include/rfl/parsing/Parser_ref.hpp @@ -22,6 +22,13 @@ template struct Parser, ProcessorsType> { using InputVarType = typename R::InputVarType; + /** + * @brief Reads a Ref from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed Ref or an error. + */ static Result> read(const R& _r, const InputVarType& _var) noexcept { if constexpr (atomic::is_atomic_v) { using RemoveAtomicT = atomic::remove_atomic_t; @@ -48,12 +55,26 @@ struct Parser, ProcessorsType> { } } + /** + * @brief Writes a Ref to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _ref The Ref to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const Ref& _ref, const P& _parent) { Parser, ProcessorsType>::write(_w, *_ref, _parent); } + /** + * @brief Generates the schema for the Ref. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser, ProcessorsType>::to_schema( diff --git a/include/rfl/parsing/Parser_reference_wrapper.hpp b/include/rfl/parsing/Parser_reference_wrapper.hpp index 52b7e481..45a62011 100644 --- a/include/rfl/parsing/Parser_reference_wrapper.hpp +++ b/include/rfl/parsing/Parser_reference_wrapper.hpp @@ -18,6 +18,11 @@ template struct Parser, ProcessorsType> { using InputVarType = typename R::InputVarType; + /** + * @brief Reading into a reference wrapper is not supported. + * + * @return An error. + */ static Result> read(const R&, const InputVarType&) noexcept { static_assert(always_false_v, @@ -29,6 +34,14 @@ struct Parser, ProcessorsType> { return error("Unsupported."); } + /** + * @brief Writes a value from a reference wrapper to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _ref The reference wrapper to write. + * @param _p The parent object. + */ template static void write(const W& _w, const std::reference_wrapper _ref, const P& _p) { @@ -36,6 +49,12 @@ struct Parser, ProcessorsType> { _p); } + /** + * @brief Generates the schema for the reference wrapper. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser, ProcessorsType>::to_schema( diff --git a/include/rfl/parsing/Parser_rename.hpp b/include/rfl/parsing/Parser_rename.hpp index a79846d1..f8598298 100644 --- a/include/rfl/parsing/Parser_rename.hpp +++ b/include/rfl/parsing/Parser_rename.hpp @@ -20,6 +20,13 @@ template , ProcessorsType> { using InputVarType = typename R::InputVarType; + /** + * @brief Reads a renamed value from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed value or an error. + */ static Result> read(const R& _r, const InputVarType& _var) noexcept { const auto to_rename = [](auto&& _t) { @@ -29,6 +36,14 @@ struct Parser, ProcessorsType> { .transform(to_rename); } + /** + * @brief Writes a renamed value to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _rename The renamed value to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const Rename<_name, T>& _rename, const P& _parent) { @@ -36,6 +51,12 @@ struct Parser, ProcessorsType> { _w, _rename.value(), _parent); } + /** + * @brief Generates the schema for the renamed value. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser, ProcessorsType>::to_schema( diff --git a/include/rfl/parsing/Parser_result.hpp b/include/rfl/parsing/Parser_result.hpp index 0b5085fe..b66f7e64 100644 --- a/include/rfl/parsing/Parser_result.hpp +++ b/include/rfl/parsing/Parser_result.hpp @@ -24,6 +24,13 @@ struct Parser, ProcessorsType> { using ErrorType = NamedTuple>; using VariantType = std::variant, ErrorType>; + /** + * @brief Reads a Result from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed Result or an error. + */ static Result> read(const R& _r, const InputVarType& _var) noexcept { const auto handle = [](auto&& _t) -> Result { @@ -44,6 +51,14 @@ struct Parser, ProcessorsType> { to_res)); } + /** + * @brief Writes a Result to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _r The Result to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const Result& _r, const P& _parent) { if (_r) { @@ -55,6 +70,12 @@ struct Parser, ProcessorsType> { } } + /** + * @brief Generates the schema for the Result. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser, ProcessorsType>::to_schema( diff --git a/include/rfl/parsing/Parser_rfl_array.hpp b/include/rfl/parsing/Parser_rfl_array.hpp index 9e5c470b..be154b40 100644 --- a/include/rfl/parsing/Parser_rfl_array.hpp +++ b/include/rfl/parsing/Parser_rfl_array.hpp @@ -23,17 +23,38 @@ struct Parser, ProcessorsType> { using StdArray = internal::to_std_array_t; + /** + * @brief Reads an rfl::Array from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed rfl::Array or an error. + */ static Result> read(const R& _r, const InputVarType& _var) noexcept { return Parser::read(_r, _var); } + /** + * @brief Writes an rfl::Array to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _arr The rfl::Array to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const internal::Array& _arr, const P& _parent) { Parser::write(_w, _arr.arr_, _parent); } + /** + * @brief Generates the schema for the rfl::Array. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser::to_schema(_definitions); diff --git a/include/rfl/parsing/Parser_rfl_tuple.hpp b/include/rfl/parsing/Parser_rfl_tuple.hpp index c10d0c67..8f6505d9 100644 --- a/include/rfl/parsing/Parser_rfl_tuple.hpp +++ b/include/rfl/parsing/Parser_rfl_tuple.hpp @@ -9,6 +9,9 @@ namespace rfl { namespace parsing { +/** + * @brief Parser specialization for rfl::Tuple. + */ template requires AreReaderAndWriter> struct Parser, ProcessorsType> diff --git a/include/rfl/parsing/Parser_rfl_variant.hpp b/include/rfl/parsing/Parser_rfl_variant.hpp index 88aa7c2d..e0f5686a 100644 --- a/include/rfl/parsing/Parser_rfl_variant.hpp +++ b/include/rfl/parsing/Parser_rfl_variant.hpp @@ -30,6 +30,13 @@ class Parser, ProcessorsType> { public: using InputVarType = typename R::InputVarType; + /** + * @brief Reads an rfl::Variant from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed rfl::Variant or an error. + */ static Result> read( const R& _r, const InputVarType& _var) noexcept { if constexpr (internal::all_fields>()) { @@ -92,6 +99,14 @@ class Parser, ProcessorsType> { } } + /** + * @brief Writes an rfl::Variant to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _variant The rfl::Variant to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const rfl::Variant& _variant, @@ -150,6 +165,12 @@ class Parser, ProcessorsType> { } } + /** + * @brief Generates the schema for the rfl::Variant. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { if constexpr (internal::all_fields>()) { diff --git a/include/rfl/parsing/Parser_shared_ptr.hpp b/include/rfl/parsing/Parser_shared_ptr.hpp index e405d9d3..e6e67a3f 100644 --- a/include/rfl/parsing/Parser_shared_ptr.hpp +++ b/include/rfl/parsing/Parser_shared_ptr.hpp @@ -29,6 +29,13 @@ struct Parser, ProcessorsType> { using ParentType = Parent; + /** + * @brief Reads a shared_ptr from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed shared_ptr or an error. + */ static Result> read(const R& _r, const InputVarType& _var) noexcept { if constexpr (atomic::is_atomic_v) { @@ -67,6 +74,14 @@ struct Parser, ProcessorsType> { } } + /** + * @brief Writes a shared_ptr to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _s The shared_ptr to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const std::shared_ptr& _s, const P& _parent) noexcept { @@ -90,6 +105,12 @@ struct Parser, ProcessorsType> { } } + /** + * @brief Generates the schema for the shared_ptr. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { using U = std::remove_cvref_t; diff --git a/include/rfl/parsing/Parser_short.hpp b/include/rfl/parsing/Parser_short.hpp index ad32a5f3..4857ddd8 100644 --- a/include/rfl/parsing/Parser_short.hpp +++ b/include/rfl/parsing/Parser_short.hpp @@ -19,6 +19,13 @@ template , ProcessorsType> { using InputVarType = typename R::InputVarType; + /** + * @brief Reads a short value from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed value or an error. + */ static Result> read(const R& _r, const InputVarType& _var) noexcept { const auto to_short = [](auto&& _t) { @@ -28,6 +35,14 @@ struct Parser, ProcessorsType> { .transform(to_short); } + /** + * @brief Writes a short value to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _short The short value to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const Short<_name, T>& _short, const P& _parent) { @@ -35,6 +50,12 @@ struct Parser, ProcessorsType> { _w, _short.value(), _parent); } + /** + * @brief Generates the schema for the short value. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser, ProcessorsType>::to_schema( diff --git a/include/rfl/parsing/Parser_skip.hpp b/include/rfl/parsing/Parser_skip.hpp index b5346c7f..fd7cc955 100644 --- a/include/rfl/parsing/Parser_skip.hpp +++ b/include/rfl/parsing/Parser_skip.hpp @@ -24,6 +24,13 @@ struct Parser; + /** + * @brief Reads a value and skips it if required. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed value or an error. + */ static Result> read(const R& _r, const InputVarType& _var) noexcept { if constexpr (_skip_deserialization) { @@ -40,6 +47,14 @@ struct Parser static void write(const W& _w, const internal::Skip* _definitions) { return Parser, ProcessorsType>::to_schema( diff --git a/include/rfl/parsing/Parser_span.hpp b/include/rfl/parsing/Parser_span.hpp index e27ca75a..1894634e 100644 --- a/include/rfl/parsing/Parser_span.hpp +++ b/include/rfl/parsing/Parser_span.hpp @@ -23,6 +23,13 @@ struct Parser, ProcessorsType> { using InputVarType = typename R::InputVarType; using ParentType = Parent; + /** + * @brief Reads a span from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed span or an error. + */ static Result> read(const R& _r, const InputVarType& _var) noexcept { if constexpr (!internal::allow_raw_ptrs_v) { @@ -55,6 +62,14 @@ struct Parser, ProcessorsType> { } } + /** + * @brief Writes a span to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _span The span to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const std::span& _span, const P& _parent) { auto arr = ParentType::add_array(_w, _span.size(), _parent); @@ -66,6 +81,12 @@ struct Parser, ProcessorsType> { _w.end_array(&arr); } + /** + * @brief Generates the schema for the span. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser>, diff --git a/include/rfl/parsing/Parser_string_view.hpp b/include/rfl/parsing/Parser_string_view.hpp index 8b879d64..3cf6e74e 100644 --- a/include/rfl/parsing/Parser_string_view.hpp +++ b/include/rfl/parsing/Parser_string_view.hpp @@ -20,6 +20,13 @@ template struct Parser { using InputVarType = typename R::InputVarType; + /** + * @brief Reads a string_view from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed string_view or an error. + */ static Result read(const R& _r, const InputVarType& _var) noexcept { if constexpr (!internal::allow_raw_ptrs_v) { @@ -46,11 +53,25 @@ struct Parser { } } + /** + * @brief Writes a string_view to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _str The string_view to write. + * @param _p The parent object. + */ template static void write(const W& _w, const std::string_view& _str, const P& _p) { Parser::write(_w, std::string(_str), _p); } + /** + * @brief Generates the schema for the string_view. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser::to_schema(_definitions); diff --git a/include/rfl/parsing/Parser_tagged_union.hpp b/include/rfl/parsing/Parser_tagged_union.hpp index 3abc55ca..e13e7b3e 100644 --- a/include/rfl/parsing/Parser_tagged_union.hpp +++ b/include/rfl/parsing/Parser_tagged_union.hpp @@ -41,6 +41,13 @@ struct Parser, std::conditional_t; + /** + * @brief Reads a tagged union from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed tagged union or an error. + */ static ResultType read(const R& _r, const InputVarType& _var) noexcept { if constexpr (schemaful::IsSchemafulReader) { return Parser, ProcessorsType>::read( @@ -71,6 +78,14 @@ struct Parser, } } + /** + * @brief Writes a tagged union to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _tagged_union The tagged union to write. + * @param _parent The parent object. + */ template static void write( const W& _w, @@ -85,6 +100,12 @@ struct Parser, } } + /** + * @brief Generates the schema for the tagged union. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) noexcept { if constexpr (schemaful::IsSchemafulReader && diff --git a/include/rfl/parsing/Parser_time_point.hpp b/include/rfl/parsing/Parser_time_point.hpp index 22fc7487..280f9e19 100644 --- a/include/rfl/parsing/Parser_time_point.hpp +++ b/include/rfl/parsing/Parser_time_point.hpp @@ -30,18 +30,39 @@ struct Parser; + /** + * @brief Reads a time point from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed time point or an error. + */ static Result read(const R& _r, const InputVarType& _var) noexcept { return Parser::read(_r, _var).and_then( from_string); } + /** + * @brief Writes a time point to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _tp The time point to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const TimePointType& _tp, const P& _parent) { Parser::write(_w, to_string(_tp), _parent); } + /** + * @brief Generates the schema for the time point. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser::to_schema(_definitions); diff --git a/include/rfl/parsing/Parser_tuple.hpp b/include/rfl/parsing/Parser_tuple.hpp index d06f335d..e54bf711 100644 --- a/include/rfl/parsing/Parser_tuple.hpp +++ b/include/rfl/parsing/Parser_tuple.hpp @@ -10,6 +10,9 @@ namespace rfl { namespace parsing { +/** + * @brief Parser specialization for std::tuple. + */ template requires AreReaderAndWriter> struct Parser, ProcessorsType> diff --git a/include/rfl/parsing/Parser_unique_ptr.hpp b/include/rfl/parsing/Parser_unique_ptr.hpp index 3434bd8e..820f6139 100644 --- a/include/rfl/parsing/Parser_unique_ptr.hpp +++ b/include/rfl/parsing/Parser_unique_ptr.hpp @@ -29,6 +29,13 @@ struct Parser, ProcessorsType> { using ParentType = Parent; + /** + * @brief Reads a unique_ptr from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed unique_ptr or an error. + */ static Result> read(const R& _r, const InputVarType& _var) noexcept { if constexpr (atomic::is_atomic_v) { @@ -67,6 +74,14 @@ struct Parser, ProcessorsType> { } } + /** + * @brief Writes a unique_ptr to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _s The unique_ptr to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const std::unique_ptr& _s, const P& _parent) { @@ -90,6 +105,12 @@ struct Parser, ProcessorsType> { } } + /** + * @brief Generates the schema for the unique_ptr. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { using U = std::remove_cvref_t; diff --git a/include/rfl/parsing/Parser_variant.hpp b/include/rfl/parsing/Parser_variant.hpp index 33b1cf08..615c983e 100644 --- a/include/rfl/parsing/Parser_variant.hpp +++ b/include/rfl/parsing/Parser_variant.hpp @@ -38,6 +38,13 @@ class Parser, ProcessorsType> { public: using InputVarType = typename R::InputVarType; + /** + * @brief Reads a variant from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed variant or an error. + */ static Result> read( const R& _r, const InputVarType& _var) noexcept { if constexpr (internal::all_fields>()) { @@ -108,6 +115,14 @@ class Parser, ProcessorsType> { } } + /** + * @brief Writes a variant to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _variant The variant to write. + * @param _parent The parent object to write into. + */ template static void write(const W& _w, const std::variant& _variant, @@ -178,6 +193,12 @@ class Parser, ProcessorsType> { } } + /** + * @brief Generates a schema for the variant. + * + * @param _definitions The map of definitions to add the schema to. + * @return The generated schema type. + */ static schema::Type to_schema( std::map* _definitions) { if constexpr (internal::all_fields>()) { @@ -204,6 +225,13 @@ class Parser, ProcessorsType> { } private: + /** + * @brief Adds an alternative to the schema. + * + * @tparam _i The index of the alternative. + * @param _definitions The map of definitions to add the schema to. + * @param _types The vector of types to add the generated schema to. + */ template static void add_to_schema(std::map* _definitions, std::vector* _types) noexcept { @@ -212,6 +240,13 @@ class Parser, ProcessorsType> { _types->push_back(Parser::to_schema(_definitions)); } + /** + * @brief Builds the schema for the variant. + * + * @tparam _is The indices of the alternatives. + * @param _definitions The map of definitions to add the schema to. + * @param _types The vector of types to add the generated schemas to. + */ template static void build_schema(std::map* _definitions, std::vector* _types, @@ -219,6 +254,15 @@ class Parser, ProcessorsType> { (add_to_schema<_is>(_definitions, _types), ...); } + /** + * @brief Reads a single alternative from the input. + * + * @tparam _i The index of the alternative. + * @param _r The reader to use. + * @param _var The input variable to read from. + * @param _result The result pointer to store the parsed alternative. + * @param _errors The vector of errors to add parsing errors to. + */ template static void read_one_alternative( const R& _r, const InputVarType& _var, @@ -236,6 +280,15 @@ class Parser, ProcessorsType> { } } + /** + * @brief Reads the variant from the input by trying each alternative. + * + * @tparam _is The indices of the alternatives. + * @param _r The reader to use. + * @param _var The input variable to read from. + * @param _result The result pointer to store the parsed alternative. + * @param _errors The vector of errors to add parsing errors to. + */ template static void read_variant( const R& _r, const InputVarType& _var, diff --git a/include/rfl/parsing/Parser_vector_like.hpp b/include/rfl/parsing/Parser_vector_like.hpp index 8ce8322b..74306b7e 100644 --- a/include/rfl/parsing/Parser_vector_like.hpp +++ b/include/rfl/parsing/Parser_vector_like.hpp @@ -18,21 +18,33 @@ namespace rfl { namespace parsing { +/** + * @brief Parser specialization for std::deque. + */ template requires AreReaderAndWriter> struct Parser, ProcessorsType> : public VectorParser, ProcessorsType> {}; +/** + * @brief Parser specialization for std::forward_list. + */ template requires AreReaderAndWriter> struct Parser, ProcessorsType> : public VectorParser, ProcessorsType> {}; +/** + * @brief Parser specialization for std::list. + */ template requires AreReaderAndWriter> struct Parser, ProcessorsType> : public VectorParser, ProcessorsType> {}; +/** + * @brief Parser specialization for std::map. + */ template requires AreReaderAndWriter> @@ -40,6 +52,9 @@ struct Parser, ProcessorsType> : public VectorParser, ProcessorsType> {}; +/** + * @brief Parser specialization for std::multimap. + */ template requires AreReaderAndWriter> @@ -47,6 +62,9 @@ struct Parser, ProcessorsType> : public VectorParser, ProcessorsType> {}; +/** + * @brief Parser specialization for std::multiset. + */ template requires AreReaderAndWriter> @@ -54,6 +72,9 @@ struct Parser, ProcessorsType> : public VectorParser, ProcessorsType> {}; +/** + * @brief Parser specialization for std::set. + */ template requires AreReaderAndWriter> @@ -61,6 +82,9 @@ struct Parser, ProcessorsType> : public VectorParser, ProcessorsType> {}; +/** + * @brief Parser specialization for std::unordered_map. + */ template requires AreReaderAndWriter< @@ -71,6 +95,9 @@ struct Parser, std::unordered_map, ProcessorsType> {}; +/** + * @brief Parser specialization for std::unordered_multiset. + */ template requires AreReaderAndWriter< @@ -81,6 +108,9 @@ struct Parser, std::unordered_multiset, ProcessorsType> {}; +/** + * @brief Parser specialization for std::unordered_multimap. + */ template requires AreReaderAndWriter< @@ -90,6 +120,9 @@ struct Parser, : public VectorParser, ProcessorsType> { }; +/** + * @brief Parser specialization for std::unordered_set. + */ template requires AreReaderAndWriter, std::unordered_set, ProcessorsType> {}; +/** + * @brief Parser specialization for std::vector. + */ template requires AreReaderAndWriter> struct Parser, ProcessorsType> diff --git a/include/rfl/parsing/Parser_vectorstring.hpp b/include/rfl/parsing/Parser_vectorstring.hpp index 5559fcfe..9daacc7d 100644 --- a/include/rfl/parsing/Parser_vectorstring.hpp +++ b/include/rfl/parsing/Parser_vectorstring.hpp @@ -17,16 +17,37 @@ struct Parser { using InputVarType = typename R::InputVarType; using ParentType = Parent; + /** + * @brief Reads a Vectorstring from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed Vectorstring or an error. + */ static Result read(const R& _r, const InputVarType& _var) noexcept { return _r.template to_basic_type(_var); } + /** + * @brief Writes a Vectorstring to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _b The Vectorstring to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const Vectorstring& _b, const P& _parent) { ParentType::add_value(_w, _b, _parent); } + /** + * @brief Generates the schema for the Vectorstring. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema(std::map*) { return schema::Type{schema::Type::Vectorstring{}}; } diff --git a/include/rfl/parsing/Parser_wstring.hpp b/include/rfl/parsing/Parser_wstring.hpp index 73ee2c43..aa160f74 100644 --- a/include/rfl/parsing/Parser_wstring.hpp +++ b/include/rfl/parsing/Parser_wstring.hpp @@ -20,6 +20,13 @@ struct Parser { using ParentType = Parent; + /** + * @brief Reads a wstring from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed wstring or an error. + */ static Result read(const R& _r, const InputVarType& _var) noexcept { if (_r.is_empty(_var)) { @@ -51,6 +58,14 @@ struct Parser { return Result(outStr); } + /** + * @brief Writes a wstring to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _str The wstring to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const std::wstring& _str, const P& _parent) { if (_str.empty()) { @@ -69,6 +84,12 @@ struct Parser { ParentType::add_value(_w, outStr, _parent); } + /** + * @brief Generates the schema for the wstring. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { return Parser::to_schema(_definitions); diff --git a/include/rfl/parsing/SupportsTaggedUnions.hpp b/include/rfl/parsing/SupportsTaggedUnions.hpp index 971e41b2..70c68d64 100644 --- a/include/rfl/parsing/SupportsTaggedUnions.hpp +++ b/include/rfl/parsing/SupportsTaggedUnions.hpp @@ -10,6 +10,11 @@ namespace rfl::parsing { +/** + * @brief Determines whether a reader supports tagged unions. + * + * @tparam R The reader type. + */ template concept SupportsTaggedUnions = requires( R r, std::string name, typename R::InputArrayType arr, diff --git a/include/rfl/parsing/TupleParser.hpp b/include/rfl/parsing/TupleParser.hpp index bda80536..b9dd097c 100644 --- a/include/rfl/parsing/TupleParser.hpp +++ b/include/rfl/parsing/TupleParser.hpp @@ -32,6 +32,13 @@ struct TupleParser { using ParentType = Parent; + /** + * @brief Reads a tuple from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed tuple or an error. + */ static Result read(const R& _r, const InputVarType& _var) noexcept { if constexpr (schemaful::IsSchemafulReader) { @@ -72,6 +79,14 @@ struct TupleParser { } } + /** + * @brief Writes a tuple to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _tup The tuple to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const TupleType& _tup, const P& _parent) { if constexpr (schemaful::IsSchemafulWriter) { @@ -88,6 +103,12 @@ struct TupleParser { } } + /** + * @brief Generates the schema for the tuple. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { std::vector types; @@ -98,6 +119,13 @@ struct TupleParser { } private: + /** + * @brief Adds an element of the tuple to the schema. + * + * @tparam _i The index of the element. + * @param _definitions The map of definitions to add to. + * @param _types The vector of types to add the generated schema to. + */ template static void add_to_schema(std::map* _definitions, std::vector* _types) noexcept { @@ -105,6 +133,14 @@ struct TupleParser { _types->push_back(Parser::to_schema(_definitions)); } + /** + * @brief Builds the schema for the tuple. + * + * @tparam _is The indices of the elements. + * @param _definitions The map of definitions to add to. + * @param _types The vector of types to add the generated schemas to. + * @param seq The integer sequence of indices. + */ template static void build_schema(std::map* _definitions, std::vector* _types, @@ -112,6 +148,15 @@ struct TupleParser { (add_to_schema<_is>(_definitions, _types), ...); } + /** + * @brief Adds an element of the tuple to the array. + * + * @tparam _i The index of the element. + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _tup The tuple to write. + * @param _parent The parent object. + */ template static void add_to_array(const W& _w, const TupleType& _tup, const P& _parent) { @@ -121,6 +166,16 @@ struct TupleParser { _parent); } + /** + * @brief Converts the tuple to an array. + * + * @tparam _is The indices of the elements. + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _tup The tuple to write. + * @param _parent The parent object. + * @param seq The integer sequence of indices. + */ template static void to_array(const W& _w, const TupleType& _tup, const P& _parent, std::integer_sequence) { diff --git a/include/rfl/parsing/TupleReader.hpp b/include/rfl/parsing/TupleReader.hpp index c4304450..15ecf5f7 100644 --- a/include/rfl/parsing/TupleReader.hpp +++ b/include/rfl/parsing/TupleReader.hpp @@ -21,11 +21,22 @@ class TupleReader { static constexpr size_t size_ = rfl::tuple_size_v; public: + /** + * @brief Constructor. + * + * @param _r The reader to use. + * @param _tuple The tuple to read into. + */ TupleReader(const R* _r, TupleType* _tuple) : num_set_(0), r_(_r), tuple_(_tuple) {} ~TupleReader() = default; + /** + * @brief Handles any fields that were missing from the input. + * + * @return An optional error. + */ std::optional handle_missing_fields() const { std::optional err; if (num_set_ < size_) { @@ -34,8 +45,19 @@ class TupleReader { return err; } + /** + * @brief Returns the number of fields that have been set. + * + * @return The number of fields set. + */ size_t num_set() const { return num_set_; } + /** + * @brief Reads a single variable from the input. + * + * @param _var The input variable to read from. + * @return An optional error. + */ std::optional read(const InputVarType& _var) const { std::optional err; read_impl(_var, &err); diff --git a/include/rfl/parsing/VariantAlternativeWrapper.hpp b/include/rfl/parsing/VariantAlternativeWrapper.hpp index fe6215bf..208589c2 100644 --- a/include/rfl/parsing/VariantAlternativeWrapper.hpp +++ b/include/rfl/parsing/VariantAlternativeWrapper.hpp @@ -22,6 +22,13 @@ struct GetName> { constexpr static internal::StringLiteral name_ = _name; }; +/** + * @brief Makes a tag for the variant alternative. + * + * @tparam T The type to make the tag for. + * @tparam _remove_namespaces Whether to remove namespaces from the name. + * @return The tag for the type. + */ template consteval auto make_tag() { if constexpr (internal::has_tag_v) { diff --git a/include/rfl/parsing/VectorParser.hpp b/include/rfl/parsing/VectorParser.hpp index afbe6733..36ac892f 100644 --- a/include/rfl/parsing/VectorParser.hpp +++ b/include/rfl/parsing/VectorParser.hpp @@ -43,6 +43,13 @@ struct VectorParser { static_assert(!std::is_same_v, Vectorstring>, "Cannot be a vectorstring."); + /** + * @brief Reads a vector-like type from the input. + * + * @param _r The reader to use. + * @param _var The input variable to read from. + * @return A Result containing the parsed type or an error. + */ static Result read(const R& _r, const InputVarType& _var) noexcept { if constexpr (treat_as_map()) { return MapParser::read(_r, _var); @@ -71,6 +78,14 @@ struct VectorParser { } } + /** + * @brief Writes a vector-like type to the output. + * + * @tparam P The type of the parent. + * @param _w The writer to use. + * @param _vec The vector-like type to write. + * @param _parent The parent object. + */ template static void write(const W& _w, const VecType& _vec, const P& _parent) { if constexpr (treat_as_map()) { @@ -87,7 +102,12 @@ struct VectorParser { } } - /// Generates a schema for the underlying type. + /** + * @brief Generates the schema for the vector-like type. + * + * @param _definitions The map of definitions to add to. + * @return The schema type. + */ static schema::Type to_schema( std::map* _definitions) { if constexpr (treat_as_map()) { @@ -101,6 +121,11 @@ struct VectorParser { } private: + /** + * @brief Determines if the vector-like type should be treated as a map. + * + * @return true if the type should be treated as a map, false otherwise. + */ static constexpr bool treat_as_map() { if constexpr (is_map_like_not_multimap()) { if constexpr (internal::has_reflection_type_v) { diff --git a/include/rfl/parsing/VectorReader.hpp b/include/rfl/parsing/VectorReader.hpp index 90824346..ac2c72c9 100644 --- a/include/rfl/parsing/VectorReader.hpp +++ b/include/rfl/parsing/VectorReader.hpp @@ -18,10 +18,22 @@ class VectorReader { using T = typename VecType::value_type; public: + /** + * @brief Constructor. + * + * @param _r The reader to use. + * @param _vec The vector to read into. + */ VectorReader(const R* _r, VecType* _vec) : r_(_r), vec_(_vec) {} ~VectorReader() = default; + /** + * @brief Reads a single variable from the input. + * + * @param _var The input variable to read from. + * @return An optional error. + */ std::optional read(const InputVarType& _var) const { const auto parse = [this](const InputVarType& _var) { if constexpr (is_map_like_v) { diff --git a/include/rfl/parsing/ViewReader.hpp b/include/rfl/parsing/ViewReader.hpp index 8e761f2d..928bf672 100644 --- a/include/rfl/parsing/ViewReader.hpp +++ b/include/rfl/parsing/ViewReader.hpp @@ -24,27 +24,48 @@ class ViewReader { static constexpr size_t size_ = ViewType::size(); public: + /** + * @brief Constructor. + * + * @param _r The reader to use. + * @param _view The view to read into. + * @param _found A boolean array indicating which fields have been found. + * @param _set A boolean array indicating which fields have been successfully set. + * @param _errors The vector to collect errors in. + */ ViewReader(const R* _r, ViewType* _view, std::array* _found, std::array* _set, std::vector* _errors) : r_(_r), view_(_view), found_(_found), set_(_set), errors_(_errors) {} ~ViewReader() = default; - /// Assigns the parsed version of _var to the field signified by _name, if - /// such a field exists in the underlying view. + /** + * @brief Reads a single field into the view. + * + * @param _name The name of the field. + * @param _var The input variable to read from. + */ void read(const std::string_view& _name, const InputVarType& _var) const { assign_to_matching_field(*r_, _name, _var, view_, errors_, found_, set_, std::make_integer_sequence()); } - /// Assigns the parsed version of _var to the field signified by _index, if - /// such a field exists in the underlying view. - /// Note that schemaful formats can assign by index. + /** + * @brief Reads a single field into the view. + * + * @param _index The index of the field. + * @param _var The input variable to read from. + */ void read(const int _index, const InputVarType& _var) const { assign_to_matching_field(*r_, _index, _var, view_, errors_, found_, set_, std::make_integer_sequence()); } + /** + * @brief Returns the size of the view. + * + * @return The size of the view. + */ static constexpr size_t size() { return size_; } private: diff --git a/include/rfl/parsing/ViewReaderWithDefault.hpp b/include/rfl/parsing/ViewReaderWithDefault.hpp index 4796a262..bb5fd2af 100644 --- a/include/rfl/parsing/ViewReaderWithDefault.hpp +++ b/include/rfl/parsing/ViewReaderWithDefault.hpp @@ -24,6 +24,13 @@ class ViewReaderWithDefault { static constexpr size_t size_ = ViewType::size(); public: + /** + * @brief Constructor. + * + * @param _r The reader to use. + * @param _view The view to read into. + * @param _errors The vector to collect errors in. + */ ViewReaderWithDefault(const R* _r, ViewType* _view, std::vector* _errors) : r_(_r), view_(_view), errors_(_errors) { @@ -32,15 +39,29 @@ class ViewReaderWithDefault { ~ViewReaderWithDefault() = default; + /** + * @brief Returns a boolean array indicating which fields were found. + * + * @return The boolean array. + */ const std::array& found() const { return *found_; } - /// Assigns the parsed version of _var to the field signified by _name, if - /// such a field exists in the underlying view. + /** + * @brief Reads a single field into the view. + * + * @param _name The name of the field. + * @param _var The input variable to read from. + */ void read(const std::string_view& _name, const InputVarType& _var) const { assign_to_matching_field(*r_, _name, _var, view_, errors_, found_.get(), std::make_integer_sequence()); } + /** + * @brief Returns the size of the view. + * + * @return The size of the view. + */ static constexpr size_t size() { return size_; } private: diff --git a/include/rfl/parsing/ViewReaderWithDefaultAndStrippedFieldNames.hpp b/include/rfl/parsing/ViewReaderWithDefaultAndStrippedFieldNames.hpp index 329f57d4..6abd2520 100644 --- a/include/rfl/parsing/ViewReaderWithDefaultAndStrippedFieldNames.hpp +++ b/include/rfl/parsing/ViewReaderWithDefaultAndStrippedFieldNames.hpp @@ -21,12 +21,24 @@ class ViewReaderWithDefaultAndStrippedFieldNames { static constexpr size_t size_ = ViewType::size(); public: + /** + * @brief Constructor. + * + * @param _r The reader to use. + * @param _view The view to read into. + * @param _errors The vector to collect errors in. + */ ViewReaderWithDefaultAndStrippedFieldNames(const R* _r, ViewType* _view, std::vector* _errors) : i_(0), r_(_r), view_(_view), errors_(_errors) {} ~ViewReaderWithDefaultAndStrippedFieldNames() = default; + /** + * @brief Returns a boolean array indicating which fields were found. + * + * @return The boolean array. + */ std::array found() const { std::array f; std::fill(f.begin(), f.begin() + i_, true); @@ -34,8 +46,12 @@ class ViewReaderWithDefaultAndStrippedFieldNames { return f; } - /// Assigns the parsed version of _var to the field signified by i_, to be - /// used when the field names are stripped. + /** + * @brief Reads a single variable from the input. + * + * @param _var The input variable to read from. + * @return An optional error. + */ std::optional read(const InputVarType& _var) const { if (i_ == size_) { std::stringstream stream; @@ -49,6 +65,11 @@ class ViewReaderWithDefaultAndStrippedFieldNames { return std::nullopt; } + /** + * @brief Returns the size of the view. + * + * @return The size of the view. + */ static constexpr size_t size() { return size_; } private: diff --git a/include/rfl/parsing/ViewReaderWithStrippedFieldNames.hpp b/include/rfl/parsing/ViewReaderWithStrippedFieldNames.hpp index 2a1da337..18f54377 100644 --- a/include/rfl/parsing/ViewReaderWithStrippedFieldNames.hpp +++ b/include/rfl/parsing/ViewReaderWithStrippedFieldNames.hpp @@ -22,6 +22,15 @@ class ViewReaderWithStrippedFieldNames { static constexpr size_t size_ = ViewType::size(); public: + /** + * @brief Constructor. + * + * @param _r The reader to use. + * @param _view The view to read into. + * @param _found A boolean array indicating which fields have been found. + * @param _set A boolean array indicating which fields have been successfully set. + * @param _errors The vector to collect errors in. + */ ViewReaderWithStrippedFieldNames(const R* _r, ViewType* _view, std::array* _found, std::array* _set, @@ -35,8 +44,12 @@ class ViewReaderWithStrippedFieldNames { ~ViewReaderWithStrippedFieldNames() = default; - /// Assigns the parsed version of _var to the field signified by i_, to be - /// used when the field names are stripped. + /** + * @brief Reads a single variable from the input. + * + * @param _var The input variable to read from. + * @return An optional error. + */ std::optional read(const InputVarType& _var) const { if (i_ == size_) { std::stringstream stream; @@ -50,6 +63,11 @@ class ViewReaderWithStrippedFieldNames { return std::nullopt; } + /** + * @brief Returns the size of the view. + * + * @return The size of the view. + */ static constexpr size_t size() { return size_; } private: diff --git a/include/rfl/parsing/call_destructors_on_array_where_necessary.hpp b/include/rfl/parsing/call_destructors_on_array_where_necessary.hpp index 1b02d3fd..acb4e87e 100644 --- a/include/rfl/parsing/call_destructors_on_array_where_necessary.hpp +++ b/include/rfl/parsing/call_destructors_on_array_where_necessary.hpp @@ -8,9 +8,14 @@ namespace rfl::parsing { -/// Because of the way we have allocated the fields, we need to manually -/// trigger the destructors. - +/** + * @brief Calls the destructors on the elements of an array, if necessary. + * + * @tparam T The type of the elements in the array. + * @tparam _size The size of the array. + * @param _num_set The number of elements that have been set. + * @param _array The array to call the destructors on. + */ template void call_destructors_on_array_where_necessary(const size_t _num_set, std::array* _array) { diff --git a/include/rfl/parsing/call_destructors_on_tuple_where_necessary.hpp b/include/rfl/parsing/call_destructors_on_tuple_where_necessary.hpp index 88004a0d..ff871834 100644 --- a/include/rfl/parsing/call_destructors_on_tuple_where_necessary.hpp +++ b/include/rfl/parsing/call_destructors_on_tuple_where_necessary.hpp @@ -8,9 +8,15 @@ namespace rfl::parsing { -/// Because of the way we have allocated the fields, we need to manually -/// trigger the destructors. - +/** + * @brief Calls the destructor on a single element of a tuple, if necessary. + * + * @tparam TupleType The type of the tuple. + * @tparam _size The size of the tuple. + * @tparam _i The index of the element. + * @param _num_set The number of elements that have been set. + * @param _tup The tuple to call the destructor on. + */ template void call_destructor_on_one_tuple_element_if_necessary(const size_t _num_set, TupleType* _tup) { @@ -29,6 +35,13 @@ void call_destructor_on_one_tuple_element_if_necessary(const size_t _num_set, } } +/** + * @brief Calls the destructors on the elements of a tuple, if necessary. + * + * @tparam TupleType The type of the tuple. + * @param _num_set The number of elements that have been set. + * @param _tup The tuple to call the destructors on. + */ template void call_destructors_on_tuple_where_necessary(const size_t _num_set, TupleType* _tup) { diff --git a/include/rfl/parsing/call_destructors_where_necessary.hpp b/include/rfl/parsing/call_destructors_where_necessary.hpp index 3862afaf..40360976 100644 --- a/include/rfl/parsing/call_destructors_where_necessary.hpp +++ b/include/rfl/parsing/call_destructors_where_necessary.hpp @@ -8,9 +8,13 @@ namespace rfl::parsing { -/// Because of the way we have allocated the fields, we need to manually -/// trigger the destructors. - +/** + * @brief Calls the destructors on an array. + * + * @tparam T The type of the elements in the array. + * @param _size The size of the array. + * @param _ptr A pointer to the array. + */ template void call_destructor_on_array(const size_t _size, T* _ptr) { for (size_t i = 0; i < _size; ++i) { @@ -22,6 +26,15 @@ void call_destructor_on_array(const size_t _size, T* _ptr) { } } +/** + * @brief Calls the destructor on a single element of a view, if necessary. + * + * @tparam ViewType The type of the view. + * @tparam _size The size of the set array. + * @tparam _i The index of the element. + * @param _set A boolean array indicating which elements have been set. + * @param _view The view to call the destructor on. + */ template void call_destructor_on_one_if_necessary(const std::array& _set, ViewType* _view) { @@ -43,6 +56,14 @@ void call_destructor_on_one_if_necessary(const std::array& _set, } } +/** + * @brief Calls the destructors on the elements of a view, if necessary. + * + * @tparam ViewType The type of the view. + * @tparam _size The size of the set array. + * @param _set A boolean array indicating which elements have been set. + * @param _view The view to call the destructors on. + */ template void call_destructors_where_necessary(const std::array& _set, ViewType* _view) { diff --git a/include/rfl/parsing/is_empty.hpp b/include/rfl/parsing/is_empty.hpp index 4c596d36..41d5b851 100644 --- a/include/rfl/parsing/is_empty.hpp +++ b/include/rfl/parsing/is_empty.hpp @@ -13,6 +13,13 @@ namespace rfl { namespace parsing { +/** + * @brief Checks if a variable is empty. + * + * @tparam T The type of the variable. + * @param _var The variable to check. + * @return True if the variable is empty, false otherwise. + */ template static bool is_empty(const T& _var) { using Type = std::remove_cvref_t; diff --git a/include/rfl/parsing/is_forward_list.hpp b/include/rfl/parsing/is_forward_list.hpp index 2ac6fe79..4bca6c87 100644 --- a/include/rfl/parsing/is_forward_list.hpp +++ b/include/rfl/parsing/is_forward_list.hpp @@ -7,6 +7,11 @@ namespace rfl { namespace parsing { +/** + * @brief Trait to check if a type is a std::forward_list. + * + * @tparam T The type to check. + */ template class is_forward_list; diff --git a/include/rfl/parsing/is_map_like.hpp b/include/rfl/parsing/is_map_like.hpp index 1fb0cf65..95a704a0 100644 --- a/include/rfl/parsing/is_map_like.hpp +++ b/include/rfl/parsing/is_map_like.hpp @@ -8,6 +8,11 @@ namespace rfl { namespace parsing { +/** + * @brief Trait to check if a type is a map-like type. + * + * @tparam T The type to check. + */ template class is_map_like; diff --git a/include/rfl/parsing/is_map_like_not_multimap.hpp b/include/rfl/parsing/is_map_like_not_multimap.hpp index 83475765..87c2a0a6 100644 --- a/include/rfl/parsing/is_map_like_not_multimap.hpp +++ b/include/rfl/parsing/is_map_like_not_multimap.hpp @@ -8,6 +8,11 @@ namespace rfl { namespace parsing { +/** + * @brief Trait to check if a type is a map-like type, but not a multimap. + * + * @tparam T The type to check. + */ template class is_map_like_not_multimap; diff --git a/include/rfl/parsing/is_required.hpp b/include/rfl/parsing/is_required.hpp index c7ddb676..30fe10f6 100644 --- a/include/rfl/parsing/is_required.hpp +++ b/include/rfl/parsing/is_required.hpp @@ -20,8 +20,11 @@ namespace rfl { namespace parsing { -/// Determines whether a field in a named tuple is required. -/// General case - most fields are required. +/** + * @brief Trait to check if a type is never required. + * + * @tparam T The type to check. + */ template class is_never_required; @@ -40,6 +43,13 @@ class is_never_required> : public std::true_type {}; template constexpr bool is_never_required_v = is_never_required::value; +/** + * @brief Checks if a field of type T is required. + * + * @tparam T The type of the field. + * @tparam _ignore_empty_containers Whether to ignore empty containers. + * @return True if the field is required, false otherwise. + */ template consteval bool is_required() { using Type = std::remove_cvref_t>; diff --git a/include/rfl/parsing/is_set_like.hpp b/include/rfl/parsing/is_set_like.hpp index 1ccf1fc7..ed9b2066 100644 --- a/include/rfl/parsing/is_set_like.hpp +++ b/include/rfl/parsing/is_set_like.hpp @@ -8,6 +8,11 @@ namespace rfl { namespace parsing { +/** + * @brief Trait to check if a type is a set-like type. + * + * @tparam T The type to check. + */ template class is_set_like; diff --git a/include/rfl/parsing/is_tagged_union_wrapper.hpp b/include/rfl/parsing/is_tagged_union_wrapper.hpp index 31e0bcc5..281fc8cc 100644 --- a/include/rfl/parsing/is_tagged_union_wrapper.hpp +++ b/include/rfl/parsing/is_tagged_union_wrapper.hpp @@ -9,6 +9,11 @@ namespace rfl { namespace parsing { +/** + * @brief Trait to check if a type is a tagged union wrapper. + * + * @tparam T The type to check. + */ template class is_tagged_union_wrapper; diff --git a/include/rfl/parsing/is_vector_like.hpp b/include/rfl/parsing/is_vector_like.hpp index d48bee44..f10f23f8 100644 --- a/include/rfl/parsing/is_vector_like.hpp +++ b/include/rfl/parsing/is_vector_like.hpp @@ -11,6 +11,11 @@ namespace rfl { namespace parsing { +/** + * @brief Trait to check if a type is a vector-like type. + * + * @tparam T The type to check. + */ template class is_vector_like; diff --git a/include/rfl/parsing/is_view_reader.hpp b/include/rfl/parsing/is_view_reader.hpp index 42cf30ef..0afab185 100644 --- a/include/rfl/parsing/is_view_reader.hpp +++ b/include/rfl/parsing/is_view_reader.hpp @@ -5,6 +5,11 @@ namespace rfl ::parsing { +/** + * @brief Trait to check if a type is a view reader. + * + * @tparam T The type to check. + */ template class is_view_reader; diff --git a/include/rfl/parsing/make_type_name.hpp b/include/rfl/parsing/make_type_name.hpp index 5f2ed404..35e9a554 100644 --- a/include/rfl/parsing/make_type_name.hpp +++ b/include/rfl/parsing/make_type_name.hpp @@ -6,6 +6,12 @@ namespace rfl::parsing { +/** + * @brief Replaces all non-alphanumeric characters with underscores. + * + * @param _str The string to process. + * @return The processed string. + */ inline std::string replace_non_alphanumeric(std::string _str) { for (auto& ch : _str) { ch = std::isalnum(ch) ? ch : '_'; @@ -13,6 +19,12 @@ inline std::string replace_non_alphanumeric(std::string _str) { return _str; } +/** + * @brief Generates a type name for the type U. + * + * @tparam U The type to generate the name for. + * @return The type name. + */ template static std::string make_type_name() { if constexpr (is_tagged_union_wrapper_v) { diff --git a/include/rfl/parsing/schema/Type.hpp b/include/rfl/parsing/schema/Type.hpp index 824daa0d..ba2a1acf 100644 --- a/include/rfl/parsing/schema/Type.hpp +++ b/include/rfl/parsing/schema/Type.hpp @@ -111,10 +111,21 @@ struct RFL_API Type { Object, Optional, Reference, StringMap, Tuple, TypedArray, Validated>; + /** + * @brief Default constructor. + */ Type(); + /** + * @brief Constructor. + * + * @param _variant The variant to use. + */ Type(const VariantType& _variant); + /** + * @brief Destructor. + */ ~Type(); /// A type can be determined to be any of the above. diff --git a/include/rfl/parsing/schema/make.hpp b/include/rfl/parsing/schema/make.hpp index 94433858..2900232d 100644 --- a/include/rfl/parsing/schema/make.hpp +++ b/include/rfl/parsing/schema/make.hpp @@ -9,6 +9,15 @@ namespace rfl::parsing::schema { +/** + * @brief Generates the schema for the type T. + * + * @tparam R The reader type. + * @tparam W The writer type. + * @tparam T The type to generate the schema for. + * @tparam ProcessorsType The processors to use. + * @return The generated schema. + */ template Definition make() { std::map definitions; diff --git a/include/rfl/parsing/schemaful/IsSchemafulReader.hpp b/include/rfl/parsing/schemaful/IsSchemafulReader.hpp index 19ecdc8c..bada85f3 100644 --- a/include/rfl/parsing/schemaful/IsSchemafulReader.hpp +++ b/include/rfl/parsing/schemaful/IsSchemafulReader.hpp @@ -12,16 +12,31 @@ namespace rfl::parsing::schemaful { using MockVariantType = std::variant; +/** + * @brief A mock reader for maps. + * + * @tparam R The reader type. + */ template struct MockMapReader { void read(const std::string_view&, typename R::InputVarType&) const {} }; +/** + * @brief A mock reader for objects. + * + * @tparam R The reader type. + */ template struct MockObjectReader { void read(const int, typename R::InputVarType&) const {} }; +/** + * @brief A mock reader for unions. + * + * @tparam R The reader type. + */ template struct MockUnionReader { static rfl::Result read(const R&, const size_t, @@ -30,6 +45,11 @@ struct MockUnionReader { } }; +/** + * @brief Concept for a schemaful reader. + * + * @tparam R The reader type. + */ template concept IsSchemafulReader = requires(R r, typename R::InputVarType var, typename R::InputObjectType obj, diff --git a/include/rfl/parsing/schemaful/IsSchemafulWriter.hpp b/include/rfl/parsing/schemaful/IsSchemafulWriter.hpp index 68076838..87a14203 100644 --- a/include/rfl/parsing/schemaful/IsSchemafulWriter.hpp +++ b/include/rfl/parsing/schemaful/IsSchemafulWriter.hpp @@ -7,6 +7,11 @@ namespace rfl::parsing::schemaful { +/** + * @brief Concept for a schemaful writer. + * + * @tparam W The writer type. + */ template concept IsSchemafulWriter = requires( W w, typename W::OutputVarType var, typename W::OutputArrayType arr, diff --git a/include/rfl/parsing/schemaful/OptionalReader.hpp b/include/rfl/parsing/schemaful/OptionalReader.hpp index 6f423c54..6b57c2ae 100644 --- a/include/rfl/parsing/schemaful/OptionalReader.hpp +++ b/include/rfl/parsing/schemaful/OptionalReader.hpp @@ -11,6 +11,14 @@ namespace rfl::parsing::schemaful { template struct OptionalReader { + /** + * @brief Reads an optional value from the input. + * + * @param _r The reader to use. + * @param _index The index of the element in the union. + * @param _var The input variable to read from. + * @return A Result containing the parsed optional value or an error. + */ static Result> read( const R& _r, const size_t _index, const typename R::InputVarType& _var) noexcept { diff --git a/include/rfl/parsing/schemaful/SharedPtrReader.hpp b/include/rfl/parsing/schemaful/SharedPtrReader.hpp index 154e5b52..a2251c9c 100644 --- a/include/rfl/parsing/schemaful/SharedPtrReader.hpp +++ b/include/rfl/parsing/schemaful/SharedPtrReader.hpp @@ -11,6 +11,14 @@ namespace rfl::parsing::schemaful { template struct SharedPtrReader { + /** + * @brief Reads a shared_ptr from the input. + * + * @param _r The reader to use. + * @param _index The index of the element in the union. + * @param _var The input variable to read from. + * @return A Result containing the parsed shared_ptr or an error. + */ static Result> read( const R& _r, const size_t _index, const typename R::InputVarType& _var) noexcept { diff --git a/include/rfl/parsing/schemaful/UniquePtrReader.hpp b/include/rfl/parsing/schemaful/UniquePtrReader.hpp index b27fa23e..cc27ac44 100644 --- a/include/rfl/parsing/schemaful/UniquePtrReader.hpp +++ b/include/rfl/parsing/schemaful/UniquePtrReader.hpp @@ -11,6 +11,14 @@ namespace rfl::parsing::schemaful { template struct UniquePtrReader { + /** + * @brief Reads a unique_ptr from the input. + * + * @param _r The reader to use. + * @param _index The index of the alternative to read (0 for value, 1 for null). + * @param _var The input variable to read from. + * @return A Result containing the parsed unique_ptr or an error. + */ static Result> read( const R& _r, const size_t _index, const typename R::InputVarType& _var) noexcept { diff --git a/include/rfl/parsing/schemaful/VariantReader.hpp b/include/rfl/parsing/schemaful/VariantReader.hpp index 5b6656e4..ab0df0a1 100644 --- a/include/rfl/parsing/schemaful/VariantReader.hpp +++ b/include/rfl/parsing/schemaful/VariantReader.hpp @@ -14,6 +14,14 @@ template class VariantReader { public: + /** + * @brief Reads a variant from the input. + * + * @param _r The reader to use. + * @param _index The index of the alternative to read. + * @param _var The input variable to read from. + * @return A Result containing the parsed variant or an error. + */ static Result read( const R& _r, const size_t _index, const typename R::InputVarType& _var) noexcept { @@ -26,6 +34,15 @@ class VariantReader { } private: + /** + * @brief Tries to read one specific type of the variant. + * + * @tparam _i The index of the type to try. + * @param _r The reader to use. + * @param _index The index of the alternative to read. + * @param _var The input variable to read from. + * @param _result The result pointer to store the parsed variant. + */ template static void try_one_type(const R& _r, const size_t _index, const typename R::InputVarType& _var, diff --git a/include/rfl/parsing/schemaful/tuple_to_named_tuple.hpp b/include/rfl/parsing/schemaful/tuple_to_named_tuple.hpp index 65f654e1..4fe31b98 100644 --- a/include/rfl/parsing/schemaful/tuple_to_named_tuple.hpp +++ b/include/rfl/parsing/schemaful/tuple_to_named_tuple.hpp @@ -12,6 +12,12 @@ namespace rfl::parsing::schemaful { +/** + * @brief Generates a field name for a tuple element. + * + * @tparam _i The index of the element. + * @return The generated field name. + */ template inline consteval auto to_field_name() { return internal::StringLiteral<5>('f', @@ -20,14 +26,26 @@ inline consteval auto to_field_name() { static_cast('0' + (_i % 10))); } +/** + * @brief Converts a tuple element to a field. + * + * @tparam _i The index of the element. + * @param _t The element to convert. + * @return The generated field. + */ template inline auto to_field(const auto& _t) { using T = std::remove_cvref_t; return rfl::Field(), const T*>(&_t); } -/// Schemaful formats often don't have an explicit tuple representation. -/// This is the required workaround. +/** + * @brief Converts a Tuple to a NamedTuple. + * + * @tparam Ts The types in the tuple. + * @param _tup The tuple to convert. + * @return The generated NamedTuple. + */ template auto tuple_to_named_tuple(const Tuple& _tup) { static_assert(sizeof...(Ts) <= 1000, @@ -37,8 +55,13 @@ auto tuple_to_named_tuple(const Tuple& _tup) { }(std::make_integer_sequence()); } -/// Schemaful formats often don't have an explicit tuple representation. -/// This is the required workaround. +/** + * @brief Converts a std::tuple to a NamedTuple. + * + * @tparam Ts The types in the tuple. + * @param _tup The tuple to convert. + * @return The generated NamedTuple. + */ template auto tuple_to_named_tuple(const std::tuple& _tup) { static_assert(sizeof...(Ts) <= 1000, diff --git a/include/rfl/parsing/schemaful/tuple_to_object.hpp b/include/rfl/parsing/schemaful/tuple_to_object.hpp index 38515a48..79b5962a 100644 --- a/include/rfl/parsing/schemaful/tuple_to_object.hpp +++ b/include/rfl/parsing/schemaful/tuple_to_object.hpp @@ -6,8 +6,12 @@ namespace rfl::parsing::schemaful { -/// Schemaful formats often don't have an explicit tuple representation. -/// This is the required workaround. +/** + * @brief Converts a tuple schema type to an object schema type. + * + * @param _tup The tuple schema type. + * @return The object schema type. + */ RFL_API schema::Type::Object tuple_to_object(const schema::Type::Tuple& _tup); } // namespace rfl::parsing::schemaful diff --git a/include/rfl/parsing/supports_attributes.hpp b/include/rfl/parsing/supports_attributes.hpp index a6a2bdb2..6cb860c3 100644 --- a/include/rfl/parsing/supports_attributes.hpp +++ b/include/rfl/parsing/supports_attributes.hpp @@ -9,7 +9,11 @@ namespace rfl { namespace parsing { -/// Determines whether a writer supports attributes. +/** + * @brief Determines whether a writer supports attributes. + * + * @tparam W The writer type. + */ template concept supports_attributes = requires(W w, std::string_view name, typename W::OutputObjectType obj, diff --git a/include/rfl/parsing/supports_comments.hpp b/include/rfl/parsing/supports_comments.hpp index a91332b3..230c8f2b 100644 --- a/include/rfl/parsing/supports_comments.hpp +++ b/include/rfl/parsing/supports_comments.hpp @@ -10,7 +10,11 @@ namespace rfl::parsing { -/// Determines whether a writer supports comments. +/** + * @brief Determines whether a writer supports comments. + * + * @tparam W The writer type. + */ template concept supports_comments = requires(W w, typename W::OutputArrayType arr, diff --git a/include/rfl/parsing/tabular/ArrowReader.hpp b/include/rfl/parsing/tabular/ArrowReader.hpp index 90f18171..166b3135 100644 --- a/include/rfl/parsing/tabular/ArrowReader.hpp +++ b/include/rfl/parsing/tabular/ArrowReader.hpp @@ -47,6 +47,11 @@ class ArrowReader { public: using ValueType = typename std::remove_cvref_t; + /** + * @brief Creates a new ArrowReader. + * @param _table The arrow table to read from. + * @return An ArrowReader or an error. + */ static Result make(const std::shared_ptr& _table) { try { return ArrowReader(_table); @@ -57,6 +62,10 @@ class ArrowReader { ~ArrowReader() = default; + /** + * @brief Reads the data from the arrow table into a vector-like container. + * @return The vector-like container or an error. + */ Result read() const noexcept { return make_chunked_array_iterators, _s>( table_) @@ -74,15 +83,29 @@ class ArrowReader { } private: + /** + * @brief Constructor. + * @param _table The arrow table to read from. + */ ArrowReader(const std::shared_ptr& _table) : table_(Ref::make(_table).value()) {} + /** + * @brief Checks if the end of any chunked array iterator has been reached. + * @param _chunked_array_iterators The iterators to check. + * @return true if the end has been reached, false otherwise. + */ bool end(const auto& _chunked_array_iterators) const { return apply( [](const auto&... _its) { return (false || ... || _its.end()); }, _chunked_array_iterators); } + /** + * @brief Creates a new value from the chunked array iterators. + * @param _chunked_array_iterators The iterators to read from. + * @return The new value or an error. + */ Result new_value(auto* _chunked_array_iterators) const noexcept { alignas(ValueType) unsigned char buf[sizeof(ValueType)]{}; auto ptr = internal::ptr_cast(&buf); @@ -117,6 +140,12 @@ class ArrowReader { return std::move(*ptr); } + /** + * @brief Destroys the values that have been set in the view so far. + * @tparam _i The number of values that have been set. + * @tparam ViewType The type of the view. + * @param _view The view to destroy. + */ template void destroy_value(ViewType* _view) const { static_assert(_i < ViewType::size(), "_i out of bounds."); diff --git a/include/rfl/parsing/tabular/ArrowTypes.hpp b/include/rfl/parsing/tabular/ArrowTypes.hpp index 62818554..c0ed325f 100644 --- a/include/rfl/parsing/tabular/ArrowTypes.hpp +++ b/include/rfl/parsing/tabular/ArrowTypes.hpp @@ -28,6 +28,13 @@ enum class SerializationType { csv, parquet }; template struct ArrowTypes; +/** + * @brief Transforms a numerical array to the desired type T. + * @tparam T The desired type. + * @tparam _s The serialization type. + * @param _arr The array to transform. + * @return The transformed array or an error. + */ template Result::ArrayType>> transform_numerical_array( const std::shared_ptr& _arr) noexcept; @@ -37,8 +44,17 @@ struct ArrowTypes { using ArrayType = arrow::BooleanArray; using BuilderType = arrow::BooleanBuilder; + /** + * @brief Returns the Arrow data type for boolean. + * @return The Arrow data type. + */ static auto data_type() { return arrow::boolean(); } + /** + * @brief Adds a boolean value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const bool _val, BuilderType* _builder) { const auto status = _builder->Append(_val); if (!status.ok()) { @@ -46,6 +62,11 @@ struct ArrowTypes { } } + /** + * @brief Returns the boolean array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The boolean array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { if (_arr->type()->Equals(data_type())) { @@ -56,11 +77,21 @@ struct ArrowTypes { } } + /** + * @brief Returns the boolean value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The boolean value. + */ static Result get_value(const Ref& _chunk, const int64_t _ix) { return _chunk->Value(_ix); } + /** + * @brief Creates a builder for boolean arrays. + * @return The builder. + */ static auto make_builder() { return BuilderType(); } }; @@ -70,8 +101,17 @@ struct ArrowTypes { using BuilderType = arrow::UInt8Builder; using T = uint8_t; + /** + * @brief Returns the Arrow data type for uint8. + * @return The Arrow data type. + */ static auto data_type() { return arrow::uint8(); } + /** + * @brief Adds a uint8 value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto _val, BuilderType* _builder) { const auto status = _builder->Append(_val); if (!status.ok()) { @@ -79,16 +119,31 @@ struct ArrowTypes { } } + /** + * @brief Returns the uint8 array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The uint8 array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return transform_numerical_array(_arr); } + /** + * @brief Returns the uint8 value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The uint8 value. + */ static Result get_value(const Ref& _chunk, const int64_t _ix) { return _chunk->Value(_ix); } + /** + * @brief Creates a builder for uint8 arrays. + * @return The builder. + */ static auto make_builder() { return BuilderType(); } }; @@ -98,8 +153,17 @@ struct ArrowTypes { using BuilderType = arrow::UInt16Builder; using T = uint16_t; + /** + * @brief Returns the Arrow data type for uint16. + * @return The Arrow data type. + */ static auto data_type() { return arrow::uint16(); } + /** + * @brief Adds a uint16 value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto _val, BuilderType* _builder) { const auto status = _builder->Append(_val); if (!status.ok()) { @@ -107,16 +171,31 @@ struct ArrowTypes { } } + /** + * @brief Returns the uint16 array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The uint16 array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return transform_numerical_array(_arr); } + /** + * @brief Returns the uint16 value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The uint16 value. + */ static Result get_value(const Ref& _chunk, const int64_t _ix) { return _chunk->Value(_ix); } + /** + * @brief Creates a builder for uint16 arrays. + * @return The builder. + */ static auto make_builder() { return BuilderType(); } }; @@ -126,8 +205,17 @@ struct ArrowTypes { using BuilderType = arrow::UInt32Builder; using T = uint32_t; + /** + * @brief Returns the Arrow data type for uint32. + * @return The Arrow data type. + */ static auto data_type() { return arrow::uint32(); } + /** + * @brief Adds a uint32 value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto _val, BuilderType* _builder) { const auto status = _builder->Append(_val); if (!status.ok()) { @@ -135,16 +223,31 @@ struct ArrowTypes { } } + /** + * @brief Returns the uint32 array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The uint32 array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return transform_numerical_array(_arr); } + /** + * @brief Returns the uint32 value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The uint32 value. + */ static Result get_value(const Ref& _chunk, const int64_t _ix) { return _chunk->Value(_ix); } + /** + * @brief Creates a builder for uint32 arrays. + * @return The builder. + */ static auto make_builder() { return BuilderType(); } }; @@ -154,8 +257,17 @@ struct ArrowTypes { using BuilderType = arrow::UInt64Builder; using T = uint64_t; + /** + * @brief Returns the Arrow data type for uint64. + * @return The Arrow data type. + */ static auto data_type() { return arrow::uint64(); } + /** + * @brief Adds a uint64 value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto _val, BuilderType* _builder) { const auto status = _builder->Append(_val); if (!status.ok()) { @@ -163,16 +275,31 @@ struct ArrowTypes { } } + /** + * @brief Returns the uint64 array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The uint64 array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return transform_numerical_array(_arr); } + /** + * @brief Returns the uint64 value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The uint64 value. + */ static Result get_value(const Ref& _chunk, const int64_t _ix) { return _chunk->Value(_ix); } + /** + * @brief Creates a builder for uint64 arrays. + * @return The builder. + */ static auto make_builder() { return BuilderType(); } }; @@ -182,8 +309,17 @@ struct ArrowTypes { using BuilderType = arrow::Int8Builder; using T = int8_t; + /** + * @brief Returns the Arrow data type for int8. + * @return The Arrow data type. + */ static auto data_type() { return arrow::int8(); } + /** + * @brief Adds an int8 value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto _val, BuilderType* _builder) { const auto status = _builder->Append(_val); if (!status.ok()) { @@ -191,16 +327,31 @@ struct ArrowTypes { } } + /** + * @brief Returns the int8 array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The int8 array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return transform_numerical_array(_arr); } + /** + * @brief Returns the int8 value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The int8 value. + */ static Result get_value(const Ref& _chunk, const int64_t _ix) { return _chunk->Value(_ix); } + /** + * @brief Creates a builder for int8 arrays. + * @return The builder. + */ static auto make_builder() { return BuilderType(); } }; @@ -210,8 +361,17 @@ struct ArrowTypes { using BuilderType = arrow::Int16Builder; using T = int16_t; + /** + * @brief Returns the Arrow data type for int16. + * @return The Arrow data type. + */ static auto data_type() { return arrow::int16(); } + /** + * @brief Adds an int16 value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto _val, BuilderType* _builder) { const auto status = _builder->Append(_val); if (!status.ok()) { @@ -219,16 +379,31 @@ struct ArrowTypes { } } + /** + * @brief Returns the int16 array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The int16 array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return transform_numerical_array(_arr); } + /** + * @brief Returns the int16 value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The int16 value. + */ static Result get_value(const Ref& _chunk, const int64_t _ix) { return _chunk->Value(_ix); } + /** + * @brief Creates a builder for int16 arrays. + * @return The builder. + */ static auto make_builder() { return BuilderType(); } }; @@ -238,8 +413,17 @@ struct ArrowTypes { using BuilderType = arrow::Int32Builder; using T = int32_t; + /** + * @brief Returns the Arrow data type for int32. + * @return The Arrow data type. + */ static auto data_type() { return arrow::int32(); } + /** + * @brief Adds an int32 value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto _val, BuilderType* _builder) { const auto status = _builder->Append(_val); if (!status.ok()) { @@ -247,16 +431,31 @@ struct ArrowTypes { } } + /** + * @brief Returns the int32 array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The int32 array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return transform_numerical_array(_arr); } + /** + * @brief Returns the int32 value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The int32 value. + */ static Result get_value(const Ref& _chunk, const int64_t _ix) { return _chunk->Value(_ix); } + /** + * @brief Creates a builder for int32 arrays. + * @return The builder. + */ static auto make_builder() { return BuilderType(); } }; @@ -266,8 +465,17 @@ struct ArrowTypes { using BuilderType = arrow::Int64Builder; using T = int64_t; + /** + * @brief Returns the Arrow data type for int64. + * @return The Arrow data type. + */ static auto data_type() { return arrow::int64(); } + /** + * @brief Adds an int64 value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto _val, BuilderType* _builder) { const auto status = _builder->Append(_val); if (!status.ok()) { @@ -275,16 +483,31 @@ struct ArrowTypes { } } + /** + * @brief Returns the int64 array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The int64 array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return transform_numerical_array(_arr); } + /** + * @brief Returns the int64 value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The int64 value. + */ static Result get_value(const Ref& _chunk, const int64_t _ix) { return _chunk->Value(_ix); } + /** + * @brief Creates a builder for int64 arrays. + * @return The builder. + */ static auto make_builder() { return BuilderType(); } }; @@ -294,8 +517,17 @@ struct ArrowTypes { using BuilderType = arrow::FloatBuilder; using T = float; + /** + * @brief Returns the Arrow data type for float32. + * @return The Arrow data type. + */ static auto data_type() { return arrow::float32(); } + /** + * @brief Adds a float value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto _val, BuilderType* _builder) { const auto status = _builder->Append(_val); if (!status.ok()) { @@ -303,16 +535,31 @@ struct ArrowTypes { } } + /** + * @brief Returns the float array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The float array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return transform_numerical_array(_arr); } + /** + * @brief Returns the float value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The float value. + */ static Result get_value(const Ref& _chunk, const int64_t _ix) { return _chunk->Value(_ix); } + /** + * @brief Creates a builder for float arrays. + * @return The builder. + */ static auto make_builder() { return BuilderType(); } }; @@ -322,8 +569,17 @@ struct ArrowTypes { using BuilderType = arrow::DoubleBuilder; using T = double; + /** + * @brief Returns the Arrow data type for float64. + * @return The Arrow data type. + */ static auto data_type() { return arrow::float64(); } + /** + * @brief Adds a double value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto _val, BuilderType* _builder) { const auto status = _builder->Append(_val); if (!status.ok()) { @@ -331,16 +587,31 @@ struct ArrowTypes { } } + /** + * @brief Returns the double array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The double array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return transform_numerical_array(_arr); } + /** + * @brief Returns the double value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The double value. + */ static Result get_value(const Ref& _chunk, const int64_t _ix) { return _chunk->Value(_ix); } + /** + * @brief Creates a builder for double arrays. + * @return The builder. + */ static auto make_builder() { return BuilderType(); } }; @@ -349,8 +620,17 @@ struct ArrowTypes { using ArrayType = arrow::StringArray; using BuilderType = arrow::StringBuilder; + /** + * @brief Returns the Arrow data type for string (utf8). + * @return The Arrow data type. + */ static auto data_type() { return arrow::utf8(); } + /** + * @brief Adds a string value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto& _val, BuilderType* _builder) { const auto status = _builder->Append(_val); if (!status.ok()) { @@ -358,6 +638,11 @@ struct ArrowTypes { } } + /** + * @brief Returns the string array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The string array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { if (_arr->type()->Equals(data_type())) { @@ -368,11 +653,21 @@ struct ArrowTypes { } } + /** + * @brief Returns the string value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The string value. + */ static Result get_value(const Ref& _chunk, const int64_t _ix) { return std::string(_chunk->Value(_ix)); } + /** + * @brief Creates a builder for string arrays. + * @return The builder. + */ static auto make_builder() { return BuilderType(); } }; @@ -382,8 +677,17 @@ struct ArrowTypes { using ArrayType = arrow::StringArray; using BuilderType = arrow::StringBuilder; + /** + * @brief Returns the Arrow data type for enums (utf8). + * @return The Arrow data type. + */ static auto data_type() { return arrow::utf8(); } + /** + * @brief Adds an enum value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const T _val, BuilderType* _builder) { const auto status = _builder->Append(enum_to_string(_val)); if (!status.ok()) { @@ -391,15 +695,30 @@ struct ArrowTypes { } } + /** + * @brief Returns the enum array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The enum array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return ArrowTypes::get_array(_arr); } + /** + * @brief Returns the enum value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The enum value. + */ static Result get_value(const Ref& _chunk, const int64_t _ix) { return string_to_enum(std::string(_chunk->Value(_ix))); } + /** + * @brief Creates a builder for enum arrays. + * @return The builder. + */ static auto make_builder() { return BuilderType(); } }; @@ -409,8 +728,17 @@ struct ArrowTypes { using ArrayType = arrow::BinaryArray; using BuilderType = arrow::BinaryBuilder; + /** + * @brief Returns the Arrow data type for binary. + * @return The Arrow data type. + */ static auto data_type() { return arrow::binary(); } + /** + * @brief Adds a binary value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto& _val, BuilderType* _builder) { const auto status = _builder->Append( internal::ptr_cast(_val.data()), _val.size()); @@ -419,6 +747,11 @@ struct ArrowTypes { } } + /** + * @brief Returns the binary array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The binary array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { if (_arr->type()->Equals(data_type())) { @@ -434,14 +767,29 @@ struct ArrowTypes { } } + /** + * @brief Returns the binary value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The binary value. + */ static Result get_value(const Ref& _chunk, const int64_t _ix) { const auto begin = internal::ptr_cast( _chunk->Value(_ix).data()); return T(begin, begin + _chunk->Value(_ix).size()); } + /** + * @brief Creates a builder for binary arrays. + * @return The builder. + */ static auto make_builder() { return BuilderType(); } + /** + * @brief Transforms a string array to a binary array. + * @param _arr The string array. + * @return The binary array or an error. + */ static Result> transform_string( const std::shared_ptr& _arr) noexcept { if (!_arr) { @@ -482,8 +830,17 @@ struct ArrowTypes, _s> { using ArrayType = arrow::TimestampArray; using BuilderType = arrow::TimestampBuilder; + /** + * @brief Returns the Arrow data type for timestamps (milli). + * @return The Arrow data type. + */ static auto data_type() { return arrow::timestamp(arrow::TimeUnit::MILLI); } + /** + * @brief Adds a timestamp value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto& _val, BuilderType* _builder) { const auto status = _builder->Append(_val.to_time_t() * 1000); if (!status.ok()) { @@ -491,6 +848,11 @@ struct ArrowTypes, _s> { } } + /** + * @brief Returns the timestamp array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The timestamp array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { if (_arr->type()->Equals(data_type())) { @@ -527,15 +889,32 @@ struct ArrowTypes, _s> { } } + /** + * @brief Returns the timestamp value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The timestamp value. + */ static Result> get_value(const Ref& _chunk, const int64_t _ix) { return Timestamp<_format>(_chunk->Value(_ix) / 1000); } + /** + * @brief Creates a builder for timestamp arrays. + * @return The builder. + */ static auto make_builder() { return BuilderType(data_type(), arrow::default_memory_pool()); } + /** + * @brief Transforms an array with different time units to a timestamp array. + * @tparam _unit The time unit of the source array. + * @tparam SourceArrayType The type of the source array. + * @param _arr The source array. + * @return The timestamp array or an error. + */ template static Result> transform_time_stamp( const std::shared_ptr& _arr) noexcept { @@ -613,8 +992,17 @@ struct ArrowTypes, SerializationType::csv> { using ArrayType = arrow::TimestampArray; using BuilderType = arrow::StringBuilder; + /** + * @brief Returns the Arrow data type for timestamps (milli). + * @return The Arrow data type. + */ static auto data_type() { return arrow::timestamp(arrow::TimeUnit::MILLI); } + /** + * @brief Adds a timestamp value to the builder (as string for CSV). + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const Timestamp<_format>& _val, BuilderType* _builder) { const auto status = _builder->Append(_val.str()); @@ -623,18 +1011,33 @@ struct ArrowTypes, SerializationType::csv> { } } + /** + * @brief Returns the timestamp array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The timestamp array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return ArrowTypes, SerializationType::parquet>::get_array(_arr); } + /** + * @brief Returns the timestamp value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The timestamp value. + */ static Result> get_value(const Ref& _chunk, const int64_t _ix) { return ArrowTypes, SerializationType::parquet>::get_value(_chunk, _ix); } + /** + * @brief Creates a builder for timestamp arrays (string builder for CSV). + * @return The builder. + */ static auto make_builder() { return BuilderType(); } }; @@ -646,20 +1049,40 @@ struct ArrowTypes { using BuilderType = typename ArrowTypes::BuilderType; + /** + * @brief Returns the Arrow data type for T based on its ReflectionType. + * @return The Arrow data type. + */ static auto data_type() { return ArrowTypes::data_type(); } + /** + * @brief Adds a value of type T to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto& _val, BuilderType* _builder) { ArrowTypes::add_to_builder( _val.reflection(), _builder); } + /** + * @brief Returns the array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return ArrowTypes::get_array(_arr); } + /** + * @brief Returns the value of type T from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The value of type T. + */ static Result get_value(const Ref& _chunk, const int64_t _ix) { return ArrowTypes, _s>::get_value(_chunk, _ix) @@ -672,6 +1095,10 @@ struct ArrowTypes { }); } + /** + * @brief Creates a builder for arrays of type T. + * @return The builder. + */ static auto make_builder() { return ArrowTypes::make_builder(); } @@ -683,8 +1110,17 @@ struct ArrowTypes, _s> { using BuilderType = typename ArrowTypes, _s>::BuilderType; + /** + * @brief Returns the Arrow data type for optional T. + * @return The Arrow data type. + */ static auto data_type() { return ArrowTypes::data_type(); } + /** + * @brief Adds an optional value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto& _val, BuilderType* _builder) { if (_val) { ArrowTypes::add_to_builder(*_val, _builder); @@ -696,16 +1132,31 @@ struct ArrowTypes, _s> { } } + /** + * @brief Returns the array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return ArrowTypes::get_array(_arr); } + /** + * @brief Returns the optional value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The optional value. + */ static auto get_value(const Ref& _chunk, const int64_t _ix) { return ArrowTypes, _s>::get_value(_chunk, _ix) .transform([](const auto& _v) { return std::make_optional(_v); }); } + /** + * @brief Creates a builder for arrays of optional T. + * @return The builder. + */ static auto make_builder() { return ArrowTypes::make_builder(); } }; @@ -715,8 +1166,17 @@ struct ArrowTypes, _s> { using BuilderType = typename ArrowTypes, _s>::BuilderType; + /** + * @brief Returns the Arrow data type for shared_ptr T. + * @return The Arrow data type. + */ static auto data_type() { return ArrowTypes::data_type(); } + /** + * @brief Adds a shared_ptr value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto& _val, BuilderType* _builder) { if (_val) { ArrowTypes::add_to_builder(*_val, _builder); @@ -728,16 +1188,31 @@ struct ArrowTypes, _s> { } } + /** + * @brief Returns the array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return ArrowTypes::get_array(_arr); } + /** + * @brief Returns the shared_ptr value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The shared_ptr value. + */ static auto get_value(const Ref& _chunk, const int64_t _ix) { return ArrowTypes, _s>::get_value(_chunk, _ix) .transform([](const auto& _v) { return std::make_shared(_v); }); } + /** + * @brief Creates a builder for arrays of shared_ptr T. + * @return The builder. + */ static auto make_builder() { return ArrowTypes::make_builder(); } }; @@ -747,8 +1222,17 @@ struct ArrowTypes, _s> { using BuilderType = typename ArrowTypes, _s>::BuilderType; + /** + * @brief Returns the Arrow data type for unique_ptr T. + * @return The Arrow data type. + */ static auto data_type() { return ArrowTypes::data_type(); } + /** + * @brief Adds a unique_ptr value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto& _val, BuilderType* _builder) { if (_val) { ArrowTypes::add_to_builder(*_val, _builder); @@ -760,16 +1244,31 @@ struct ArrowTypes, _s> { } } + /** + * @brief Returns the array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return ArrowTypes::get_array(_arr); } + /** + * @brief Returns the unique_ptr value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The unique_ptr value. + */ static auto get_value(const Ref& _chunk, const int64_t _ix) { return ArrowTypes, _s>::get_value(_chunk, _ix) .transform([](const auto& _v) { return std::make_unique(_v); }); } + /** + * @brief Creates a builder for arrays of unique_ptr T. + * @return The builder. + */ static auto make_builder() { return ArrowTypes::make_builder(); } }; @@ -779,22 +1278,46 @@ struct ArrowTypes, _s> { using BuilderType = typename ArrowTypes, _s>::BuilderType; + /** + * @brief Returns the Arrow data type for Box T. + * @return The Arrow data type. + */ static auto data_type() { return ArrowTypes::data_type(); } + /** + * @brief Adds a Box value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto& _val, BuilderType* _builder) { ArrowTypes::add_to_builder(*_val, _builder); } + /** + * @brief Returns the array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return ArrowTypes::get_array(_arr); } + /** + * @brief Returns the Box value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The Box value. + */ static auto get_value(const Ref& _chunk, const int64_t _ix) { return ArrowTypes, _s>::get_value(_chunk, _ix) .transform([](const auto& _v) { return Box::make(_v); }); } + /** + * @brief Creates a builder for arrays of Box T. + * @return The builder. + */ static auto make_builder() { return ArrowTypes::make_builder(); } }; @@ -804,22 +1327,46 @@ struct ArrowTypes, _s> { using BuilderType = typename ArrowTypes, _s>::BuilderType; + /** + * @brief Returns the Arrow data type for Ref T. + * @return The Arrow data type. + */ static auto data_type() { return ArrowTypes::data_type(); } + /** + * @brief Adds a Ref value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto& _val, BuilderType* _builder) { ArrowTypes::add_to_builder(*_val, _builder); } + /** + * @brief Returns the array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return ArrowTypes::get_array(_arr); } + /** + * @brief Returns the Ref value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The Ref value. + */ static auto get_value(const Ref& _chunk, const int64_t _ix) { return ArrowTypes, _s>::get_value(_chunk, _ix) .transform([](const auto& _v) { return Ref::make(_v); }); } + /** + * @brief Creates a builder for arrays of Ref T. + * @return The builder. + */ static auto make_builder() { return ArrowTypes::make_builder(); } }; @@ -829,25 +1376,57 @@ struct ArrowTypes, _s> { using BuilderType = typename ArrowTypes, _s>::BuilderType; + /** + * @brief Returns the Arrow data type for Rename T. + * @return The Arrow data type. + */ static auto data_type() { return ArrowTypes::data_type(); } + /** + * @brief Adds a Rename value to the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ static void add_to_builder(const auto& _val, BuilderType* _builder) { ArrowTypes::add_to_builder(_val.value(), _builder); } + /** + * @brief Returns the array from the shared pointer. + * @param _arr The shared pointer to the arrow array. + * @return The array or an error. + */ static Result> get_array( const std::shared_ptr& _arr) { return ArrowTypes::get_array(_arr); } + /** + * @brief Returns the Rename value from the array at the given index. + * @param _chunk The array to get the value from. + * @param _ix The index of the value. + * @return The Rename value. + */ static auto get_value(const Ref& _chunk, const int64_t _ix) { return ArrowTypes, _s>::get_value(_chunk, _ix) .transform([](const auto& _v) { return Rename<_name, T>(_v); }); } + /** + * @brief Creates a builder for arrays of Rename T. + * @return The builder. + */ static auto make_builder() { return ArrowTypes::make_builder(); } }; +/** + * @brief Implementation of numerical array transformation. + * @tparam T The target type. + * @tparam _s The serialization type. + * @tparam SourceArrayType The type of the source array. + * @param _arr The source array. + * @return The transformed array or an error. + */ template Result::ArrayType>> transform_numerical_array_impl( @@ -882,6 +1461,13 @@ transform_numerical_array_impl( std::static_pointer_cast(res)); } +/** + * @brief Transforms a numerical array to the desired type T. + * @tparam T The desired type. + * @tparam _s The serialization type. + * @param _arr The array to transform. + * @return The transformed array or an error. + */ template Result::ArrayType>> transform_numerical_array( const std::shared_ptr& _arr) noexcept { diff --git a/include/rfl/parsing/tabular/ArrowWriter.hpp b/include/rfl/parsing/tabular/ArrowWriter.hpp index 087c5761..2b240676 100644 --- a/include/rfl/parsing/tabular/ArrowWriter.hpp +++ b/include/rfl/parsing/tabular/ArrowWriter.hpp @@ -44,10 +44,21 @@ class ArrowWriter { public: using ValueType = typename std::remove_cvref_t; + /** + * @brief Constructor. + * + * @param _chunksize The chunk size. + */ ArrowWriter(const size_t _chunksize) : chunksize_(_chunksize) {} ~ArrowWriter() = default; + /** + * @brief Converts the data to an Arrow table. + * + * @param _data The data to convert. + * @return The Arrow table. + */ std::shared_ptr to_table(const VecType& _data) const { return arrow::Table::Make( make_arrow_schema, _s>(), @@ -55,6 +66,12 @@ class ArrowWriter { } private: + /** + * @brief Converts the data to chunked arrays. + * + * @param _data The data to convert. + * @return The chunked arrays. + */ std::vector> to_chunked_arrays( const VecType& _data) const; diff --git a/include/rfl/parsing/tabular/ChunkedArrayIterator.hpp b/include/rfl/parsing/tabular/ChunkedArrayIterator.hpp index b29a2723..5e1ebbee 100644 --- a/include/rfl/parsing/tabular/ChunkedArrayIterator.hpp +++ b/include/rfl/parsing/tabular/ChunkedArrayIterator.hpp @@ -19,15 +19,28 @@ class ChunkedArrayIterator { using ArrayType = array_t; + /** + * @brief Creates a new ChunkedArrayIterator. + * @param _arr The chunked array to iterate over. + * @return A ChunkedArrayIterator. + */ static ChunkedArrayIterator make(const Ref& _arr) { return ChunkedArrayIterator(_arr); } + /** + * @brief Constructor. + * @param _arr The chunked array to iterate over. + */ ChunkedArrayIterator(const Ref& _arr) : arr_(_arr), chunk_ix_(0), current_chunk_(get_chunk(arr_, 0)), ix_(0) {} ~ChunkedArrayIterator() = default; + /** + * @brief Returns the value at the current position. + * @return A Result containing the value or an error. + */ Result operator*() const noexcept { const bool is_null = current_chunk_ @@ -46,8 +59,16 @@ class ChunkedArrayIterator { [&](const auto& _c) { return ArrowTypes::get_value(_c, ix_); }); } + /** + * @brief Checks if the iterator has reached the end. + * @return true if the end has been reached, false otherwise. + */ bool end() const noexcept { return chunk_ix_ >= arr_->num_chunks(); } + /** + * @brief Advances the iterator to the next position. + * @return A reference to the iterator. + */ ChunkedArrayIterator& operator++() noexcept { if (!current_chunk_) { return *this; @@ -61,9 +82,18 @@ class ChunkedArrayIterator { return *this; } + /** + * @brief Advances the iterator to the next position (postfix). + */ void operator++(int) noexcept { ++*this; } private: + /** + * @brief Returns the chunk at the specified index. + * @param _arr The chunked array. + * @param _chunk_ix The index of the chunk. + * @return A Result containing the chunk or an error. + */ static Result> get_chunk(const Ref& _arr, const int _chunk_ix) noexcept { if (_chunk_ix < _arr->num_chunks()) { diff --git a/include/rfl/parsing/tabular/add_to_builder.hpp b/include/rfl/parsing/tabular/add_to_builder.hpp index d353cbc5..6b7341d9 100644 --- a/include/rfl/parsing/tabular/add_to_builder.hpp +++ b/include/rfl/parsing/tabular/add_to_builder.hpp @@ -8,6 +8,15 @@ namespace rfl::parsing::tabular { +/** + * @brief Adds a value to an Arrow builder. + * + * @tparam _s The serialization type. + * @tparam ValueType The type of the value. + * @tparam BuilderType The type of the builder. + * @param _val The value to add. + * @param _builder The builder to add to. + */ template inline void add_to_builder(const ValueType& _val, BuilderType* _builder) { ArrowTypes, _s>::add_to_builder(_val, diff --git a/include/rfl/parsing/tabular/make_arrow_builders.hpp b/include/rfl/parsing/tabular/make_arrow_builders.hpp index 1ab8e506..85b0de11 100644 --- a/include/rfl/parsing/tabular/make_arrow_builders.hpp +++ b/include/rfl/parsing/tabular/make_arrow_builders.hpp @@ -22,6 +22,10 @@ template struct ArrowBuildersType, _s> { using Type = Tuple...>; + /** + * @brief Returns the data types for the fields in the named tuple. + * @return An array of shared pointers to the data types. + */ static auto data_types() { return [&](std::integer_sequence) { return std::array, @@ -30,10 +34,18 @@ struct ArrowBuildersType, _s> { }(std::make_integer_sequence()); } + /** + * @brief Creates the builders for the fields in the named tuple. + * @return A tuple of arrow builders. + */ static Type make_builders() { return Type(ArrowTypes::make_builder()...); } + /** + * @brief Generates the arrow schema for the fields in the named tuple. + * @return A shared pointer to the arrow schema. + */ static auto schema() { const auto fields = std::vector>({arrow::field( @@ -43,6 +55,12 @@ struct ArrowBuildersType, _s> { } }; +/** + * @brief Creates the arrow builders for the fields in the named tuple T. + * @tparam T The named tuple type. + * @tparam _s The serialization type. + * @return A tuple of arrow builders. + */ template auto make_arrow_builders() { return ArrowBuildersType, _s>::make_builders(); diff --git a/include/rfl/parsing/tabular/make_arrow_data_types.hpp b/include/rfl/parsing/tabular/make_arrow_data_types.hpp index d153fcfc..0e8e1ddc 100644 --- a/include/rfl/parsing/tabular/make_arrow_data_types.hpp +++ b/include/rfl/parsing/tabular/make_arrow_data_types.hpp @@ -8,6 +8,13 @@ namespace rfl::parsing::tabular { +/** + * @brief Returns the Arrow data types for type T. + * + * @tparam T The type to get data types for. + * @tparam _s The serialization type. + * @return The Arrow data types. + */ template inline auto make_arrow_data_types() { return ArrowBuildersType>, diff --git a/include/rfl/parsing/tabular/make_arrow_schema.hpp b/include/rfl/parsing/tabular/make_arrow_schema.hpp index 8139b451..34a23c2f 100644 --- a/include/rfl/parsing/tabular/make_arrow_schema.hpp +++ b/include/rfl/parsing/tabular/make_arrow_schema.hpp @@ -8,6 +8,13 @@ namespace rfl::parsing::tabular { +/** + * @brief Returns the Arrow schema for type T. + * + * @tparam T The type to get the schema for. + * @tparam _s The serialization type. + * @return The Arrow schema. + */ template inline auto make_arrow_schema() { return ArrowBuildersType>, _s>::schema(); diff --git a/include/rfl/parsing/tabular/make_chunked_array_iterators.hpp b/include/rfl/parsing/tabular/make_chunked_array_iterators.hpp index bf65dffb..2cf66a56 100644 --- a/include/rfl/parsing/tabular/make_chunked_array_iterators.hpp +++ b/include/rfl/parsing/tabular/make_chunked_array_iterators.hpp @@ -21,6 +21,11 @@ struct MakeChunkedArrayIterators, _s> { using TupleType = Tuple...>; + /** + * @brief Creates a tuple of chunked array iterators for the fields in the named tuple. + * @param _table The arrow table to read from. + * @return A Result containing the tuple of iterators or an error. + */ Result operator()(const Ref& _table) const { const auto get_column = [&](const std::string& _colname) -> Result> { diff --git a/include/rfl/parsing/to_single_error_message.hpp b/include/rfl/parsing/to_single_error_message.hpp index 4e7ec6a0..88163cf3 100644 --- a/include/rfl/parsing/to_single_error_message.hpp +++ b/include/rfl/parsing/to_single_error_message.hpp @@ -11,7 +11,14 @@ namespace rfl::parsing { -/// Combines a set of errors to a single, readable error message. +/** + * @brief Combines a set of errors to a single, readable error message. + * + * @param _errors The vector of error messages. + * @param _msg_prefix An optional prefix for the error message. + * @param _err_limit The maximum number of errors to show. + * @return The combined error message. + */ inline std::string to_single_error_message( std::vector _errors, std::optional _msg_prefix = std::nullopt, diff --git a/include/rfl/remove_fields.hpp b/include/rfl/remove_fields.hpp index 3721abfc..dd7d1f39 100644 --- a/include/rfl/remove_fields.hpp +++ b/include/rfl/remove_fields.hpp @@ -10,8 +10,12 @@ namespace rfl { -/// Recursively removes all of the fields signified by _names from the -/// NamedTupleType. +/// Recursively removes all of the fields signified by _names from the NamedTupleType. +/// This type alias creates a new NamedTuple type with specified fields removed. +/// The removal is recursive - if the NamedTuple contains nested NamedTuples, +/// the removal will be applied to those as well. +/// @tparam NamedTupleType The NamedTuple type to remove fields from +/// @tparam _names The compile-time string literal names of fields to remove template using remove_fields_t = typename internal::remove_fields, diff --git a/include/rfl/to_named_tuple.hpp b/include/rfl/to_named_tuple.hpp index 441dd549..b180f709 100644 --- a/include/rfl/to_named_tuple.hpp +++ b/include/rfl/to_named_tuple.hpp @@ -17,8 +17,11 @@ namespace rfl { /// Generates the named tuple that is equivalent to the struct _t. -/// If _t already is a named tuple, then _t will be returned. +/// A named tuple is like a std::tuple but with compile-time string names for each field. +/// If _t is already a named tuple, it will be returned unchanged. /// All fields of the struct must be an rfl::Field. +/// @param _t The struct or named tuple to convert (rvalue reference version) +/// @return A named tuple representation of the struct auto to_named_tuple(auto&& _t) { using T = std::remove_cvref_t; if constexpr (internal::is_named_tuple_v>) { @@ -34,9 +37,13 @@ auto to_named_tuple(auto&& _t) { } } -/// Generates the named tuple that is equivalent to the struct _t. -/// If _t already is a named tuple, then _t will be returned. +/// Generates the named tuple that is equivalent to the struct _t (const version). +/// A named tuple is like a std::tuple but with compile-time string names for each field. +/// If _t is already a named tuple, it will be returned unchanged. /// All fields of the struct must be an rfl::Field. +/// @tparam ProcessorsType The processors type (for template compatibility) +/// @param _t The struct or named tuple to convert (const reference) +/// @return A named tuple representation of the struct template auto to_named_tuple(const auto& _t) { using T = std::remove_cvref_t; diff --git a/include/rfl/to_view.hpp b/include/rfl/to_view.hpp index d9c31a04..eb2e2699 100644 --- a/include/rfl/to_view.hpp +++ b/include/rfl/to_view.hpp @@ -10,6 +10,9 @@ namespace rfl { +/// Converts a struct to a view (named tuple of pointers to fields). +/// @param _t The struct to convert to a view +/// @return A named tuple containing pointers to the fields of the struct template auto to_view(T& _t) { return internal::to_ptr_named_tuple(_t); diff --git a/include/rfl/toml/Reader.hpp b/include/rfl/toml/Reader.hpp index 2dda297d..47b3eeff 100644 --- a/include/rfl/toml/Reader.hpp +++ b/include/rfl/toml/Reader.hpp @@ -18,16 +18,21 @@ #include "../always_false.hpp" namespace rfl::toml { - struct Reader { using InputArrayType = ::toml::array*; using InputObjectType = ::toml::table*; using InputVarType = ::toml::node*; + /// @brief Checks if type T has a custom constructor from a TOML object. + /// @tparam T The type to check. template static constexpr bool has_custom_constructor = (requires(InputVarType var) { T::from_toml_obj(var); }); + /// @brief Retrieves a field from a TOML array by index. + /// @param _idx The index of the field. + /// @param _arr The TOML array pointer. + /// @return The node at the given index or an error if out of bounds. rfl::Result get_field_from_array( const size_t _idx, const InputArrayType _arr) const noexcept { if (_idx >= _arr->size()) { @@ -36,6 +41,10 @@ struct Reader { return _arr->get(_idx); } + /// @brief Retrieves a field from a TOML object by name. + /// @param _name The name of the field. + /// @param _obj The TOML object pointer. + /// @return The node corresponding to the field name or an error if not found. rfl::Result get_field_from_object( const std::string& _name, const InputObjectType& _obj) const noexcept { auto var = (*_obj)[_name]; @@ -45,10 +54,17 @@ struct Reader { return var.node(); } + /// @brief Checks if a TOML node is empty. + /// @param _var The TOML node pointer. + /// @return True if the node is empty, false otherwise. bool is_empty(const InputVarType& _var) const noexcept { return !_var && true; } + /// @brief Converts a TOML node to a basic type. + /// @tparam T The target type. + /// @param _var The TOML node pointer. + /// @return The converted value or an error if conversion fails. template rfl::Result to_basic_type(const InputVarType& _var) const noexcept { if constexpr (std::is_same, std::string>()) { @@ -80,6 +96,9 @@ struct Reader { } } + /// @brief Converts a TOML node to an array pointer. + /// @param _var The TOML node pointer. + /// @return The array pointer or an error if conversion fails. rfl::Result to_array( const InputVarType& _var) const noexcept { const auto ptr = _var->as_array(); @@ -89,6 +108,11 @@ struct Reader { return ptr; } + /// @brief Reads all elements of a TOML array using a provided reader. + /// @tparam ArrayReader The reader type. + /// @param _array_reader The array reader instance. + /// @param _arr The TOML array pointer. + /// @return An optional error if reading fails, otherwise std::nullopt. template std::optional read_array(const ArrayReader& _array_reader, const InputArrayType& _arr) const noexcept { @@ -101,6 +125,11 @@ struct Reader { return std::nullopt; } + /// @brief Reads all fields of a TOML object using a provided reader. + /// @tparam ObjectReader The reader type. + /// @param _object_reader The object reader instance. + /// @param _obj The TOML object pointer. + /// @return An optional error if reading fails, otherwise std::nullopt. template std::optional read_object(const ObjectReader& _object_reader, InputObjectType _obj) const noexcept { @@ -110,6 +139,9 @@ struct Reader { return std::nullopt; } + /// @brief Converts a TOML node to an object pointer. + /// @param _var The TOML node pointer. + /// @return The object pointer or an error if conversion fails. rfl::Result to_object( const InputVarType& _var) const noexcept { const auto ptr = _var->as_table(); @@ -119,6 +151,10 @@ struct Reader { return ptr; } + /// @brief Uses a custom constructor to convert a TOML node to type T. + /// @tparam T The target type. + /// @param _var The TOML node pointer. + /// @return The constructed value or an error if construction fails. template rfl::Result use_custom_constructor( const InputVarType _var) const noexcept { diff --git a/include/rfl/toml/load.hpp b/include/rfl/toml/load.hpp index 1f209218..326506a3 100644 --- a/include/rfl/toml/load.hpp +++ b/include/rfl/toml/load.hpp @@ -7,6 +7,12 @@ namespace rfl::toml { +/// Loads an object from a TOML file. +/// Reads a file from disk and parses its TOML content into a C++ object using compile-time reflection. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _fname The filename/path of the TOML file to load +/// @return Result containing either the parsed object of type T or an error message template Result load(const std::string& _fname) { const auto read_string = [](const auto& _str) { diff --git a/include/rfl/toml/read.hpp b/include/rfl/toml/read.hpp index 6f063ae4..e8346879 100644 --- a/include/rfl/toml/read.hpp +++ b/include/rfl/toml/read.hpp @@ -16,7 +16,12 @@ namespace rfl::toml { using InputVarType = typename Reader::InputVarType; -/// Parses an object from a TOML var. +/// Parses an object from a TOML var (internal TOML node representation). +/// A TOML var is the internal representation used by the toml++ library. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _var The TOML variant object to parse from +/// @return The parsed object of type T template auto read(InputVarType _var) { const auto r = Reader(); @@ -27,7 +32,12 @@ auto read(InputVarType _var) { return Parser::read(r, _var); } -/// Reads a TOML string. +/// Reads a TOML string and parses it into an object. +/// This function reads a TOML string and constructs a C++ object using compile-time reflection. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _toml_str The TOML string to parse +/// @return Result containing either the parsed object (or array of objects) or an error message template Result> read( const std::string_view _toml_str) noexcept { @@ -47,7 +57,12 @@ Result> read( #endif } -/// Parses an object from a stringstream. +/// Parses an object from a stringstream containing TOML. +/// Reads the entire stream content and parses it as TOML. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _stream The input stream containing TOML data +/// @return Result containing either the parsed object (or array of objects) or an error message template auto read(std::istream& _stream) { const auto toml_str = std::string(std::istreambuf_iterator(_stream), diff --git a/include/rfl/toml/save.hpp b/include/rfl/toml/save.hpp index d15bd7b7..a79a0678 100644 --- a/include/rfl/toml/save.hpp +++ b/include/rfl/toml/save.hpp @@ -12,6 +12,12 @@ namespace rfl { namespace toml { +/// Saves an object to a TOML file. +/// Serializes a C++ object to TOML and writes it to a file using compile-time reflection. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _fname The filename/path where the TOML file will be saved +/// @param _obj The object to serialize to TOML +/// @return Result containing Nothing on success or an error message on failure template Result save(const std::string& _fname, const auto& _obj) { const auto write_func = [](const auto& _obj, auto& _stream) -> auto& { diff --git a/include/rfl/toml/write.hpp b/include/rfl/toml/write.hpp index e7de4a33..05d62d47 100644 --- a/include/rfl/toml/write.hpp +++ b/include/rfl/toml/write.hpp @@ -14,7 +14,12 @@ namespace rfl::toml { -/// Writes a TOML into an ostream. +/// Writes a TOML representation into an ostream. +/// Uses compile-time reflection to serialize a C++ object to TOML and write to a stream. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to TOML +/// @param _stream The output stream to write TOML to +/// @return The output stream (for chaining) template std::ostream& write(const auto& _obj, std::ostream& _stream) { using T = std::remove_cvref_t; @@ -30,7 +35,11 @@ std::ostream& write(const auto& _obj, std::ostream& _stream) { return _stream; } -/// Returns a TOML string. +/// Returns a TOML string representation of the object. +/// Uses compile-time reflection to serialize a C++ object to TOML format. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to TOML +/// @return TOML string representation of the object template std::string write(const auto& _obj) { using T = std::remove_cvref_t; diff --git a/include/rfl/tuple_cat.hpp b/include/rfl/tuple_cat.hpp index da558f54..36f66aa6 100644 --- a/include/rfl/tuple_cat.hpp +++ b/include/rfl/tuple_cat.hpp @@ -6,17 +6,27 @@ namespace rfl { +/// Concatenates multiple tuples (const reference version). +/// @param _head The first tuple +/// @param _tail The remaining tuples to concatenate +/// @return A new tuple containing all elements from all input tuples template auto tuple_cat(const Head& _head, const Tail&... _tail) { return internal::tuple::concat(_head, _tail...); } +/// Concatenates multiple tuples (rvalue reference version). +/// @param _head The first tuple +/// @param _tail The remaining tuples to concatenate +/// @return A new tuple containing all elements from all input tuples template auto tuple_cat(Head&& _head, Tail&&... _tail) { return internal::tuple::concat(std::forward(_head), std::forward(_tail)...); } +/// Concatenates zero tuples, returning an empty tuple. +/// @return An empty tuple inline auto tuple_cat() { return rfl::Tuple(); } } // namespace rfl diff --git a/include/rfl/ubjson/load.hpp b/include/rfl/ubjson/load.hpp index f344c17f..30aaace8 100644 --- a/include/rfl/ubjson/load.hpp +++ b/include/rfl/ubjson/load.hpp @@ -8,6 +8,13 @@ namespace rfl::ubjson { +/// Loads an object from a UBJSON file. +/// Reads a binary file from disk and parses its UBJSON content into a C++ object using compile-time reflection. +/// UBJSON (Universal Binary JSON) is a compact binary format that mirrors JSON's data model. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _fname The filename/path of the UBJSON file to load +/// @return Result containing either the parsed object of type T or an error message template Result load(const std::string& _fname) { const auto read_bytes = [](const auto& _bytes) { diff --git a/include/rfl/ubjson/read.hpp b/include/rfl/ubjson/read.hpp index 3f257693..cfdc9d0f 100644 --- a/include/rfl/ubjson/read.hpp +++ b/include/rfl/ubjson/read.hpp @@ -18,7 +18,13 @@ namespace rfl::ubjson { using InputObjectType = typename Reader::InputObjectType; using InputVarType = typename Reader::InputVarType; -/// Parses an object from UBJSON using reflection. +/// Parses an object from UBJSON bytes using reflection (contiguous container version). +/// UBJSON (Universal Binary JSON) is a compact binary format that mirrors JSON's data model. +/// It's designed to be faster to parse than JSON while maintaining compatibility with JSON semantics. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _bytes A contiguous byte container (e.g., std::vector, std::string) containing UBJSON data +/// @return Result containing either the parsed object (or array of objects) or an error message template Result> read( const concepts::ContiguousByteContainer auto& _bytes) { @@ -31,7 +37,12 @@ Result> read( } } -/// Parses an object from a stream. +/// Parses an object from a stream containing UBJSON data. +/// Reads UBJSON binary data from the stream and constructs a C++ object. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _stream The input stream containing UBJSON binary data +/// @return Result containing either the parsed object (or array of objects) or an error message template Result> read(std::istream& _stream) { auto result = jsoncons::ubjson::try_decode_ubjson(_stream); diff --git a/include/rfl/ubjson/save.hpp b/include/rfl/ubjson/save.hpp index 453fb52e..778753de 100644 --- a/include/rfl/ubjson/save.hpp +++ b/include/rfl/ubjson/save.hpp @@ -11,6 +11,13 @@ namespace rfl::ubjson { +/// Saves an object to a UBJSON file. +/// Serializes a C++ object to UBJSON binary format and writes it to a file using compile-time reflection. +/// UBJSON (Universal Binary JSON) is a compact binary format that mirrors JSON's data model. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _fname The filename/path where the UBJSON file will be saved +/// @param _obj The object to serialize to UBJSON +/// @return Result containing Nothing on success or an error message on failure template Result save(const std::string& _fname, const auto& _obj) { const auto write_func = [](const auto& _obj, auto& _stream) -> auto& { diff --git a/include/rfl/ubjson/write.hpp b/include/rfl/ubjson/write.hpp index c7fadd84..523405db 100644 --- a/include/rfl/ubjson/write.hpp +++ b/include/rfl/ubjson/write.hpp @@ -14,7 +14,12 @@ namespace rfl::ubjson { -/// Returns UBJSON bytes. +/// Returns UBJSON bytes representation of the object. +/// UBJSON (Universal Binary JSON) is a compact binary format that mirrors JSON's data model. +/// Uses compile-time reflection to serialize a C++ object to UBJSON format. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to UBJSON +/// @return A vector of chars containing the UBJSON binary representation template std::vector write(const auto& _obj) { using T = std::remove_cvref_t; @@ -29,7 +34,12 @@ std::vector write(const auto& _obj) { internal::ptr_cast(buffer.data() + buffer.size())); } -/// Writes a UBJSON into an ostream. +/// Writes a UBJSON representation into an ostream. +/// Uses compile-time reflection to serialize a C++ object to UBJSON and write to a stream. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to UBJSON +/// @param _stream The output stream to write UBJSON binary data to +/// @return The output stream (for chaining) template std::ostream& write(const auto& _obj, std::ostream& _stream) { auto buffer = write(_obj); diff --git a/include/rfl/visit.hpp b/include/rfl/visit.hpp index 2e0a477d..0a6e3993 100644 --- a/include/rfl/visit.hpp +++ b/include/rfl/visit.hpp @@ -11,6 +11,11 @@ namespace rfl { +/// Visits a Literal with a visitor function. +/// @param _visitor The visitor to apply +/// @param _literal The literal to visit +/// @param _args Additional arguments to pass to the visitor +/// @return The result of the visitor function template inline auto visit(const Visitor& _visitor, const Literal<_fields...> _literal, const Args&... _args) { @@ -21,18 +26,31 @@ inline auto visit(const Visitor& _visitor, const Literal<_fields...> _literal, wrapper, _literal.value(), _args...); } +/// Visits a variant-based type with a visitor function. +/// @param _f The visitor function to apply +/// @param _v The variant to visit +/// @return The result of the visitor function template inline auto visit(F&& _f, V&& _v) -> decltype(std::declval().visit(std::declval())) { return std::forward(_v).visit(std::forward(_f)); } +/// Visits a tagged union with a visitor function. +/// @param _f The visitor function to apply +/// @param _tagged_union The tagged union to visit +/// @return The result of the visitor function template inline auto visit(F&& _f, T&& _tagged_union) -> decltype(std::declval().variant().visit(std::declval())) { return std::forward(_tagged_union).variant().visit(std::forward(_f)); } +/// Visits multiple variants with a visitor function (Cartesian product). +/// @param _f The visitor function to apply +/// @param _head The first variant to visit +/// @param _tail The remaining variants to visit +/// @return The result of the visitor function applied to all combinations template inline auto visit(F&& _f, Head&& _head, Tail&&... _tail) { const auto f_outer = [&](auto& _h) { diff --git a/include/rfl/xml/Reader.hpp b/include/rfl/xml/Reader.hpp index 77c83743..fc0725a3 100644 --- a/include/rfl/xml/Reader.hpp +++ b/include/rfl/xml/Reader.hpp @@ -16,17 +16,29 @@ namespace rfl::xml { +/// Reader class for deserializing XML (Extensible Markup Language) data. +/// This class provides the interface for parsing XML format into C++ objects. +/// Uses the pugixml library for XML parsing. XML has a hierarchical structure +/// with elements (nodes) and attributes, both of which can be mapped to object fields. struct Reader { + /// Represents an XML array during deserialization. + /// In XML, arrays are represented as multiple sibling elements with the same name. + /// Wraps a pugixml node representing the first element in the array. struct XMLInputArray { XMLInputArray(pugi::xml_node _node) : node_(_node) {} pugi::xml_node node_; }; + /// Represents an XML object during deserialization. + /// Wraps a pugixml node that can contain child elements and attributes. struct XMLInputObject { XMLInputObject(pugi::xml_node _node) : node_(_node) {} pugi::xml_node node_; }; + /// Represents a variant XML value during deserialization. + /// Can hold either an XML node (element) or an XML attribute. + /// This distinction is unique to XML format. struct XMLInputVar { XMLInputVar() : node_or_attribute_(pugi::xml_node()) {} XMLInputVar(pugi::xml_attribute _attr) : node_or_attribute_(_attr) {} @@ -38,10 +50,16 @@ struct Reader { using InputObjectType = XMLInputObject; using InputVarType = XMLInputVar; - // TODO + /// Compile-time flag indicating whether type T has a custom constructor from XML. + /// Currently not implemented for XML format (always false). template static constexpr bool has_custom_constructor = false; + /// Retrieves an element from an XML array by index. + /// In XML, arrays are represented as sibling elements with the same name. + /// @param _idx The zero-based index of the element to retrieve + /// @param _arr The XML array (first element of same-named siblings) to read from + /// @return Result containing the element at the specified index, or an error if out of bounds rfl::Result get_field_from_array( const size_t _idx, const InputArrayType& _arr) const noexcept { const auto name = _arr.node_.name(); @@ -54,6 +72,11 @@ struct Reader { return error("Index " + std::to_string(_idx) + " of of bounds."); } + /// Retrieves a field from an XML object by name. + /// Looks for a child element with the specified name. + /// @param _name The name of the child element to retrieve + /// @param _obj The XML object to read from + /// @return Result containing the field value, or an error if field is not found rfl::Result get_field_from_object( const std::string& _name, const InputObjectType _obj) const noexcept { const auto node = _obj.node_.child(_name.c_str()); @@ -63,6 +86,9 @@ struct Reader { return InputVarType(node); } + /// Checks if an XML value is empty or null. + /// @param _var The XML value (node or attribute) to check + /// @return true if the value is empty/null, false otherwise bool is_empty(const InputVarType _var) const noexcept { const auto wrap = [](const auto& _node) { return !_node; }; return std::visit(cast_as_node, _var.node_or_attribute_) @@ -70,6 +96,13 @@ struct Reader { .value_or(false); } + /// Converts an XML value to a basic C++ type. + /// Supports strings, booleans (as "true"/"false" or "1"/"0"), + /// floating-point numbers, and integers. Reads text content from nodes + /// or values from attributes. + /// @tparam T The target C++ type + /// @param _var The XML value (node or attribute) to convert + /// @return Result containing the converted value, or an error if conversion fails template rfl::Result to_basic_type(const InputVarType _var) const noexcept { const auto get_value = [](const auto& _n) -> std::string { @@ -118,11 +151,21 @@ struct Reader { } } + /// Converts an XML value to an array. + /// The node must be castable (not an attribute). + /// @param _var The XML value to convert + /// @return Result containing the array, or an error if value is an attribute rfl::Result to_array(const InputVarType _var) const noexcept { const auto wrap = [](const auto& _node) { return InputArrayType(_node); }; return std::visit(cast_as_node, _var.node_or_attribute_).transform(wrap); } + /// Reads all elements from an XML array using a provided array reader. + /// Iterates through all sibling elements with the same name. + /// @tparam ArrayReader Type that provides a read() method for processing elements + /// @param _array_reader The reader object used to process each array element + /// @param _arr The XML array to read from + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_array(const ArrayReader& _array_reader, const InputArrayType& _arr) const noexcept { @@ -136,6 +179,14 @@ struct Reader { return std::nullopt; } + /// Reads all fields from an XML object using a provided object reader. + /// Processes child elements, attributes, and optionally the text content. + /// The object reader's read() method is called for each child and attribute. + /// If the reader is a view reader, also provides access to "xml_content" field. + /// @tparam ObjectReader Type that provides a read() method for processing fields + /// @param _object_reader The reader object used to process each field + /// @param _obj The XML object to read from + /// @return std::nullopt on success, or an Error if reading fails template std::optional read_object(const ObjectReader& _object_reader, const InputObjectType& _obj) const noexcept { @@ -157,12 +208,21 @@ struct Reader { return std::nullopt; } + /// Converts an XML value to an object. + /// The node must be castable (not an attribute). + /// @param _var The XML value to convert + /// @return Result containing the object, or an error if value is an attribute rfl::Result to_object( const InputVarType _var) const noexcept { const auto wrap = [](const auto& _node) { return InputObjectType(_node); }; return std::visit(cast_as_node, _var.node_or_attribute_).transform(wrap); } + /// Uses a type's custom constructor to deserialize from XML. + /// Currently not implemented for XML format. + /// @tparam T The type to construct + /// @param _var The XML value to deserialize from + /// @return Error indicating this feature is not yet implemented template rfl::Result use_custom_constructor( const InputVarType _var) const noexcept { diff --git a/include/rfl/xml/Writer.hpp b/include/rfl/xml/Writer.hpp index 6b032ff3..78d898ae 100644 --- a/include/rfl/xml/Writer.hpp +++ b/include/rfl/xml/Writer.hpp @@ -12,7 +12,14 @@ namespace rfl::xml { +/// Writer class for serializing C++ objects to XML (Extensible Markup Language) format. +/// This class provides the interface for converting C++ objects into XML text. +/// Uses the pugixml library for XML generation. XML supports both elements (nodes) +/// and attributes, providing flexibility in how data is represented. struct RFL_API Writer { + /// Represents an XML array being constructed during serialization. + /// In XML, arrays are represented as multiple sibling elements with the same name. + /// Stores the element name and parent node where array elements will be added. struct XMLOutputArray { XMLOutputArray(const std::string_view& _name, const Ref& _node) @@ -21,11 +28,15 @@ struct RFL_API Writer { Ref node_; }; + /// Represents an XML object being constructed during serialization. + /// Wraps a reference to the pugixml node that will contain child elements and attributes. struct XMLOutputObject { XMLOutputObject(const Ref& _node) : node_(_node) {} Ref node_; }; + /// Represents an XML value being constructed during serialization. + /// Wraps a reference to the pugixml node representing the value. struct XMLOutputVar { XMLOutputVar(const Ref& _node) : node_(_node) {} Ref node_; @@ -35,42 +46,91 @@ struct RFL_API Writer { using OutputObjectType = XMLOutputObject; using OutputVarType = XMLOutputVar; + /// Constructs an XML Writer with the specified root node and name. + /// @param _root Reference to the pugixml node that will serve as the document root + /// @param _root_name The name for the root element Writer(const Ref& _root, const std::string& _root_name); ~Writer(); + /// Creates an XML array as the root element of the output. + /// @param _size The expected size (unused, reserved for future optimization) + /// @return An output array that can be populated with elements OutputArrayType array_as_root(const size_t _size) const; + /// Creates an XML object as the root element of the output. + /// @param _size The expected size (unused, reserved for future optimization) + /// @return An output object that can be populated with child elements and attributes OutputObjectType object_as_root(const size_t _size) const; + /// Creates a null value as the root element of the output. + /// @return An output variable representing the null value OutputVarType null_as_root() const; + /// Creates a value as the root element of the output. + /// Supports basic types like strings, numbers, and booleans. + /// @tparam T The type of the value to serialize + /// @param _var The value to write as the root element + /// @return An output variable representing the serialized value template OutputVarType value_as_root(const T& _var) const { const auto str = to_string(_var); return value_as_root_impl(str); } + /// Adds a nested array to a parent array. + /// Creates a new sibling element with the same name as the parent array. + /// @param _size The expected size (unused, reserved for future optimization) + /// @param _parent Pointer to the parent array to add to + /// @return An output array that can be populated with elements OutputArrayType add_array_to_array(const size_t _size, OutputArrayType* _parent) const; + /// Adds a nested array to a parent object with the specified field name. + /// @param _name The name of the field in the parent object (used as element name) + /// @param _size The expected size (unused, reserved for future optimization) + /// @param _parent Pointer to the parent object to add to + /// @return An output array that can be populated with elements OutputArrayType add_array_to_object(const std::string_view& _name, const size_t _size, OutputObjectType* _parent) const; + /// Adds an XML comment to a parent array. + /// @param _comment The comment text to add + /// @param _parent Pointer to the parent array to add the comment to void add_comment_to_array(const std::string_view& _comment, OutputArrayType* _parent) const; + /// Adds an XML comment to a parent object. + /// @param _comment The comment text to add + /// @param _parent Pointer to the parent object to add the comment to void add_comment_to_object(const std::string_view& _comment, OutputObjectType* _parent) const; + /// Adds a nested object to a parent array. + /// Creates a new sibling element with the same name as the parent array. + /// @param _size The expected size (unused, reserved for future optimization) + /// @param _parent Pointer to the parent array to add to + /// @return An output object that can be populated with child elements and attributes OutputObjectType add_object_to_array(const size_t _size, OutputArrayType* _parent) const; + /// Adds a nested object to a parent object with the specified field name. + /// @param _name The name of the field in the parent object (used as element name) + /// @param _size The expected size (unused, reserved for future optimization) + /// @param _parent Pointer to the parent object to add to + /// @return An output object that can be populated with child elements and attributes OutputObjectType add_object_to_object(const std::string_view& _name, const size_t _size, OutputObjectType* _parent) const; + /// Adds a value to a parent array. + /// Creates a new sibling element with the same name as the parent array. + /// Supports basic types like strings, numbers, and booleans. + /// @tparam T The type of the value to add + /// @param _var The value to add to the array + /// @param _parent Pointer to the parent array to add to + /// @return An output variable representing the added value template OutputVarType add_value_to_array(const T& _var, OutputArrayType* _parent) const { @@ -78,6 +138,15 @@ struct RFL_API Writer { return add_value_to_array_impl(str, _parent); } + /// Adds a value to a parent object with the specified field name. + /// Can be added as either a child element or an attribute. + /// Supports basic types like strings, numbers, and booleans. + /// @tparam T The type of the value to add + /// @param _name The name of the field in the parent object + /// @param _var The value to add to the object + /// @param _parent Pointer to the parent object to add to + /// @param _is_attribute If true, adds as an XML attribute; if false, adds as a child element + /// @return An output variable representing the added value template OutputVarType add_value_to_object(const std::string_view& _name, const T& _var, OutputObjectType* _parent, @@ -86,14 +155,29 @@ struct RFL_API Writer { return add_value_to_object_impl(_name, str, _parent, _is_attribute); } + /// Adds a null value to a parent array. + /// @param _parent Pointer to the parent array to add to + /// @return An output variable representing the null value OutputVarType add_null_to_array(OutputArrayType* _parent) const; + /// Adds a null value to a parent object with the specified field name. + /// Can be added as either a child element or an attribute. + /// @param _name The name of the field in the parent object + /// @param _parent Pointer to the parent object to add to + /// @param _is_attribute If true, adds as an XML attribute; if false, adds as a child element + /// @return An output variable representing the null value OutputVarType add_null_to_object(const std::string_view& _name, OutputObjectType* _parent, const bool _is_attribute = false) const; + /// Finalizes an XML array after all elements have been added. + /// This is a no-op for XML as arrays don't need explicit finalization. + /// @param _arr Pointer to the array to finalize void end_array(OutputArrayType* _arr) const; + /// Finalizes an XML object after all fields have been added. + /// This is a no-op for XML as objects don't need explicit finalization. + /// @param _obj Pointer to the object to finalize void end_object(OutputObjectType* _obj) const; private: diff --git a/include/rfl/xml/load.hpp b/include/rfl/xml/load.hpp index 861f8c41..f8e3d183 100644 --- a/include/rfl/xml/load.hpp +++ b/include/rfl/xml/load.hpp @@ -8,6 +8,12 @@ namespace rfl { namespace xml { +/// Loads an object from an XML file. +/// Reads a file from disk and parses its XML content into a C++ object using compile-time reflection. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _fname The filename/path of the XML file to load +/// @return Result containing either the parsed object of type T or an error message template Result load(const std::string& _fname) { const auto read_string = [](const auto& _str) { diff --git a/include/rfl/xml/read.hpp b/include/rfl/xml/read.hpp index 54d7f775..499d18ea 100644 --- a/include/rfl/xml/read.hpp +++ b/include/rfl/xml/read.hpp @@ -17,7 +17,12 @@ namespace rfl ::xml { using InputVarType = typename Reader::InputVarType; -/// Parses an object from a XML var. +/// Parses an object from an XML var (internal XML node representation). +/// An XML var is the internal representation used by the pugixml library. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _var The XML variant object to parse from +/// @return Result containing the parsed object of type T template auto read(const InputVarType& _var) { const auto r = Reader(); @@ -29,6 +34,11 @@ auto read(const InputVarType& _var) { } /// Parses an object from XML using reflection. +/// This function reads an XML string and constructs a C++ object using compile-time reflection. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _xml_str The XML string to parse +/// @return Result containing either the parsed object of type T or an error message template Result read(const std::string_view _xml_str) { pugi::xml_document doc; @@ -41,7 +51,12 @@ Result read(const std::string_view _xml_str) { return read(var); } -/// Parses an object from a stringstream. +/// Parses an object from a stringstream containing XML. +/// Reads the entire stream content and parses it as XML. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _stream The input stream containing XML data +/// @return Result containing either the parsed object of type T or an error message template auto read(std::istream& _stream) { const auto xml_str = std::string(std::istreambuf_iterator(_stream), diff --git a/include/rfl/xml/save.hpp b/include/rfl/xml/save.hpp index 48c3e5c9..2485257a 100644 --- a/include/rfl/xml/save.hpp +++ b/include/rfl/xml/save.hpp @@ -13,6 +13,13 @@ namespace rfl { namespace xml { +/// Saves an object to an XML file. +/// Serializes a C++ object to XML and writes it to a file using compile-time reflection. +/// @tparam _root The name of the XML root element (defaults to type name if empty) +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _fname The filename/path where the XML file will be saved +/// @param _obj The object to serialize to XML +/// @return Result containing Nothing on success or an error message on failure template Result save(const std::string& _fname, const auto& _obj) { diff --git a/include/rfl/xml/write.hpp b/include/rfl/xml/write.hpp index e0879734..c71d937a 100644 --- a/include/rfl/xml/write.hpp +++ b/include/rfl/xml/write.hpp @@ -18,6 +18,11 @@ namespace rfl { namespace xml { +/// Helper function to determine the XML root element name at compile time. +/// Uses explicit root name if provided, otherwise derives it from the type name. +/// @tparam _root Explicitly specified root name (empty string means auto-derive) +/// @tparam T The type being serialized +/// @return The root element name to use template consteval auto get_root_name() { if constexpr (_root != internal::StringLiteral("")) { @@ -28,7 +33,14 @@ consteval auto get_root_name() { } } -/// Writes a XML into an ostream. +/// Writes an XML representation into an ostream. +/// Uses compile-time reflection to serialize a C++ object to XML and write to a stream. +/// @tparam _root The name of the XML root element (defaults to type name if empty) +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to XML +/// @param _stream The output stream to write XML to +/// @param _indent The indentation string for formatting (default: 4 spaces) +/// @return The output stream (for chaining) template std::ostream& write(const auto& _obj, std::ostream& _stream, @@ -64,7 +76,13 @@ std::ostream& write(const auto& _obj, std::ostream& _stream, return _stream; } -/// Returns a XML string. +/// Returns an XML string representation of the object. +/// Uses compile-time reflection to serialize a C++ object to XML format. +/// @tparam _root The name of the XML root element (defaults to type name if empty) +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to XML +/// @param _indent The indentation string for formatting (default: 4 spaces) +/// @return XML string representation of the object template std::string write(const auto& _obj, const std::string& _indent = " ") { diff --git a/include/rfl/yaml/Reader.hpp b/include/rfl/yaml/Reader.hpp index 0b169a90..3ff3ac04 100644 --- a/include/rfl/yaml/Reader.hpp +++ b/include/rfl/yaml/Reader.hpp @@ -24,16 +24,22 @@ namespace yaml { struct Reader { struct YAMLInputArray { + /// @brief Constructs a YAMLInputArray from a YAML::Node. + /// @param _node The YAML node representing a sequence. YAMLInputArray(const YAML::Node& _node) : node_(_node) {} YAML::Node node_; }; struct YAMLInputObject { + /// @brief Constructs a YAMLInputObject from a YAML::Node. + /// @param _node The YAML node representing a mapping. YAMLInputObject(const YAML::Node& _node) : node_(_node) {} YAML::Node node_; }; struct YAMLInputVar { + /// @brief Constructs a YAMLInputVar from a YAML::Node. + /// @param _node The YAML node representing a generic value. YAMLInputVar(const YAML::Node& _node) : node_(_node) {} YAML::Node node_; }; @@ -42,15 +48,25 @@ struct Reader { using InputObjectType = YAMLInputObject; using InputVarType = YAMLInputVar; + /// @brief Trait to check if a type T has a from_json_obj method. + /// @tparam T The type to check. template struct has_from_json_obj : std::false_type {}; + /// @brief Compile-time check for custom constructor from YAML object. + /// @tparam T The type to check. template static constexpr bool has_custom_constructor = (requires(InputVarType var) { T::from_yaml_obj(var); }); + /// @brief Constructs a Reader from a YAML string view. + /// @param _yaml_str The YAML document as a string view. Reader(const std::string_view& _yaml_str) noexcept : yaml_str_(_yaml_str) {} + /// @brief Retrieves an element from a YAML sequence by index. + /// @param _idx The index of the element in the array. + /// @param _arr The YAMLInputArray representing the sequence. + /// @return Result containing the InputVarType or an error if out of bounds. rfl::Result get_field_from_array( const size_t _idx, const InputArrayType& _arr) const noexcept { if (_idx >= _arr.node_.size()) { @@ -59,6 +75,11 @@ struct Reader { return InputVarType(_arr.node_[_idx]); } + /// @brief Retrieves a field from a YAML mapping by name. + /// @param _name The name of the field. + /// @param _obj The YAMLInputObject representing the mapping. + /// @return Result containing the InputVarType or an error if the field does + /// not exist. rfl::Result get_field_from_object( const std::string& _name, const InputObjectType& _obj) const noexcept { auto var = InputVarType(_obj.node_[_name]); @@ -68,10 +89,19 @@ struct Reader { return var; } + /// @brief Checks if a YAMLInputVar is empty or null. + /// @param _var The variable to check. + /// @return True if the node is empty or null, false otherwise. bool is_empty(const InputVarType& _var) const noexcept { return !_var.node_ || _var.node_.IsNull(); } + /// @brief Converts a YAMLInputVar to a basic C++ type (string, bool, float, + /// or int). + /// @tparam T The target type. + /// @param _var The YAMLInputVar to convert. + /// @return Result containing the converted value or an error if conversion + /// fails. template rfl::Result to_basic_type(const InputVarType& _var) const noexcept { try { @@ -85,8 +115,10 @@ struct Reader { // multiple re-serialization checks, for this reason we trim trailing // new-lines here. // - // This is only done for literal blocks which doesn't have tags or anchors - if (_var.node_.Tag() == "!" && yaml_str_[_var.node_.Mark().pos] == '|') { + // This is only done for literal blocks which doesn't have tags or + // anchors + if (_var.node_.Tag() == "!" && + yaml_str_[_var.node_.Mark().pos] == '|') { auto last_non_new_line = result.find_last_not_of("\r\n"); if (last_non_new_line != std::string::npos) { result = result.substr(0, last_non_new_line + 1); @@ -107,6 +139,10 @@ struct Reader { } } + /// @brief Converts a YAMLInputVar to a YAMLInputArray if it is a sequence. + /// @param _var The variable to convert. + /// @return Result containing the InputArrayType or an error if not a + /// sequence. rfl::Result to_array( const InputVarType& _var) const noexcept { if (!_var.node_.IsSequence()) { @@ -115,6 +151,11 @@ struct Reader { return InputArrayType(_var.node_); } + /// @brief Reads each element of a YAML sequence using a provided ArrayReader. + /// @tparam ArrayReader The type of the array reader functor. + /// @param _array_reader The functor to process each element. + /// @param _arr The YAMLInputArray to read from. + /// @return Optional error if any element fails to be read, otherwise nullopt. template std::optional read_array(const ArrayReader& _array_reader, const InputArrayType& _arr) const noexcept { @@ -127,6 +168,12 @@ struct Reader { return std::nullopt; } + /// @brief Reads each key-value pair of a YAML mapping using a provided + /// ObjectReader. + /// @tparam ObjectReader The type of the object reader functor. + /// @param _object_reader The functor to process each field. + /// @param _obj The YAMLInputObject to read from. + /// @return Optional error if any field fails to be read, otherwise nullopt. template std::optional read_object(const ObjectReader& _object_reader, const InputObjectType& _obj) const noexcept { @@ -141,6 +188,10 @@ struct Reader { return std::nullopt; } + /// @brief Converts a YAMLInputVar to a YAMLInputObject if it is a mapping. + /// @param _var The variable to convert. + /// @return Result containing the InputObjectType or an error if not a + /// mapping. rfl::Result to_object( const InputVarType& _var) const noexcept { if (!_var.node_.IsMap()) { @@ -149,6 +200,11 @@ struct Reader { return InputObjectType(_var.node_); } + /// @brief Uses a custom constructor to convert a YAMLInputVar to type T. + /// @tparam T The target type with a static from_yaml_obj method. + /// @param _var The YAMLInputVar to convert. + /// @return Result containing the constructed T or an error if construction + /// fails. template rfl::Result use_custom_constructor( const InputVarType _var) const noexcept { @@ -160,6 +216,8 @@ struct Reader { } private: + /// @brief The YAML document as a string view, used for context and error + /// reporting. std::string_view yaml_str_; }; diff --git a/include/rfl/yaml/Writer.hpp b/include/rfl/yaml/Writer.hpp index 112a105c..04412791 100644 --- a/include/rfl/yaml/Writer.hpp +++ b/include/rfl/yaml/Writer.hpp @@ -15,69 +15,136 @@ namespace rfl::yaml { class RFL_API Writer { public: + /** + * @enum Flags + * @brief Flags to control YAML string formatting behavior in Writer. + */ enum Flags { - no_flags = 0, + no_flags = 0, ///< No special formatting flags. - /// A string value which has at least one new-line character will be written - /// as multiline YAML literal. It costs one call to std::basic_string::find - /// on all string values. + /// @brief Write string values containing new-lines as YAML multiline + /// literals. + /// @details Costs one call to std::basic_string::find on all string values. string_multiline_literal = 1, - /// All string values will be written as multiline YAML literal + /// @brief Write all string values as YAML multiline literals. string_all_literal = 2 }; + /** + * @struct YAMLArray + * @brief Tag type representing a YAML array node. + */ struct YAMLArray {}; + /** + * @struct YAMLObject + * @brief Tag type representing a YAML object node. + */ struct YAMLObject {}; + /** + * @struct YAMLVar + * @brief Tag type representing a YAML value node. + */ struct YAMLVar {}; - using OutputArrayType = YAMLArray; - using OutputObjectType = YAMLObject; - using OutputVarType = YAMLVar; + using OutputArrayType = YAMLArray; ///< Alias for YAML array output type. + using OutputObjectType = YAMLObject; ///< Alias for YAML object output type. + using OutputVarType = YAMLVar; ///< Alias for YAML value output type. + /// @brief Constructs a Writer for emitting YAML. + /// @param _out Reference to a YAML::Emitter object for output. + /// @param _flags Optional flags to control string formatting. Writer(const Ref& _out, Flags _flags = no_flags); + /// @brief Destructor for Writer. ~Writer(); + /// @brief Begin a YAML array as the root node. + /// @param _size Expected size of the array. + /// @return OutputArrayType representing the root array. OutputArrayType array_as_root(const size_t _size) const; + /// @brief Begin a YAML object as the root node. + /// @param _size Expected size of the object. + /// @return OutputObjectType representing the root object. OutputObjectType object_as_root(const size_t _size) const; + /// @brief Begin a YAML null value as the root node. + /// @return OutputVarType representing the root null value. OutputVarType null_as_root() const; + /// @brief Begin a YAML value as the root node. + /// @tparam T Type of the value. + /// @param _var Value to write as root. + /// @return OutputVarType representing the root value. template OutputVarType value_as_root(const T& _var) const { return insert_value(_var); } + /// @brief Add a new array to an existing array node. + /// @param _size Expected size of the new array. + /// @param _parent Pointer to the parent array node. + /// @return OutputArrayType representing the new array. OutputArrayType add_array_to_array(const size_t _size, OutputArrayType* /*_parent*/) const; + /// @brief Add a new array to an object node under a given key. + /// @param _name Name of the key in the object. + /// @param _size Expected size of the new array. + /// @param _parent Pointer to the parent object node. + /// @return OutputArrayType representing the new array. OutputArrayType add_array_to_object(const std::string_view& _name, const size_t _size, OutputObjectType* /*_parent*/) const; + /// @brief Add a comment to an array node. + /// @param _comment The comment string. + /// @param _parent Pointer to the parent array node. void add_comment_to_array(const std::string_view& _comment, OutputArrayType* _parent) const; + /// @brief Add a comment to an object node. + /// @param _comment The comment string. + /// @param _parent Pointer to the parent object node. void add_comment_to_object(const std::string_view& _comment, OutputObjectType* _parent) const; + /// @brief Add a new object to an array node. + /// @param _size Expected size of the new object. + /// @param _parent Pointer to the parent array node. + /// @return OutputObjectType representing the new object. OutputObjectType add_object_to_array(const size_t _size, OutputArrayType* _parent) const; + /// @brief Add a new object to an object node under a given key. + /// @param _name Name of the key in the object. + /// @param _size Expected size of the new object. + /// @param _parent Pointer to the parent object node. + /// @return OutputObjectType representing the new object. OutputObjectType add_object_to_object(const std::string_view& _name, const size_t _size, OutputObjectType* _parent) const; + /// @brief Add a value to an array node. + /// @tparam T Type of the value. + /// @param _var Value to add. + /// @param _parent Pointer to the parent array node. + /// @return OutputVarType representing the added value. template OutputVarType add_value_to_array(const T& _var, OutputArrayType* _parent) const { return insert_value(_var); } + /// @brief Add a value to an object node under a given key. + /// @tparam T Type of the value. + /// @param _name Name of the key in the object. + /// @param _var Value to add. + /// @param _parent Pointer to the parent object node. + /// @return OutputVarType representing the added value. template OutputVarType add_value_to_object(const std::string_view& _name, const T& _var, @@ -85,26 +152,47 @@ class RFL_API Writer { return insert_value(_name, _var); } + /// @brief Add a YAML null value to an array node. + /// @param _parent Pointer to the parent array node. + /// @return OutputVarType representing the added null value. OutputVarType add_null_to_array(OutputArrayType* _parent) const; + /// @brief Add a YAML null value to an object node under a given key. + /// @param _name Name of the key in the object. + /// @param _parent Pointer to the parent object node. + /// @return OutputVarType representing the added null value. OutputVarType add_null_to_object(const std::string_view& _name, OutputObjectType* _parent) const; + /// @brief End the current array node. + /// @param _arr Pointer to the array node to end. void end_array(OutputArrayType* _arr) const; + /// @brief End the current object node. + /// @param _obj Pointer to the object node to end. void end_object(OutputObjectType* _obj) const; private: + /// @brief Insert YAML literal block indicator if needed for a value. + /// @tparam T Type of the value. + /// @param _var Value to check for literal block formatting. template void insert_literal_block_if_needed(const T& _var) const { if constexpr (std::is_same, std::string>()) { - if (flags_ & string_all_literal || (flags_ & string_multiline_literal && _var.find('\n') != std::string::npos)) { + if (flags_ & string_all_literal || + (flags_ & string_multiline_literal && + _var.find('\n') != std::string::npos)) { (*out_) << YAML::Literal; } } } public: + /// @brief Insert a value into an object node under a given key. + /// @tparam T Type of the value. + /// @param _name Name of the key in the object. + /// @param _var Value to insert. + /// @return OutputVarType representing the inserted value. template OutputVarType insert_value(const std::string_view& _name, const T& _var) const { @@ -129,6 +217,10 @@ class RFL_API Writer { return OutputVarType{}; } + /// @brief Insert a value node. + /// @tparam T Type of the value. + /// @param _var Value to insert. + /// @return OutputVarType representing the inserted value. template OutputVarType insert_value(const T& _var) const { if constexpr (std::is_same, std::string>() || @@ -149,18 +241,32 @@ class RFL_API Writer { return OutputVarType{}; } + /// @brief Create a new YAML array node under a given key. + /// @param _name Name of the key in the object. + /// @return OutputArrayType representing the new array. OutputArrayType new_array(const std::string_view& _name) const; + /// @brief Create a new YAML array node as a root or child. + /// @return OutputArrayType representing the new array. OutputArrayType new_array() const; + /// @brief Add a comment to the YAML output. + /// @param _comment The comment string. void new_comment(const std::string_view& _comment) const; + /// @brief Create a new YAML object node under a given key. + /// @param _name Name of the key in the object. + /// @return OutputObjectType representing the new object. OutputObjectType new_object(const std::string_view& _name) const; + /// @brief Create a new YAML object node as a root or child. + /// @return OutputObjectType representing the new object. OutputObjectType new_object() const; public: + /// @brief Reference to the YAML emitter used for output. const Ref out_; + /// @brief Flags controlling string formatting behavior. Flags flags_; }; diff --git a/include/rfl/yaml/load.hpp b/include/rfl/yaml/load.hpp index 7f3fa92d..db4b358f 100644 --- a/include/rfl/yaml/load.hpp +++ b/include/rfl/yaml/load.hpp @@ -8,6 +8,12 @@ namespace rfl { namespace yaml { +/// Loads an object from a YAML file. +/// Reads a file from disk and parses its YAML content into a C++ object using compile-time reflection. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _fname The filename/path of the YAML file to load +/// @return Result containing either the parsed object of type T or an error message template Result load(const std::string& _fname) { const auto read_string = [](const auto& _str) { diff --git a/include/rfl/yaml/read.hpp b/include/rfl/yaml/read.hpp index ddcc1183..f8b1b338 100644 --- a/include/rfl/yaml/read.hpp +++ b/include/rfl/yaml/read.hpp @@ -18,7 +18,13 @@ namespace yaml { using InputVarType = typename Reader::InputVarType; -/// Parses an object from a YAML var. +/// Parses an object from a YAML var (internal YAML node representation). +/// A YAML var is the internal representation used by the yaml-cpp library. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _var The YAML variant object to parse from +/// @param _yaml_str The original YAML string (used for error context) +/// @return The parsed object of type T template auto read(const InputVarType& _var, const std::string& _yaml_str) { const auto r = Reader(_yaml_str); @@ -30,6 +36,11 @@ auto read(const InputVarType& _var, const std::string& _yaml_str) { } /// Parses an object from YAML using reflection. +/// This function reads a YAML string and constructs a C++ object using compile-time reflection. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _yaml_str The YAML string to parse +/// @return Result containing either the parsed object (or array of objects) or an error message template Result> read(const std::string& _yaml_str) { try { @@ -40,14 +51,23 @@ Result> read(const std::string& _yaml_str) { } } -/// Parses an object from YAML using reflection. +/// Parses an object from YAML using reflection (string_view version). +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _yaml_str The YAML string to parse +/// @return Result containing either the parsed object (or array of objects) or an error message template Result> read( const std::string_view _yaml_str) { return read(std::string(_yaml_str)); } -/// Parses an object from a stringstream. +/// Parses an object from a stringstream containing YAML. +/// Reads the entire stream content and parses it as YAML. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _stream The input stream containing YAML data +/// @return Result containing either the parsed object (or array of objects) or an error message template auto read(std::istream& _stream) { const auto yaml_str = std::string(std::istreambuf_iterator(_stream), diff --git a/include/rfl/yaml/save.hpp b/include/rfl/yaml/save.hpp index 6333c99e..87e7eb9b 100644 --- a/include/rfl/yaml/save.hpp +++ b/include/rfl/yaml/save.hpp @@ -13,6 +13,12 @@ namespace rfl { namespace yaml { +/// Saves an object to a YAML file. +/// Serializes a C++ object to YAML and writes it to a file using compile-time reflection. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _fname The filename/path where the YAML file will be saved +/// @param _obj The object to serialize to YAML +/// @return Result containing Nothing on success or an error message on failure template Result save(const std::string& _fname, const auto& _obj) { const auto write_func = [](const auto& _obj, auto& _stream) -> auto& { diff --git a/include/rfl/yaml/write.hpp b/include/rfl/yaml/write.hpp index 55f83ae9..f0a16011 100644 --- a/include/rfl/yaml/write.hpp +++ b/include/rfl/yaml/write.hpp @@ -16,7 +16,13 @@ namespace rfl { namespace yaml { -/// Writes a YAML into an ostream. +/// Writes a YAML representation into an ostream. +/// Uses compile-time reflection to serialize a C++ object to YAML and write to a stream. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to YAML +/// @param _stream The output stream to write YAML to +/// @param _flags Optional writer flags for formatting (default: no_flags) +/// @return The output stream (for chaining) template std::ostream& write(const auto& _obj, std::ostream& _stream, Writer::Flags _flags = Writer::Flags::no_flags) { using T = std::remove_cvref_t; @@ -32,7 +38,12 @@ std::ostream& write(const auto& _obj, std::ostream& _stream, Writer::Flags _flag return _stream; } -/// Returns a YAML string. +/// Returns a YAML string representation of the object. +/// Uses compile-time reflection to serialize a C++ object to YAML format. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to YAML +/// @param _flags Optional writer flags for formatting (default: no_flags) +/// @return YAML string representation of the object template std::string write(const auto& _obj, Writer::Flags _flags = Writer::Flags::no_flags) { using T = std::remove_cvref_t; diff --git a/include/rfl/yas/Reader.hpp b/include/rfl/yas/Reader.hpp index 5979a015..bf1b652c 100644 --- a/include/rfl/yas/Reader.hpp +++ b/include/rfl/yas/Reader.hpp @@ -40,11 +40,23 @@ struct Reader { IArchive* ar; }; + /// @brief Indicates whether a custom constructor exists for type T. + /// @tparam T The type to check for a custom constructor. template - static constexpr bool has_custom_constructor = false; + static constexpr bool has_custom_constructor = + (requires(InputVarType var) { T::from_yas_obj(var); }); + /// @brief Checks if the given input variable is empty. + /// @param _var The input variable to check. + /// @return Always returns false, as emptiness is not supported in this + /// context. bool is_empty(const InputVarType& /*_var*/) const noexcept { return false; } + /// @brief Deserializes a basic type from the input variable using the YAS + /// archive. + /// @tparam T The type to deserialize. + /// @param _var The input variable containing the archive pointer. + /// @return The deserialized value or an error if deserialization fails. template rfl::Result to_basic_type(const InputVarType& _var) const noexcept { try { @@ -62,25 +74,46 @@ struct Reader { } } + /// @brief Converts an input variable to an array type for further + /// deserialization. + /// @param _var The input variable containing the archive pointer. + /// @return An InputArrayType wrapping the archive pointer. rfl::Result to_array( const InputVarType& _var) const noexcept { return InputArrayType{_var.ar}; } + /// @brief Converts an input variable to an object type for further + /// deserialization. + /// @param _var The input variable containing the archive pointer. + /// @return An InputObjectType wrapping the archive pointer. rfl::Result to_object( const InputVarType& _var) const noexcept { return InputObjectType{_var.ar}; } + /// @brief Converts an input variable to a map type for further + /// deserialization. + /// @param _var The input variable containing the archive pointer. + /// @return An InputMapType wrapping the archive pointer. rfl::Result to_map(const InputVarType& _var) const noexcept { return InputMapType{_var.ar}; } + /// @brief Converts an input variable to a union type for further + /// deserialization. + /// @param _var The input variable containing the archive pointer. + /// @return An InputUnionType wrapping the archive pointer. rfl::Result to_union( const InputVarType& _var) const noexcept { return InputUnionType{_var.ar}; } + /// @brief Reads an array from the archive using the provided ArrayReader. + /// @tparam ArrayReader The type responsible for reading array elements. + /// @param _array_reader The reader instance for array elements. + /// @param _arr The input array type containing the archive pointer. + /// @return std::nullopt on success, or an Error if reading fails. template std::optional read_array(const ArrayReader& _array_reader, const InputArrayType& _arr) const noexcept { @@ -99,6 +132,11 @@ struct Reader { } } + /// @brief Reads a map from the archive using the provided MapReader. + /// @tparam MapReader The type responsible for reading map entries. + /// @param _map_reader The reader instance for map entries. + /// @param _map The input map type containing the archive pointer. + /// @return std::nullopt on success, or an Error if reading fails. template std::optional read_map(const MapReader& _map_reader, const InputMapType& _map) const noexcept { @@ -116,6 +154,11 @@ struct Reader { } } + /// @brief Reads an object from the archive using the provided ObjectReader. + /// @tparam ObjectReader The type responsible for reading object fields. + /// @param _object_reader The reader instance for object fields. + /// @param _obj The input object type containing the archive pointer. + /// @return std::nullopt on success, or an Error if reading fails. template std::optional read_object(const ObjectReader& _object_reader, const InputObjectType& _obj) const noexcept { @@ -129,6 +172,11 @@ struct Reader { } } + /// @brief Reads a union from the archive using the provided UnionReader. + /// @tparam T The type to deserialize. + /// @tparam UnionReader The type responsible for reading union alternatives. + /// @param _union The input union type containing the archive pointer. + /// @return The deserialized union value or an error if reading fails. template rfl::Result read_union(const InputUnionType& _union) const noexcept { try { @@ -140,6 +188,11 @@ struct Reader { } } + /// @brief Returns an error indicating that custom constructors are not + /// supported. + /// @tparam T The type for which a custom constructor would be used. + /// @param _var The input variable (unused). + /// @return An error indicating custom constructors are not supported. template rfl::Result use_custom_constructor( const InputVarType& /*_var*/) const noexcept { diff --git a/include/rfl/yas/Writer.hpp b/include/rfl/yas/Writer.hpp index 44bc1317..4d235258 100644 --- a/include/rfl/yas/Writer.hpp +++ b/include/rfl/yas/Writer.hpp @@ -43,47 +43,87 @@ struct Writer { OArchive* ar; }; + /// + /// @brief Constructs a Writer with the given output archive pointer. + /// @param _ar Pointer to the output archive used for serialization. Writer(OArchive* _ar) : ar_(_ar) {} - template - static constexpr bool has_custom_constructor = false; - + /// + /// @brief Begins serializing an array as the root object. + /// @param _size The number of elements in the array. + /// @return OutputArrayType representing the serialized array context. OutputArrayType array_as_root(const size_t _size) const noexcept { (*ar_) & _size; return OutputArrayType{ar_}; } + /// + /// @brief Begins serializing a map as the root object. + /// @param _size The number of key-value pairs in the map. + /// @return OutputMapType representing the serialized map context. OutputMapType map_as_root(const size_t _size) const noexcept { (*ar_) & _size; return OutputMapType{ar_}; } + /// + /// @brief Begins serializing an object as the root object. + /// @param _size The number of fields in the object (unused). + /// @return OutputObjectType representing the serialized object context. OutputObjectType object_as_root(const size_t /*_size*/) const noexcept { return OutputObjectType{ar_}; } + /// + /// @brief Begins serializing a union as the root object. + /// @return OutputUnionType representing the serialized union context. OutputUnionType union_as_root() const noexcept { return OutputUnionType{ar_}; } + /// + /// @brief Begins serializing a null value as the root object. + /// @return OutputVarType representing the serialized null context. OutputVarType null_as_root() const noexcept { return OutputVarType{ar_}; } + /// + /// @brief Begins serializing a value as the root object. + /// @tparam T The type of the value. + /// @param _var The value to serialize. + /// @return OutputVarType representing the serialized value context. template OutputVarType value_as_root(const T& _var) const noexcept { add_value(_var); return OutputVarType{ar_}; } + /// + /// @brief Adds an array as a child to an array parent during serialization. + /// @param _size The number of elements in the child array. + /// @param _parent Pointer to the parent OutputArrayType. + /// @return OutputArrayType representing the new array context. OutputArrayType add_array_to_array(const size_t _size, OutputArrayType* _parent) const noexcept { (*_parent->ar) & _size; return OutputArrayType{_parent->ar}; } + /// + /// @brief Adds an array as a child to a map parent during serialization. + /// @param _name The key name for the array in the map. + /// @param _size The number of elements in the array. + /// @param _parent Pointer to the parent OutputMapType. + /// @return OutputArrayType representing the new array context. OutputArrayType add_array_to_map(const std::string_view& _name, const size_t _size, OutputMapType* _parent) const noexcept; + /// + /// @brief Adds an array as a child to an object parent during serialization. + /// @param _name The field name for the array in the object (unused). + /// @param _size The number of elements in the array. + /// @param _parent Pointer to the parent OutputObjectType. + /// @return OutputArrayType representing the new array context. OutputArrayType add_array_to_object( const std::string_view& /*_name*/, const size_t _size, OutputObjectType* _parent) const noexcept { @@ -91,15 +131,32 @@ struct Writer { return OutputArrayType{_parent->ar}; } + /// + /// @brief Adds an array as a child to a union parent during serialization. + /// @param _index The union field index. + /// @param _size The number of elements in the array. + /// @param _parent Pointer to the parent OutputUnionType. + /// @return OutputArrayType representing the new array context. OutputArrayType add_array_to_union(const size_t _index, const size_t _size, OutputUnionType* _parent) const noexcept; + /// + /// @brief Adds a map as a child to an array parent during serialization. + /// @param _size The number of key-value pairs in the map. + /// @param _parent Pointer to the parent OutputArrayType. + /// @return OutputMapType representing the new map context. OutputMapType add_map_to_array(const size_t _size, OutputArrayType* _parent) const noexcept { (*_parent->ar) & _size; return OutputMapType{_parent->ar}; } + /// + /// @brief Adds a map as a child to an object parent during serialization. + /// @param _name The field name for the map in the object (unused). + /// @param _size The number of key-value pairs in the map. + /// @param _parent Pointer to the parent OutputObjectType. + /// @return OutputMapType representing the new map context. OutputMapType add_map_to_object(const std::string_view& /*_name*/, const size_t _size, OutputObjectType* _parent) const noexcept { @@ -107,53 +164,120 @@ struct Writer { return OutputMapType{_parent->ar}; } + /// + /// @brief Adds a map as a child to a map parent during serialization. + /// @param _name The key name for the map in the parent map. + /// @param _size The number of key-value pairs in the map. + /// @param _parent Pointer to the parent OutputMapType. + /// @return OutputMapType representing the new map context. OutputMapType add_map_to_map(const std::string_view& _name, const size_t _size, OutputMapType* _parent) const noexcept; + /// + /// @brief Adds a map as a child to a union parent during serialization. + /// @param _index The union field index. + /// @param _size The number of key-value pairs in the map. + /// @param _parent Pointer to the parent OutputUnionType. + /// @return OutputMapType representing the new map context. OutputMapType add_map_to_union(const size_t _index, const size_t _size, OutputUnionType* _parent) const noexcept; + /// + /// @brief Adds an object as a child to an array parent during serialization. + /// @param _size The number of fields in the object (unused). + /// @param _parent Pointer to the parent OutputArrayType. + /// @return OutputObjectType representing the new object context. OutputObjectType add_object_to_array( const size_t /*_size*/, OutputArrayType* _parent) const noexcept { return OutputObjectType{_parent->ar}; } + /// + /// @brief Adds an object as a child to a map parent during serialization. + /// @param _name The key name for the object in the map. + /// @param _size The number of fields in the object. + /// @param _parent Pointer to the parent OutputMapType. + /// @return OutputObjectType representing the new object context. OutputObjectType add_object_to_map(const std::string_view& _name, const size_t _size, OutputMapType* _parent) const noexcept; + /// + /// @brief Adds an object as a child to an object parent during serialization. + /// @param _name The field name for the object in the parent object (unused). + /// @param _size The number of fields in the object (unused). + /// @param _parent Pointer to the parent OutputObjectType. + /// @return OutputObjectType representing the new object context. OutputObjectType add_object_to_object( const std::string_view& /*_name*/, const size_t /*_size*/, OutputObjectType* _parent) const noexcept { return OutputObjectType{_parent->ar}; } + /// + /// @brief Adds an object as a child to a union parent during serialization. + /// @param _index The union field index. + /// @param _size The number of fields in the object. + /// @param _parent Pointer to the parent OutputUnionType. + /// @return OutputObjectType representing the new object context. OutputObjectType add_object_to_union(const size_t _index, const size_t _size, OutputUnionType* _parent) const noexcept; + /// + /// @brief Adds a union as a child to an array parent during serialization. + /// @param _parent Pointer to the parent OutputArrayType. + /// @return OutputUnionType representing the new union context. OutputUnionType add_union_to_array(OutputArrayType* _parent) const noexcept { return OutputUnionType{_parent->ar}; } + /// + /// @brief Adds a union as a child to a map parent during serialization. + /// @param _name The key name for the union in the map. + /// @param _parent Pointer to the parent OutputMapType. + /// @return OutputUnionType representing the new union context. OutputUnionType add_union_to_map(const std::string_view& _name, OutputMapType* _parent) const noexcept; + /// + /// @brief Adds a union as a child to an object parent during serialization. + /// @param _name The field name for the union in the object (unused). + /// @param _parent Pointer to the parent OutputObjectType. + /// @return OutputUnionType representing the new union context. OutputUnionType add_union_to_object( const std::string_view& /*_name*/, OutputObjectType* _parent) const noexcept { return OutputUnionType{_parent->ar}; } + /// + /// @brief Adds a union as a child to a union parent during serialization. + /// @param _index The union field index. + /// @param _parent Pointer to the parent OutputUnionType. + /// @return OutputUnionType representing the new union context. OutputUnionType add_union_to_union(const size_t _index, OutputUnionType* _parent) const noexcept; + /// + /// @brief Adds a value as a child to an array parent during serialization. + /// @tparam T The type of the value. + /// @param _var The value to serialize. + /// @param _parent Pointer to the parent OutputArrayType. + /// @return OutputVarType representing the serialized value context. template OutputVarType add_value_to_array(const T& _var, OutputArrayType*) const { add_value(_var); return OutputVarType{}; } + /// + /// @brief Adds a value as a child to a map parent during serialization. + /// @tparam T The type of the value. + /// @param _name The key name for the value in the map. + /// @param _var The value to serialize. + /// @param _parent Pointer to the parent OutputMapType. + /// @return OutputVarType representing the serialized value context. template OutputVarType add_value_to_map(const std::string_view& _name, const T& _var, OutputMapType* _parent) const { @@ -162,6 +286,13 @@ struct Writer { return OutputVarType{}; } + /// + /// @brief Adds a value as a child to an object parent during serialization. + /// @tparam T The type of the value. + /// @param _name The field name for the value in the object. + /// @param _var The value to serialize. + /// @param _parent Pointer to the parent OutputObjectType. + /// @return OutputVarType representing the serialized value context. template OutputVarType add_value_to_object(const std::string_view& _name, const T& _var, OutputObjectType*) const { @@ -169,6 +300,13 @@ struct Writer { return OutputVarType{}; } + /// + /// @brief Adds a value as a child to a union parent during serialization. + /// @tparam T The type of the value. + /// @param _index The union field index. + /// @param _var The value to serialize. + /// @param _parent Pointer to the parent OutputUnionType. + /// @return OutputVarType representing the serialized value context. template OutputVarType add_value_to_union(const size_t _index, const T& _var, OutputUnionType* _parent) const { @@ -177,34 +315,72 @@ struct Writer { return OutputVarType{}; } + /// + /// @brief Adds a null value as a child to an array parent during + /// serialization. + /// @param _parent Pointer to the parent OutputArrayType (unused). + /// @return OutputVarType representing the serialized null context. OutputVarType add_null_to_array(OutputArrayType* /*_parent*/) const { return OutputVarType{}; } + /// + /// @brief Adds a null value as a child to a map parent during serialization. + /// @param _name The key name for the null value (unused). + /// @param _parent Pointer to the parent OutputMapType (unused). + /// @return OutputVarType representing the serialized null context. OutputVarType add_null_to_map(const std::string_view& /*_name*/, OutputMapType* /*_parent*/) const { return OutputVarType{}; } + /// + /// @brief Adds a null value as a child to an object parent during + /// serialization. + /// @param _name The field name for the null value (unused). + /// @param _parent Pointer to the parent OutputObjectType (unused). + /// @return OutputVarType representing the serialized null context. OutputVarType add_null_to_object(const std::string_view& /*_name*/, OutputObjectType* /*_parent*/) const { return OutputVarType{}; } + /// + /// @brief Adds a null value as a child to a union parent during + /// serialization. + /// @param _index The union field index. + /// @param _parent Pointer to the parent OutputUnionType. + /// @return OutputVarType representing the serialized null context. OutputVarType add_null_to_union(const size_t _index, OutputUnionType* _parent) const noexcept; + /// + /// @brief Marks the end of an array serialization context. + /// @param _arr Pointer to the OutputArrayType (unused). void end_array(OutputArrayType* /*_arr*/) const noexcept {} + /// + /// @brief Marks the end of a map serialization context. + /// @param _map Pointer to the OutputMapType (unused). void end_map(OutputMapType* /*_map*/) const noexcept {} + /// + /// @brief Marks the end of an object serialization context. + /// @param _obj Pointer to the OutputObjectType (unused). void end_object(OutputObjectType* /*_obj*/) const noexcept {} + /// + /// @brief Serializes a string_view as a sequence of bytes. + /// @param _str The string_view to serialize. void add_string_view(const std::string_view& _str) const { ar_->write_seq_size(_str.length()); ar_->write(_str.data(), _str.length()); } + /// + /// @brief Serializes a value, handling literal types specially. + /// @tparam T The type of the value. + /// @param _var The value to serialize. template void add_value(const T& _var) const { if constexpr (internal::is_literal_v) { @@ -214,6 +390,8 @@ struct Writer { } } + /// + /// @brief Pointer to the output archive used for serialization. OArchive* ar_; }; diff --git a/include/rfl/yas/load.hpp b/include/rfl/yas/load.hpp index 5771f882..1228cbb1 100644 --- a/include/rfl/yas/load.hpp +++ b/include/rfl/yas/load.hpp @@ -9,6 +9,13 @@ namespace rfl::yas { +/// Loads an object from a YAS binary file. +/// Reads a binary file from disk and parses its YAS content into a C++ object using compile-time reflection. +/// YAS (Yet Another Serialization) is a high-performance binary serialization library. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _fname The filename/path of the YAS binary file to load +/// @return Result containing either the parsed object of type T or an error message template Result load(const std::string& _fname) { const auto read_bytes = [](const auto& _bytes) { diff --git a/include/rfl/yas/read.hpp b/include/rfl/yas/read.hpp index 46f98747..90685728 100644 --- a/include/rfl/yas/read.hpp +++ b/include/rfl/yas/read.hpp @@ -18,7 +18,14 @@ namespace rfl::yas { using IArchive = Reader::IArchive; -/// Reads from an existing yas input archive. +/// Reads an object directly from an existing YAS binary input archive. +/// YAS (Yet Another Serialization) is a fast binary serialization library. +/// This function allows you to read from an already-opened YAS archive, useful when working +/// with YAS archives directly or reading multiple objects from the same archive. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _ar The YAS binary input archive to read from +/// @return The parsed object of type T template auto read_from_archive(IArchive& _ar) { auto r = Reader(); @@ -26,7 +33,14 @@ auto read_from_archive(IArchive& _ar) { return Parser>::read(r, var); } -/// Parses an object from bytes using a binary archive. +/// Parses an object from YAS binary bytes using reflection (with raw pointer and size). +/// YAS (Yet Another Serialization) is a high-performance binary serialization library +/// designed for speed and efficiency. It provides compact binary encoding. +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _bytes Pointer to byte-like data containing YAS binary format +/// @param _size The size of the byte array +/// @return Result containing either the parsed object (or array of objects) or an error message template Result> read( const concepts::ByteLike auto* _bytes, const size_t _size) { @@ -39,7 +53,11 @@ Result> read( } } -/// Parses an object from a byte container using a binary archive. +/// Parses an object from YAS binary format using reflection (contiguous container version). +/// @tparam T The type to parse into +/// @tparam Ps Processors to apply during parsing (transforms the data) +/// @param _bytes A contiguous byte container (e.g., std::vector, std::string) containing YAS binary data +/// @return Result containing either the parsed object (or array of objects) or an error message template auto read(const concepts::ContiguousByteContainer auto& _bytes) { return read(_bytes.data(), _bytes.size()); diff --git a/include/rfl/yas/save.hpp b/include/rfl/yas/save.hpp index 93c1e1e5..8778731d 100644 --- a/include/rfl/yas/save.hpp +++ b/include/rfl/yas/save.hpp @@ -10,6 +10,13 @@ namespace rfl::yas { +/// Saves an object to a YAS binary file. +/// Serializes a C++ object to YAS binary format and writes it to a file using compile-time reflection. +/// YAS (Yet Another Serialization) is a high-performance binary serialization library. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _fname The filename/path where the YAS binary file will be saved +/// @param _obj The object to serialize to YAS binary format +/// @return Result containing Nothing on success or an error message on failure template Result save(const std::string& _fname, const auto& _obj) { const auto write_func = [](const auto& _obj, auto& _stream) -> auto& { diff --git a/include/rfl/yas/write.hpp b/include/rfl/yas/write.hpp index f233fbc8..a6d88ef9 100644 --- a/include/rfl/yas/write.hpp +++ b/include/rfl/yas/write.hpp @@ -18,7 +18,13 @@ namespace rfl::yas { using OArchive = Writer::OArchive; -/// Writes an object to a yas OutputArchive. +/// Writes an object directly to an existing YAS binary output archive. +/// YAS (Yet Another Serialization) is a fast binary serialization library. +/// This function allows you to write to an already-opened YAS archive, useful when working +/// with YAS archives directly or writing multiple objects to the same archive. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _archive The YAS binary output archive to write to +/// @param _obj The object to serialize to the archive template void write_to_archive(OArchive& _archive, const auto& _obj) { using T = std::remove_cvref_t; @@ -27,7 +33,12 @@ void write_to_archive(OArchive& _archive, const auto& _obj) { Parser>::write(w, _obj, typename ParentType::Root{}); } -/// Returns yas binary bytes. +/// Returns YAS binary bytes representation of the object. +/// YAS (Yet Another Serialization) is a high-performance binary serialization library +/// designed for speed and efficiency. Uses compile-time reflection to serialize to YAS format. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to YAS binary format +/// @return A vector of chars containing the YAS binary representation template std::vector write(const auto& _obj) { ::yas::mem_ostream os; @@ -37,7 +48,12 @@ std::vector write(const auto& _obj) { return std::vector(buf.data, buf.data + buf.size); } -/// Writes yas binary format into an ostream. +/// Writes a YAS binary representation into an ostream. +/// Uses compile-time reflection to serialize a C++ object to YAS binary format and write to a stream. +/// @tparam Ps Processors to apply during serialization (transforms the data) +/// @param _obj The object to serialize to YAS binary format +/// @param _stream The output stream to write YAS binary data to +/// @return The output stream (for chaining) template std::ostream& write(const auto& _obj, std::ostream& _stream) { ::yas::mem_ostream os;