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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
65 changes: 60 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.23)
cmake_minimum_required(VERSION 3.28)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

Expand All @@ -8,6 +8,7 @@ option(REFLECTCPP_INSTALL "Install reflect cpp" OFF)

option(REFLECTCPP_ALL_FORMATS "Enable all supported formats" OFF)
option(REFLECTCPP_JSON "Enable JSON support" ON) # enabled by default
option(REFLECTCPP_CLI "Enable CLI support" ON)
option(REFLECTCPP_AVRO "Enable AVRO support" ${REFLECTCPP_ALL_FORMATS})
option(REFLECTCPP_BSON "Enable BSON support" ${REFLECTCPP_ALL_FORMATS})
option(REFLECTCPP_CAPNPROTO "Enable Cap’n Proto support" ${REFLECTCPP_ALL_FORMATS})
Expand All @@ -28,6 +29,11 @@ option(REFLECTCPP_BUILD_BENCHMARKS "Build benchmarks" OFF)
option(REFLECTCPP_BUILD_TESTS "Build tests" OFF)
option(REFLECTCPP_CHECK_HEADERS "Make sure that all headers are self-contained" OFF)

set(REFLECTCPP_ENUM_RANGE_MIN "-256" CACHE STRING
"Minimum value scanned during enum reflection")
set(REFLECTCPP_ENUM_RANGE_MAX "256" CACHE STRING
"Maximum value scanned during enum reflection")

option(REFLECTCPP_USE_BUNDLED_DEPENDENCIES "Use the bundled dependencies" ON)

option(REFLECTCPP_USE_STD_EXPECTED "Use std::expected instead of the built-in Result type (requires C++-23)" OFF)
Expand Down Expand Up @@ -233,10 +239,26 @@ if(REFLECTCPP_USE_STD_EXPECTED)
target_compile_definitions(reflectcpp PUBLIC REFLECTCPP_USE_STD_EXPECTED)
endif()

target_compile_definitions(reflectcpp PRIVATE
RFL_ENUM_RANGE_MIN=${REFLECTCPP_ENUM_RANGE_MIN}
RFL_ENUM_RANGE_MAX=${REFLECTCPP_ENUM_RANGE_MAX}
)

set(REFLECT_CPP_SOURCES
src/reflectcpp.cpp
)

set(REFLECT_CPP_MODULES
modules/rfl.cppm
)

if (REFLECTCPP_JSON OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES
modules/rfl.json.cppm
modules/rfl.c_arrays_and_inheritance.cppm
)
endif ()

target_include_directories(
reflectcpp PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
Expand Down Expand Up @@ -275,13 +297,14 @@ if (_REFLECTCPP_NEEDS_JSON_IMPL)
endif ()

if (REFLECTCPP_AVRO OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES modules/rfl.avro.cppm)
list(APPEND REFLECT_CPP_SOURCES
src/reflectcpp_avro.cpp
)
find_package(jansson CONFIG REQUIRED)
if (REFLECTCPP_USE_VCPKG)
target_include_directories(reflectcpp SYSTEM PRIVATE "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include")
if (MSVC)
if (WIN32)
set(_AVRO_STATIC_LIB "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/avro${CMAKE_STATIC_LIBRARY_SUFFIX}")
if(REFLECTCPP_BUILD_SHARED)
message(STATUS "With whole archive ${_AVRO_STATIC_LIB}")
Expand All @@ -308,6 +331,7 @@ if (REFLECTCPP_AVRO OR REFLECTCPP_CHECK_HEADERS)
endif ()

if (REFLECTCPP_BSON OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES modules/rfl.bson.cppm)
list(APPEND REFLECT_CPP_SOURCES
src/reflectcpp_bson.cpp
)
Expand All @@ -318,6 +342,7 @@ if (REFLECTCPP_BSON OR REFLECTCPP_CHECK_HEADERS)
endif ()

if (REFLECTCPP_CAPNPROTO OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES modules/rfl.capnproto.cppm)
list(APPEND REFLECT_CPP_SOURCES
src/reflectcpp_capnproto.cpp
)
Expand All @@ -333,6 +358,7 @@ if (REFLECTCPP_CAPNPROTO OR REFLECTCPP_CHECK_HEADERS)
endif ()

if (REFLECTCPP_CBOR OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES modules/rfl.cbor.cppm)
list(APPEND REFLECT_CPP_SOURCES
src/reflectcpp_cbor.cpp
)
Expand All @@ -343,6 +369,7 @@ if (REFLECTCPP_CBOR OR REFLECTCPP_CHECK_HEADERS)
endif ()

if (REFLECTCPP_CEREAL OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES modules/rfl.cereal.cppm)
list(APPEND REFLECT_CPP_SOURCES
src/reflectcpp_cereal.cpp
)
Expand All @@ -353,6 +380,7 @@ if (REFLECTCPP_CEREAL OR REFLECTCPP_CHECK_HEADERS)
endif()

if (REFLECTCPP_CSV OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES modules/rfl.csv.cppm)
if (NOT TARGET Arrow)
find_package(Arrow CONFIG REQUIRED)
endif()
Expand All @@ -364,6 +392,7 @@ if (REFLECTCPP_CSV OR REFLECTCPP_CHECK_HEADERS)
endif ()

if (REFLECTCPP_FLEXBUFFERS OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES modules/rfl.flexbuf.cppm)
list(APPEND REFLECT_CPP_SOURCES
src/reflectcpp_flexbuf.cpp
)
Expand All @@ -374,6 +403,7 @@ if (REFLECTCPP_FLEXBUFFERS OR REFLECTCPP_CHECK_HEADERS)
endif ()

if (REFLECTCPP_MSGPACK OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES modules/rfl.msgpack.cppm)
list(APPEND REFLECT_CPP_SOURCES
src/reflectcpp_msgpack.cpp
)
Expand All @@ -384,6 +414,7 @@ if (REFLECTCPP_MSGPACK OR REFLECTCPP_CHECK_HEADERS)
endif ()

if (REFLECTCPP_PARQUET OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES modules/rfl.parquet.cppm)
if (NOT TARGET Arrow)
find_package(Arrow CONFIG REQUIRED)
endif()
Expand All @@ -399,6 +430,7 @@ if (REFLECTCPP_PARQUET OR REFLECTCPP_CHECK_HEADERS)
endif ()

if (REFLECTCPP_TOML OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES modules/rfl.toml.cppm)
list(APPEND REFLECT_CPP_SOURCES
src/reflectcpp_toml.cpp
)
Expand All @@ -409,6 +441,7 @@ if (REFLECTCPP_TOML OR REFLECTCPP_CHECK_HEADERS)
endif()

if (REFLECTCPP_UBJSON OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES modules/rfl.ubjson.cppm)
list(APPEND REFLECT_CPP_SOURCES
src/reflectcpp_ubjson.cpp
)
Expand All @@ -419,6 +452,7 @@ if (REFLECTCPP_UBJSON OR REFLECTCPP_CHECK_HEADERS)
endif ()

if (REFLECTCPP_XML OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES modules/rfl.xml.cppm)
list(APPEND REFLECT_CPP_SOURCES
src/reflectcpp_xml.cpp
)
Expand All @@ -429,6 +463,7 @@ if (REFLECTCPP_XML OR REFLECTCPP_CHECK_HEADERS)
endif ()

if (REFLECTCPP_YAML OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES modules/rfl.yaml.cppm)
list(APPEND REFLECT_CPP_SOURCES
src/reflectcpp_yaml.cpp
)
Expand All @@ -439,6 +474,7 @@ if (REFLECTCPP_YAML OR REFLECTCPP_CHECK_HEADERS)
endif ()

if (REFLECTCPP_BOOST_SERIALIZATION OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES modules/rfl.boost_serialization.cppm)
list(APPEND REFLECT_CPP_SOURCES
src/reflectcpp_boost_serialization.cpp
)
Expand All @@ -449,15 +485,34 @@ if (REFLECTCPP_BOOST_SERIALIZATION OR REFLECTCPP_CHECK_HEADERS)
endif ()

if (REFLECTCPP_YAS OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES modules/rfl.yas.cppm)
list(APPEND REFLECT_CPP_SOURCES
src/reflectcpp_yas.cpp
)
find_path(YAS_INCLUDE_DIRS "yas/abseil_types.hpp")
target_include_directories(reflectcpp PRIVATE ${YAS_INCLUDE_DIRS})
endif ()

if (REFLECTCPP_CLI OR REFLECTCPP_CHECK_HEADERS)
list(APPEND REFLECT_CPP_MODULES modules/rfl.cli.cppm)
endif ()

set_source_files_properties(
${REFLECT_CPP_MODULES}
PROPERTIES
LANGUAGE CXX
SKIP_PRECOMPILE_HEADERS ON
)

set_target_properties(reflectcpp PROPERTIES LINKER_LANGUAGE CXX)
target_sources(reflectcpp PRIVATE ${REFLECT_CPP_SOURCES})
target_sources(reflectcpp
PUBLIC
FILE_SET rfl_modules
TYPE CXX_MODULES
BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/modules
FILES ${REFLECT_CPP_MODULES}
)
target_precompile_headers(reflectcpp PRIVATE [["rfl.hpp"]] <iostream> <string> <functional>)

if (REFLECTCPP_BUILD_TESTS)
Expand Down Expand Up @@ -528,7 +583,7 @@ if (REFLECTCPP_INSTALL)
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/reflectcpp"
)

file(GLOB_RECURSE RFL_HEADERS RELATIVE ${CMAKE_CURRENT_LIST_DIR} "${CMAKE_CURRENT_LIST_DIR}/include/*" )
file(GLOB_RECURSE RFL_HEADERS RELATIVE ${CMAKE_CURRENT_LIST_DIR} "${CMAKE_CURRENT_LIST_DIR}/include/*.h" "${CMAKE_CURRENT_LIST_DIR}/include/*.hpp")

target_sources(reflectcpp
PUBLIC
Expand All @@ -541,7 +596,8 @@ if (REFLECTCPP_INSTALL)
install(
TARGETS reflectcpp
EXPORT reflectcpp-exports
FILE_SET reflectcpp_headers DESTINATION ${INCLUDE_INSTALL_DIR}
FILE_SET reflectcpp_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILE_SET rfl_modules DESTINATION ${CMAKE_INSTALL_DATADIR}/reflectcpp/modules
)

install(
Expand Down Expand Up @@ -586,4 +642,3 @@ include(CPack)
if (ament_cmake_FOUND)
ament_package()
endif()

36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ reflect-cpp and sqlgen fill important gaps in C++ development. They reduce boile
- [Serialization formats](#serialization-formats)
- [Feature Overview](#feature-overview)
- [Simple Example](#simple-example)
- [C++ modules](#c-modules)
- [More Comprehensive Example](#more-comprehensive-example)
- [Tabular data](#tabular-data)
- [CLI argument parsing](#cli-argument-parsing)
Expand Down Expand Up @@ -179,6 +180,41 @@ rfl::xml::read<Person>(xml_string);
rfl::yas::read<Person>(yas_bytes);
```

### C++ modules

In addition to the classic header-based interface, reflect-cpp ships C++20
named modules. If your toolchain supports modules, you can replace the
`#include` directives with `import`:

```cpp
import rfl;
import rfl.json; // one submodule per serialization format, e.g. rfl.yaml, rfl.avro, ...

struct Person {
std::string first_name;
std::string last_name;
int age;
};

const auto homer =
Person{.first_name = "Homer", .last_name = "Simpson", .age = 45};

const std::string json_string = rfl::json::write(homer);
auto homer2 = rfl::json::read<Person>(json_string).value();
```

The public API is identical to the header-based interface; only the way you
bring the names into scope changes. Building the modules requires CMake `>= 3.28`
and a compiler with C++20 modules support. The module interface units live in
the [`modules/`](modules) directory and are enabled per format via the same
`REFLECTCPP_*` CMake options as the headers.

> **Note:** When consuming reflect-cpp as a module, the enum reflection range is
> baked into the compiled module interface. Configure it with the
> `REFLECTCPP_ENUM_RANGE_MIN` / `REFLECTCPP_ENUM_RANGE_MAX` CMake variables rather
> than the `RFL_ENUM_RANGE_MIN` / `RFL_ENUM_RANGE_MAX` macros. See the
> [enums documentation](https://rfl.getml.com/enums) for details.

### More Comprehensive Example

```cpp
Expand Down
11 changes: 11 additions & 0 deletions docs/enums.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@ However, some limitations apply:
#define RFL_ENUM_RANGE_MAX 128
#include <rfl.hpp>
```

If you consume reflect-cpp as a C++ module (`import rfl;`), you cannot define these macros in your own
translation units, because the range is baked into the compiled module interface. Instead, set the
`REFLECTCPP_ENUM_RANGE_MIN` and `REFLECTCPP_ENUM_RANGE_MAX` CMake cache variables when configuring the library:

```
cmake -DREFLECTCPP_ENUM_RANGE_MIN=-128 -DREFLECTCPP_ENUM_RANGE_MAX=128 ...
```

Note that these CMake variables only affect the compiled module interface; they have no effect on header-only
consumers, who should use the `RFL_ENUM_RANGE_MIN`/`RFL_ENUM_RANGE_MAX` macros shown above.
- You can specify a custom range for a specific enum by defining the specialization `rfl::config::enum_range` for
the enum type :
```cpp
Expand Down
4 changes: 3 additions & 1 deletion docs/rfl_tuple.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ functions.
You can use the functions `rfl::get`, `rfl::make_tuple`, `rfl::tuple_element_t`,
`rfl::tuple_size_v`, `rfl::tuple_cat` or `rfl::apply` to create or access the
tuple and they work the same way as their equivalents in the standard library.
In fact, `std::get` will also work on `rfl::Tuple`.

The legacy `std::get` overload for `rfl::Tuple` is deprecated. Use `rfl::get`
instead.
2 changes: 2 additions & 0 deletions include/rfl/Tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ namespace std {
/// @param _tup The Tuple to access.
/// @return Reference to the element at the specified index.
template <int _index, class... Types>
[[deprecated("Use rfl::get instead.")]]
constexpr auto& get(rfl::Tuple<Types...>& _tup) {
return _tup.template get<_index>();
}
Expand All @@ -353,6 +354,7 @@ constexpr auto& get(rfl::Tuple<Types...>& _tup) {
/// @param _tup The Tuple to access.
/// @return Const reference to the element at the specified index.
template <int _index, class... Types>
[[deprecated("Use rfl::get instead.")]]
constexpr const auto& get(const rfl::Tuple<Types...>& _tup) {
return _tup.template get<_index>();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ auto copy_one_element(const auto& _flattened_tuple) {
const auto name_literal = FieldNames::template name_of<_i>();
return rfl::make_field<
lit_name_v<std::remove_cvref_t<decltype(name_literal)>>>(
std::get<_i>(_flattened_tuple));
rfl::get<_i>(_flattened_tuple));
}

template <class FieldNames, class... Fields>
Expand Down
8 changes: 4 additions & 4 deletions include/rfl/internal/field_index_by_name.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ consteval std::string_view field_name_at() {
template <class T, StringLiteral Name, std::size_t... Is>
consteval std::size_t field_index_by_name_impl(std::index_sequence<Is...>) {
std::size_t result = static_cast<std::size_t>(-1);
((field_name_at<T, Is>() == Name.string_view()
? (result = Is, true)
: false) ||
...);
(void)(((field_name_at<T, Is>() == Name.string_view()
? (result = Is, true)
: false) ||
...));
return result;
}

Expand Down
10 changes: 5 additions & 5 deletions include/rfl/internal/field_index_from_ptm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ consteval std::size_t field_index_from_ptm_impl(std::index_sequence<Is...>) {
T obj{};
const void* target = static_cast<const void*>(&(obj.*FieldPtr));
std::size_t result = static_cast<std::size_t>(-1);
((static_cast<const void*>(get_ith_field_ptr<T, static_cast<int>(Is)>(obj)) ==
target
? (result = Is, true)
: false) ||
...);
(void)(((static_cast<const void*>(
get_ith_field_ptr<T, static_cast<int>(Is)>(obj)) == target
? (result = Is, true)
: false) ||
...));
return result;
#else
const void* target =
Expand Down
6 changes: 3 additions & 3 deletions include/rfl/internal/move_from_tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ auto unflatten_ptr_tuple(PtrTupleType& _t, Args... _args) {

} else {
return unflatten_ptr_tuple<TargetTupleType, PtrTupleType, _j + 1>(
_t, _args..., std::get<_j>(_t));
_t, _args..., rfl::get<_j>(_t));
}
}
}
Expand All @@ -71,7 +71,7 @@ auto move_from_pointers(Pointers& _ptrs, Args&&... _args) {

if constexpr (std::is_pointer_v<FieldType>) {
return move_from_pointers<T>(_ptrs, std::move(_args)...,
std::move(*std::get<i>(_ptrs)));
std::move(*rfl::get<i>(_ptrs)));

} else {
using PtrTupleType = ptr_tuple_t<std::remove_cvref_t<T>>;
Expand All @@ -80,7 +80,7 @@ auto move_from_pointers(Pointers& _ptrs, Args&&... _args) {
tuple_element_t<i, PtrTupleType>>::Type>;

return move_from_pointers<T>(_ptrs, std::move(_args)...,
move_from_pointers<U>(std::get<i>(_ptrs)));
move_from_pointers<U>(rfl::get<i>(_ptrs)));
}
}
}
Expand Down
Loading