diff --git a/CMakeLists.txt b/CMakeLists.txt index 71c8ce2b..720f608c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ option(REFLECTCPP_YAML "Enable YAML support" ${REFLECTCPP_ALL_FORMATS}) 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) +option(REFLECTCPP_BUILD_MODULES "Build reflectcpp as a C++ module" OFF) option(REFLECTCPP_USE_BUNDLED_DEPENDENCIES "Use the bundled dependencies" ON) @@ -446,6 +447,10 @@ if(REFLECTCPP_CHECK_HEADERS) endforeach() endif() +if (REFLECTCPP_BUILD_MODULES) + add_subdirectory(src/modules) +endif() + if (REFLECTCPP_INSTALL) include(GNUInstallDirs) include(CMakePackageConfigHelpers) diff --git a/README.md b/README.md index f82b555b..c6d04003 100644 --- a/README.md +++ b/README.md @@ -588,6 +588,33 @@ In addition, it supports the following custom containers: Finally, it is very easy to extend full support to your own classes, refer to the [documentation](https://rfl.getml.com/docs-readme) for details. +### Module support + +reflect-cpp has support for C++20 modules. To enable, pass `REFLECTCPP_BUILD_MODULES` to CMake. You must have CMake 3.28 or higher, and any build system that supports modules (such as Ninja). + +```cpp +import std; +import rfl; + +using std::string; + +struct Person { + string first_name; + string last_name; + int age; +}; + +const Person homer = Person{ + .first_name = "Homer", + .last_name = "Simpson", + .age = 45 +}; + +// We can now write into and read from a JSON string. +const string json_string = rfl::json::write(homer); +auto homer2 = rfl::json::read(json_string).value(); +``` + ## Installation diff --git a/include/rfl/capnproto/schema/CapnProtoTypes.hpp b/include/rfl/capnproto/schema/CapnProtoTypes.hpp index 6f50f4e6..959403a4 100644 --- a/include/rfl/capnproto/schema/CapnProtoTypes.hpp +++ b/include/rfl/capnproto/schema/CapnProtoTypes.hpp @@ -16,7 +16,7 @@ struct CapnProtoTypes { std::map unions_; }; -const char* MAP_DEFINITION = R"( +inline const char* MAP_DEFINITION = R"( struct Map(Value) { entries @0 :List(Entry); struct Entry { 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..27f7fc3d 100644 --- a/include/rfl/parsing/call_destructors_on_array_where_necessary.hpp +++ b/include/rfl/parsing/call_destructors_on_array_where_necessary.hpp @@ -1,3 +1,4 @@ + #ifndef RFL_PARSING_CALL_DESTRUCTORS_ON_ARRAY_WHERE_NECESSARY_HPP_ #define RFL_PARSING_CALL_DESTRUCTORS_ON_ARRAY_WHERE_NECESSARY_HPP_ diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt new file mode 100644 index 00000000..8c34032d --- /dev/null +++ b/src/modules/CMakeLists.txt @@ -0,0 +1,97 @@ +cmake_minimum_required(VERSION 3.28) + +add_library(reflectcpp_module) + +set(MODULE_FILES) + +if(REFLECTCPP_JSON) + list(APPEND MODULE_FILES rfl.json.cppm) + target_compile_definitions(reflectcpp_module PUBLIC REFLECTCPP_JSON) +endif() + +if(REFLECTCPP_AVRO) + list(APPEND MODULE_FILES rfl.avro.cppm) + target_compile_definitions(reflectcpp_module PUBLIC REFLECTCPP_AVRO) +endif() + +if(REFLECTCPP_BSON) + list(APPEND MODULE_FILES rfl.bson.cppm) + target_compile_definitions(reflectcpp_module PUBLIC REFLECTCPP_BSON) +endif() + +if(REFLECTCPP_CAPNPROTO) + list(APPEND MODULE_FILES rfl.capnproto.cppm) + target_compile_definitions(reflectcpp_module PUBLIC REFLECTCPP_CAPNPROTO) +endif() + +if(REFLECTCPP_CBOR) + list(APPEND MODULE_FILES rfl.cbor.cppm) + target_compile_definitions(reflectcpp_module PUBLIC REFLECTCPP_CBOR) +endif() + +if(REFLECTCPP_CSV) + list(APPEND MODULE_FILES rfl.csv.cppm) + target_compile_definitions(reflectcpp_module PUBLIC REFLECTCPP_CSV) +endif() + +if(REFLECTCPP_FLEXBUFFERS) + list(APPEND MODULE_FILES rfl.flexbuf.cppm) + target_compile_definitions(reflectcpp_module PUBLIC REFLECTCPP_FLEXBUFFERS) +endif() + +if(REFLECTCPP_MSGPACK) + list(APPEND MODULE_FILES rfl.msgpack.cppm) + target_compile_definitions(reflectcpp_module PUBLIC REFLECTCPP_MSGPACK) +endif() + +if(REFLECTCPP_PARQUET) + list(APPEND MODULE_FILES rfl.parquet.cppm) + target_compile_definitions(reflectcpp_module PUBLIC REFLECTCPP_PARQUET) +endif() + +if(REFLECTCPP_TOML) + list(APPEND MODULE_FILES rfl.toml.cppm) + target_compile_definitions(reflectcpp_module PUBLIC REFLECTCPP_TOML) +endif() + +if(REFLECTCPP_UBJSON) + list(APPEND MODULE_FILES rfl.ubjson.cppm) + target_compile_definitions(reflectcpp_module PUBLIC REFLECTCPP_UBJSON) +endif() + +if(REFLECTCPP_XML) + list(APPEND MODULE_FILES rfl.xml.cppm) + target_compile_definitions(reflectcpp_module PUBLIC REFLECTCPP_XML) +endif() + +if(REFLECTCPP_YAML) + list(APPEND MODULE_FILES rfl.yaml.cppm) + target_compile_definitions(reflectcpp_module PUBLIC REFLECTCPP_YAML) +endif() + +list(APPEND MODULE_FILES rfl.cppm) + +target_sources(reflectcpp_module + PUBLIC + FILE_SET CXX_MODULES FILES ${MODULE_FILES} +) + +target_compile_features(reflectcpp_module PUBLIC cxx_std_23) + +target_include_directories(reflectcpp_module PUBLIC + $ + $ +) + +target_link_libraries(reflectcpp_module PUBLIC reflectcpp::reflectcpp) + +add_library(reflectcpp::module ALIAS reflectcpp_module) + +# Installation +install(TARGETS reflectcpp_module + EXPORT ${PROJECT_NAME}Targets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + FILE_SET CXX_MODULES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/src/module +) diff --git a/src/modules/rfl.avro.cppm b/src/modules/rfl.avro.cppm new file mode 100644 index 00000000..0a342e23 --- /dev/null +++ b/src/modules/rfl.avro.cppm @@ -0,0 +1,30 @@ +module; + +#ifdef REFLECTCPP_AVRO +#include "rfl/avro.hpp" +#include "rfl/avro/schema/Type.hpp" +#endif + +export module rfl:avro; + +export namespace rfl::avro { + #ifdef REFLECTCPP_AVRO + using rfl::avro::Parser; + using rfl::avro::Reader; + using rfl::avro::Schema; + using rfl::avro::Writer; + using rfl::avro::InputObjectType; + using rfl::avro::InputVarType; + + using rfl::avro::load; + using rfl::avro::read; + using rfl::avro::save; + using rfl::avro::to_json_representation; + using rfl::avro::to_schema; + using rfl::avro::write; + + namespace schema { + using rfl::avro::schema::Type; + } + #endif +} diff --git a/src/modules/rfl.bson.cppm b/src/modules/rfl.bson.cppm new file mode 100644 index 00000000..2da78c4d --- /dev/null +++ b/src/modules/rfl.bson.cppm @@ -0,0 +1,22 @@ +module; + +#ifdef REFLECTCPP_BSON +#include "rfl/bson.hpp" +#endif + +export module rfl:bson; + +export namespace rfl::bson { + #ifdef REFLECTCPP_BSON + using rfl::bson::Parser; + using rfl::bson::Reader; + using rfl::bson::Writer; + using rfl::bson::InputObjectType; + using rfl::bson::InputVarType; + + using rfl::bson::load; + using rfl::bson::read; + using rfl::bson::save; + using rfl::bson::write; + #endif +} diff --git a/src/modules/rfl.capnproto.cppm b/src/modules/rfl.capnproto.cppm new file mode 100644 index 00000000..106464a3 --- /dev/null +++ b/src/modules/rfl.capnproto.cppm @@ -0,0 +1,41 @@ +module; + +#ifdef REFLECTCPP_CAPNPROTO +#include "rfl/capnproto.hpp" +#include "rfl/capnproto/is_named_type.hpp" +#include "rfl/capnproto/schema/CapnProtoTypes.hpp" +#endif + +export module rfl:capnproto; + +export namespace rfl::capnproto { + #ifdef REFLECTCPP_CAPNPROTO + using rfl::capnproto::Parser; + using rfl::capnproto::Reader; + using rfl::capnproto::Schema; + using rfl::capnproto::SchemaImpl; + using rfl::capnproto::SchemaHolder; + using rfl::capnproto::Writer; + using rfl::capnproto::InputObjectType; + using rfl::capnproto::InputVarType; + + using rfl::capnproto::load; + using rfl::capnproto::read; + using rfl::capnproto::save; + using rfl::capnproto::to_schema; + using rfl::capnproto::write; + using rfl::capnproto::get_root_name; + using rfl::capnproto::is_named_type; + using rfl::capnproto::to_string_representation; + using rfl::capnproto::to_schema; + + namespace schema { + using rfl::capnproto::schema::CapnProtoTypes; + using rfl::capnproto::schema::Type; + + using rfl::capnproto::schema::MAP_DEFINITION; + + using rfl::capnproto::schema::operator<<; + } + #endif +} diff --git a/src/modules/rfl.cbor.cppm b/src/modules/rfl.cbor.cppm new file mode 100644 index 00000000..03851a35 --- /dev/null +++ b/src/modules/rfl.cbor.cppm @@ -0,0 +1,22 @@ +module; + +#ifdef REFLECTCPP_CBOR +#include "rfl/cbor.hpp" +#endif + +export module rfl:cbor; + +export namespace rfl::cbor { + #ifdef REFLECTCPP_CBOR + using rfl::cbor::Parser; + using rfl::cbor::Reader; + using rfl::cbor::Writer; + using rfl::cbor::InputObjectType; + using rfl::cbor::InputVarType; + + using rfl::cbor::load; + using rfl::cbor::read; + using rfl::cbor::save; + using rfl::cbor::write; + #endif +} diff --git a/src/modules/rfl.cppm b/src/modules/rfl.cppm new file mode 100644 index 00000000..49ca4508 --- /dev/null +++ b/src/modules/rfl.cppm @@ -0,0 +1,171 @@ +module; + +#include "rfl.hpp" + +export module rfl; + +export namespace rfl { +using rfl::AddNamespacedTagsToVariants; +using rfl::AddStructName; +using rfl::AddTagsToVariants; +using rfl::AllOf; +using rfl::AllowRawPtrs; +using rfl::AlphaNumeric; +using rfl::AnyOf; +using rfl::Attribute; +using rfl::Base64Encoded; +using rfl::Binary; +using rfl::Box; +using rfl::Bytestring; +using rfl::Copyability; +using rfl::CopyableBox; +using rfl::Default; +using rfl::DefaultIfMissing; +using rfl::DefaultVal; +using rfl::Description; +using rfl::Email; +using rfl::EqualTo; +using rfl::Error; +using rfl::ExclusiveMaximum; +using rfl::ExclusiveMinimum; +using rfl::ExtraFields; +using rfl::Field; +using rfl::Flatten; +using rfl::Generic; +using rfl::Hex; +using rfl::Literal; +using rfl::LiteralHelper; +using rfl::Maximum; +using rfl::Minimum; +using rfl::NamedTuple; +using rfl::NoExtraFields; +using rfl::NoFieldNames; +using rfl::NoOptionals; +using rfl::NotEqualTo; +using rfl::Nothing; +using rfl::Object; +using rfl::Oct; +using rfl::OneOf; +using rfl::Pattern; +using rfl::PatternValidator; +using rfl::PossibleTags; +using rfl::Processors; +using rfl::Ref; +using rfl::Rename; +using rfl::Result; +using rfl::Size; +using rfl::Skip; +using rfl::SkipDeserialization; +using rfl::SkipSerialization; +using rfl::SnakeCaseToCamelCase; +using rfl::SnakeCaseToPascalCase; +using rfl::TaggedUnion; +using rfl::TaggedUnionBased; +using rfl::Timestamp; +using rfl::UnderlyingEnums; +using rfl::Unexpected; +using rfl::UUIDv1; +using rfl::UUIDv2; +using rfl::UUIDv3; +using rfl::UUIDv4; +using rfl::Validator; +using rfl::Variant; +using rfl::VariantBased; +using rfl::Vectorstring; + +using rfl::apply; +using rfl::as; +using rfl::enum_to_string; +using rfl::error; +using rfl::fields; +using rfl::from_generic; +using rfl::from_named_tuple; +using rfl::get; +using rfl::get_enum_range; +using rfl::get_enumerator_array; +using rfl::get_enumerators; +using rfl::get_if; +using rfl::get_underlying_enumerator_array; +using rfl::get_underlying_enumerators; +using rfl::holds_alternative; +using rfl::make_box; +using rfl::make_copyable_box; +using rfl::make_field; +using rfl::make_from_tuple; +using rfl::make_named_tuple; +using rfl::make_ref; +using rfl::name_of; +using rfl::replace; +using rfl::string_to_enum; +using rfl::to_array; +using rfl::to_bool; +using rfl::to_double; +using rfl::to_generic; +using rfl::to_int; +using rfl::to_int64; +using rfl::to_named_tuple; +using rfl::to_null; +using rfl::to_object; +using rfl::to_string; +using rfl::to_view; +using rfl::tuple_cat; +using rfl::value_of; +using rfl::visit; + +using rfl::always_false_v; +using rfl::default_value; +using rfl::define_literal_t; +using rfl::define_named_tuple_t; +using rfl::define_tagged_union_t; +using rfl::define_variant_t; +using rfl::extract_discriminators_t; +using rfl::field_type_t; +using rfl::name_t; +using rfl::named_tuple_t; +using rfl::possible_tags_t; +using rfl::remove_fields_t; +using rfl::type_name_t; +using rfl::variant_alternative; +using rfl::variant_alternative_t; +using rfl::variant_size; +using rfl::variant_size_v; +using rfl::view_t; + +using rfl::operator<=>; +using rfl::operator<<; +using rfl::operator*; +using rfl::operator==; + +namespace atomic { +using rfl::atomic::is_atomic_v; +using rfl::atomic::remove_atomic_t; +using rfl::atomic::set_atomic; +} // namespace atomic + +namespace concepts { +using rfl::concepts::BackInsertableByteContainer; +using rfl::concepts::ByteLike; +using rfl::concepts::ByteSpanLike; +using rfl::concepts::ContiguousByteContainer; +using rfl::concepts::MutableContiguousByteContainer; +} // namespace concepts + +namespace generic { +using rfl::generic::Parser; +using rfl::generic::Reader; +using rfl::generic::Writer; + +using rfl::generic::read; +using rfl::generic::write; +} // namespace generic + +} // namespace rfl + +export namespace std { +using std::hash; +using std::swap; + +#ifdef REFLECTCPP_USE_STD_EXPECTED +using std::bad_expected_access; +#endif +} // namespace std diff --git a/src/modules/rfl.csv.cppm b/src/modules/rfl.csv.cppm new file mode 100644 index 00000000..7c9821fa --- /dev/null +++ b/src/modules/rfl.csv.cppm @@ -0,0 +1,18 @@ +module; + +#ifdef REFLECTCPP_CSV +#include "rfl/csv.hpp" +#endif + +export module rfl:csv; + +export namespace rfl::csv { + #ifdef REFLECTCPP_CSV + using rfl::csv::Settings; + + using rfl::csv::load; + using rfl::csv::read; + using rfl::csv::save; + using rfl::csv::write; + #endif +} diff --git a/src/modules/rfl.flexbuf.cppm b/src/modules/rfl.flexbuf.cppm new file mode 100644 index 00000000..f040913a --- /dev/null +++ b/src/modules/rfl.flexbuf.cppm @@ -0,0 +1,21 @@ +module; + +#ifdef REFLECTCPP_FLEXBUFFERS +#include "rfl/flexbuf.hpp" +#endif + +export module rfl:flexbuf; + +export namespace rfl::flexbuf { + #ifdef REFLECTCPP_FLEXBUFFERS + using rfl::flexbuf::Parser; + using rfl::flexbuf::Reader; + using rfl::flexbuf::Writer; + + using rfl::flexbuf::load; + using rfl::flexbuf::read; + using rfl::flexbuf::save; + using rfl::flexbuf::to_buffer; + using rfl::flexbuf::write; + #endif +} diff --git a/src/modules/rfl.json.cppm b/src/modules/rfl.json.cppm new file mode 100644 index 00000000..2bcb69b7 --- /dev/null +++ b/src/modules/rfl.json.cppm @@ -0,0 +1,31 @@ +module; + +#ifdef REFLECTCPP_JSON +#include "rfl/json.hpp" +#endif + +export module rfl:json; + +export namespace rfl::json { + #ifdef REFLECTCPP_JSON + using rfl::json::Parser; + using rfl::json::Reader; + using rfl::json::Writer; + using rfl::json::InputObjectType; + using rfl::json::InputVarType; + using rfl::json::TypeHelper; + + using rfl::json::pretty; + + using rfl::json::load; + using rfl::json::read; + using rfl::json::save; + using rfl::json::to_schema; + using rfl::json::write; + + namespace schema { + using rfl::json::schema::JSONSchema; + using rfl::json::schema::Type; + } + #endif +} \ No newline at end of file diff --git a/src/modules/rfl.msgpack.cppm b/src/modules/rfl.msgpack.cppm new file mode 100644 index 00000000..ebfa9705 --- /dev/null +++ b/src/modules/rfl.msgpack.cppm @@ -0,0 +1,22 @@ +module; + +#ifdef REFLECTCPP_MSGPACK +#include "rfl/msgpack.hpp" +#endif + +export module rfl:msgpack; + +export namespace rfl::msgpack { + #ifdef REFLECTCPP_MSGPACK + using rfl::msgpack::Parser; + using rfl::msgpack::Reader; + using rfl::msgpack::Writer; + using rfl::msgpack::InputObjectType; + using rfl::msgpack::InputVarType; + + using rfl::msgpack::load; + using rfl::msgpack::read; + using rfl::msgpack::save; + using rfl::msgpack::write; + #endif +} diff --git a/src/modules/rfl.parquet.cppm b/src/modules/rfl.parquet.cppm new file mode 100644 index 00000000..3433c97c --- /dev/null +++ b/src/modules/rfl.parquet.cppm @@ -0,0 +1,20 @@ +module; + +#ifdef REFLECTCPP_PARQUET +#include "rfl/parquet.hpp" +#endif + +export module rfl:parquet; + +export namespace rfl::parquet { + #ifdef REFLECTCPP_PARQUET + using rfl::parquet::Compression; + using rfl::parquet::Settings; + + using rfl::parquet::load; + using rfl::parquet::read; + using rfl::parquet::save; + using rfl::parquet::to_buffer; + using rfl::parquet::write; + #endif +} diff --git a/src/modules/rfl.toml.cppm b/src/modules/rfl.toml.cppm new file mode 100644 index 00000000..f68e4570 --- /dev/null +++ b/src/modules/rfl.toml.cppm @@ -0,0 +1,21 @@ +module; + +#ifdef REFLECTCPP_TOML +#include "rfl/toml.hpp" +#endif + +export module rfl:toml; + +export namespace rfl::toml { + #ifdef REFLECTCPP_TOML + using rfl::toml::Parser; + using rfl::toml::Reader; + using rfl::toml::Writer; + using rfl::toml::InputVarType; + + using rfl::toml::load; + using rfl::toml::read; + using rfl::toml::save; + using rfl::toml::write; + #endif +} diff --git a/src/modules/rfl.ubjson.cppm b/src/modules/rfl.ubjson.cppm new file mode 100644 index 00000000..186946c8 --- /dev/null +++ b/src/modules/rfl.ubjson.cppm @@ -0,0 +1,22 @@ +module; + +#ifdef REFLECTCPP_UBJSON +#include "rfl/ubjson.hpp" +#endif + +export module rfl:ubjson; + +export namespace rfl::ubjson { + #ifdef REFLECTCPP_UBJSON + using rfl::ubjson::Parser; + using rfl::ubjson::Reader; + using rfl::ubjson::Writer; + using rfl::ubjson::InputObjectType; + using rfl::ubjson::InputVarType; + + using rfl::ubjson::load; + using rfl::ubjson::read; + using rfl::ubjson::save; + using rfl::ubjson::write; + #endif +} diff --git a/src/modules/rfl.xml.cppm b/src/modules/rfl.xml.cppm new file mode 100644 index 00000000..15aab77a --- /dev/null +++ b/src/modules/rfl.xml.cppm @@ -0,0 +1,22 @@ +module; + +#ifdef REFLECTCPP_XML +#include "rfl/xml.hpp" +#endif + +export module rfl:xml; + +export namespace rfl::xml { + #ifdef REFLECTCPP_XML + using rfl::xml::Parser; + using rfl::xml::Reader; + using rfl::xml::Writer; + using rfl::xml::InputVarType; + + using rfl::xml::load; + using rfl::xml::read; + using rfl::xml::save; + using rfl::xml::get_root_name; + using rfl::xml::write; + #endif +} diff --git a/src/modules/rfl.yaml.cppm b/src/modules/rfl.yaml.cppm new file mode 100644 index 00000000..253ee5a5 --- /dev/null +++ b/src/modules/rfl.yaml.cppm @@ -0,0 +1,21 @@ +module; + +#ifdef REFLECTCPP_YAML +#include "rfl/yaml.hpp" +#endif + +export module rfl:yaml; + +export namespace rfl::yaml { + #ifdef REFLECTCPP_YAML + using rfl::yaml::Parser; + using rfl::yaml::Reader; + using rfl::yaml::Writer; + using rfl::yaml::InputVarType; + + using rfl::yaml::load; + using rfl::yaml::read; + using rfl::yaml::save; + using rfl::yaml::write; + #endif +}