diff --git a/docs/custom_parser.md b/docs/custom_parser.md index 8a40e232..ca70fb46 100644 --- a/docs/custom_parser.md +++ b/docs/custom_parser.md @@ -1,9 +1,10 @@ # Custom parsers -## `rfl::Reflector` +## `rfl::Reflector` -If you absolutely do not want to make any changes to your original classes whatsoever, -You can create a Reflector template specialization for your type: +If you absolutely do not want to (or are unable to) make any changes to your +original classes whatsoever, you can create a Reflector template specialization +for your type: ```cpp namespace rfl { @@ -13,7 +14,7 @@ struct Reflector { std::string first_name; std::string last_name; }; - + static Person to(const ReflType& v) noexcept { return {v.first_name, v.last_name}; } @@ -25,7 +26,27 @@ struct Reflector { } ``` -It's also fine to define just the `from` method when the original class is +One way to help make sure that your `ReflType` is kept up to date with your +original class is to use the `rfl::num_fields` utility to implement a compile- +time assertion to verify that they have the same number of fields. The +`rfl::num_fields` utility can be used even in cases where the original +class is too complex for `reflect-cpp`'s default reflection logic or +`rfl::to_view()` to be able to handle. + +```cpp +namespace rfl { +template <> +struct Reflector { + struct ReflType { + std::string first_name; + std::string last_name; + }; + static_assert(rfl::num_fields == rfl::num_fields, + "ReflType and actual type must have the same number of fields"); + // ... +``` + +It's also fine to define just the `from` method when the original class is only written, or `to` when the original class is only read: ```cpp @@ -46,7 +67,7 @@ struct Reflector { ``` Note that the `ReflType` does not have to be a struct. For instance, if you have -a custom type called `MyCustomType` that you want to be serialized as a string, +a custom type called `MyCustomType` that you want to be serialized as a string, you can do the following: ```cpp @@ -114,7 +135,7 @@ struct Person { }; ``` -You can then write a helper struct: +You can then write a helper struct: ```cpp struct PersonImpl { diff --git a/docs/docs-readme.md b/docs/docs-readme.md index f132a683..bf3d6160 100644 --- a/docs/docs-readme.md +++ b/docs/docs-readme.md @@ -28,11 +28,11 @@ [Standard containers](standard_containers.md) - Describes how reflect-cpp treats containers in the standard library. -[C arrays and inheritance](c_arrays_and_inheritance.md) - Describes how reflect-cpp handles C arrays and inheritance. +[C arrays and inheritance](c_arrays_and_inheritance.md) - Describes how reflect-cpp handles C arrays and inheritance. -[rfl::Bytestring](bytestring.md) - Describes how reflect-cpp handles binary strings for formats that support them. +[rfl::Bytestring](bytestring.md) - Describes how reflect-cpp handles binary strings for formats that support them. -[rfl::Binary, rfl::Hex and rfl::Oct](number_systems.md)- For expressing numbers in different formats. +[rfl::Binary, rfl::Hex and rfl::Oct](number_systems.md)- For expressing numbers in different formats. ## Validation @@ -58,7 +58,7 @@ [Custom classes](concepts/custom_classes.md) - For custom classes with private fields. -[Custom parsers for your classes](custom_parser.md) - For custom classes with private fields that you want to leave absolutely untouched. +[Custom parsers for your classes](custom_parser.md) - For custom classes with private fields that you want (or need) to leave absolutely untouched. ## Useful helper functions and classes diff --git a/include/rfl/num_fields.hpp b/include/rfl/num_fields.hpp new file mode 100644 index 00000000..a65c01af --- /dev/null +++ b/include/rfl/num_fields.hpp @@ -0,0 +1,14 @@ +#ifndef RFL_NUM_FIELDS_HPP_ +#define RFL_NUM_FIELDS_HPP_ + +#include "internal/num_fields.hpp" + +namespace rfl { + +/// Returns the number of fields fields. +template +constexpr std::size_t num_fields = internal::num_fields; + +} // namespace rfl + +#endif diff --git a/tests/README.md b/tests/README.md index 6bcfee9e..8a2af281 100644 --- a/tests/README.md +++ b/tests/README.md @@ -3,8 +3,8 @@ reflect-cpp uses vcpkg for dependency management, including gtest, which is required for the tests. -```bash -# bootstrap vcpkg if you haven't done so already +```shell +# bootstrap vcpkg if you haven't done so already git submodule update --init ./vcpkg/bootstrap-vcpkg.sh # Linux, macOS ./vcpkg/bootstrap-vcpkg.bat # Windows @@ -15,7 +15,7 @@ git submodule update --init To compile the tests, do the following: -```bash +```shell cmake -S . -B build -DCMAKE_CXX_STANDARD=20 -DCMAKE_BUILD_TYPE=Release -DREFLECTCPP_BUILD_TESTS=ON cmake --build build -j 4 # gcc, clang cmake --build build --config Release -j 4 # MSVC @@ -23,7 +23,7 @@ cmake --build build --config Release -j 4 # MSVC To run the tests, do the following: -``` +```shell ./build/tests/json/reflect-cpp-json-tests ``` @@ -31,13 +31,19 @@ To run the tests, do the following: To compile the tests with serialization formats other than JSON, do the following: -```bash +```shell cmake -S . -B build -DCMAKE_CXX_STANDARD=20 -DREFLECTCPP_BUILD_TESTS=ON -DREFLECTCPP_AVRO=ON -DREFLECTCPP_BSON=ON -DREFLECTCPP_CAPNPROTO=ON -DREFLECTCPP_CBOR=ON -DREFLECTCPP_FLEXBUFFERS=ON -DREFLECTCPP_MSGPACK=ON -DREFLECTCPP_XML=ON -DREFLECTCPP_TOML=ON -DREFLECTCPP_UBJSON=ON -DREFLECTCPP_YAML=ON -DCMAKE_BUILD_TYPE=Release cmake --build build -j 4 # gcc, clang cmake --build build --config Release -j 4 # MSVC ``` -To run the tests, do the following: +You can run all of the tests via `ctest`, as in: + +```shell +ctest --test-dir build --output-on-failure +``` + +Or you can run tests individually, as in: ``` ./build/tests/avro/reflect-cpp-avro-tests diff --git a/tests/json_c_arrays_and_inheritance/test_inheritance2.cpp b/tests/json_c_arrays_and_inheritance/test_inheritance2.cpp index 01d50388..0bc67055 100644 --- a/tests/json_c_arrays_and_inheritance/test_inheritance2.cpp +++ b/tests/json_c_arrays_and_inheritance/test_inheritance2.cpp @@ -4,7 +4,7 @@ #include #include -#include "rfl/internal/num_fields.hpp" +#include "rfl/num_fields.hpp" namespace test_inheritance2 { @@ -31,23 +31,28 @@ struct EmptyDerived2 : EmptyBase1, EmptyBase2, BaseX {}; TEST(json, test_inheritance2) { Derived1 derived1; const auto derived1_view = rfl::to_view(derived1); + static_assert(rfl::num_fields == 2); static_assert(derived1_view.size() == 2); Derived2 derived2; const auto derived2_view = rfl::to_view(derived2); + static_assert(rfl::num_fields == 3); static_assert(derived2_view.size() == 3); - EmptyDerived1 empty_derived0; + EmptyDerived0 empty_derived0; auto empty_derived0_view = rfl::to_view(empty_derived0); + static_assert(rfl::num_fields == 2); static_assert(empty_derived0_view.size() == 2); EmptyDerived1 empty_derived1; auto empty_derived1_view = rfl::to_view(empty_derived1); + static_assert(rfl::num_fields == 2); static_assert(empty_derived1_view.size() == 2); - EmptyDerived1 empty_derived2; + EmptyDerived2 empty_derived2; auto empty_derived2_view = rfl::to_view(empty_derived2); - static_assert(empty_derived0_view.size() == 2); + static_assert(rfl::num_fields == 2); + static_assert(empty_derived2_view.size() == 2); EXPECT_TRUE(true); }