diff --git a/README.md b/README.md index bc06eef..5409f69 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Regardless of the generation method, these files are produced: # How to integrate bindings To integrate the bindings into your projects, simply add the generated bindings files to your project. -C++20 is required to compile the bindings. +C++17 or newer is required to compile the bindings. # Unsupported features diff --git a/bindgen/src/bindings/cpp/templates/callback.hpp b/bindgen/src/bindings/cpp/templates/callback.hpp index ea000f3..2ecfbc1 100644 --- a/bindgen/src/bindings/cpp/templates/callback.hpp +++ b/bindgen/src/bindings/cpp/templates/callback.hpp @@ -24,12 +24,14 @@ namespace uniffi { static uint64_t uniffi_clone(uint64_t uniffi_handle); static void init(); private: - static inline {{ vtable|ffi_type_name }} vtable = {{ vtable|ffi_type_name}} { - .uniffi_free = reinterpret_cast(&uniffi_free), - .uniffi_clone = reinterpret_cast(&uniffi_clone), + static inline {{ vtable|ffi_type_name }} vtable = [] { + {{ vtable|ffi_type_name }} value{}; + value.uniffi_free = reinterpret_cast(&uniffi_free); + value.uniffi_clone = reinterpret_cast(&uniffi_clone); {%- for (ffi_callback, meth) in vtable_methods.iter() %} - .{{ meth.name()|var_name }} = reinterpret_cast(&{{ meth.name()|var_name }}), + value.{{ meth.name()|var_name }} = reinterpret_cast(&{{ meth.name()|var_name }}); {%- endfor %} - }; + return value; + }(); }; } diff --git a/bindgen/src/bindings/cpp/templates/cpp_scaffolding.cpp b/bindgen/src/bindings/cpp/templates/cpp_scaffolding.cpp index 55bd69a..f3f6a41 100644 --- a/bindgen/src/bindings/cpp/templates/cpp_scaffolding.cpp +++ b/bindgen/src/bindings/cpp/templates/cpp_scaffolding.cpp @@ -8,8 +8,8 @@ #include #include -#include #include +#include #include #include #include @@ -125,11 +125,10 @@ extern "C" { UNIFFI_EXPORT RustBuffer {{ ci.ffi_rustbuffer_alloc().name() }}(int32_t size, RustCallStatus *out_status) { out_status->code = UNIFFI_CALL_STATUS_OK; - RustBuffer buf = { - .capacity = size, - .len = size, - .data = new uint8_t[size], - }; + RustBuffer buf{}; + buf.capacity = size; + buf.len = size; + buf.data = new uint8_t[size]; return std::move(buf); } @@ -137,11 +136,10 @@ UNIFFI_EXPORT RustBuffer {{ ci.ffi_rustbuffer_alloc().name() }}(int32_t size, Ru UNIFFI_EXPORT RustBuffer {{ ci.ffi_rustbuffer_from_bytes().name() }}(ForeignBytes bytes, RustCallStatus *out_status) { out_status->code = UNIFFI_CALL_STATUS_OK; - RustBuffer buf = { - .capacity = bytes.len, - .len = bytes.len, - .data = new uint8_t[bytes.len], - }; + RustBuffer buf{}; + buf.capacity = bytes.len; + buf.len = bytes.len; + buf.data = new uint8_t[bytes.len]; std::copy(bytes.data, bytes.data + bytes.len, buf.data); @@ -157,11 +155,10 @@ UNIFFI_EXPORT void {{ ci.ffi_rustbuffer_free().name() }}(RustBuffer buf, RustCal UNIFFI_EXPORT RustBuffer {{ ci.ffi_rustbuffer_reserve().name() }}(RustBuffer buffer, int32_t additional, RustCallStatus *out_status) { out_status->code = UNIFFI_CALL_STATUS_OK; - RustBuffer buf = { - .capacity = buffer.capacity + additional, - .len = buffer.len, - .data = (uint8_t*)std::realloc(buffer.data, buffer.capacity + additional), - }; + RustBuffer buf{}; + buf.capacity = buffer.capacity + additional; + buf.len = buffer.len; + buf.data = (uint8_t*)std::realloc(buffer.data, buffer.capacity + additional); return std::move(buf); } diff --git a/bindgen/src/bindings/cpp/templates/enum_tmpl.cpp b/bindgen/src/bindings/cpp/templates/enum_tmpl.cpp index 602890c..faddc61 100644 --- a/bindgen/src/bindings/cpp/templates/enum_tmpl.cpp +++ b/bindgen/src/bindings/cpp/templates/enum_tmpl.cpp @@ -74,7 +74,7 @@ RustBuffer {{ ffi_converter_name }}::lower(const {{ type_name }} &val) { case {{ loop.index }}: return {{ type_name }}::{{ variant|variant_name(config.enum_style) }} { {%- for field in variant.fields() %} - .{% call macros::field_name(field, loop.index) %} = {{ field|read_fn }}(stream), + {{ field|read_fn }}(stream), {%- endfor %} }; {% endfor %} diff --git a/bindgen/src/bindings/cpp/templates/rust_buf_stream.cpp b/bindgen/src/bindings/cpp/templates/rust_buf_stream.cpp index 194c5d7..4752303 100644 --- a/bindgen/src/bindings/cpp/templates/rust_buf_stream.cpp +++ b/bindgen/src/bindings/cpp/templates/rust_buf_stream.cpp @@ -23,7 +23,7 @@ struct RustStream: std::basic_iostream { RustStream &operator>>(T &val) { read(reinterpret_cast(&val), sizeof(T)); - if (std::endian::native != std::endian::big) { + if (native_byte_order_is_little_endian()) { auto bytes = reinterpret_cast(&val); std::reverse(bytes, bytes + sizeof(T)); @@ -34,7 +34,7 @@ struct RustStream: std::basic_iostream { template >> RustStream &operator<<(T val) { - if (std::endian::native != std::endian::big) { + if (native_byte_order_is_little_endian()) { auto bytes = reinterpret_cast(&val); std::reverse(bytes, bytes + sizeof(T)); @@ -45,6 +45,12 @@ struct RustStream: std::basic_iostream { return *this; } private: + // Avoid platform-specific endian APIs while retaining C++17 compatibility. + static bool native_byte_order_is_little_endian() { + const std::uint16_t value = 1; + const auto *bytes = reinterpret_cast(&value); + return bytes[0] == 1; + } + RustStreamBuffer streambuf; }; - diff --git a/bindgen/src/bindings/cpp/templates/scaffolding/callback.cpp b/bindgen/src/bindings/cpp/templates/scaffolding/callback.cpp index 8543ffd..db4582b 100644 --- a/bindgen/src/bindings/cpp/templates/scaffolding/callback.cpp +++ b/bindgen/src/bindings/cpp/templates/scaffolding/callback.cpp @@ -11,11 +11,10 @@ class {{ iface.name() }}Proxy: public {{ iface.name() }} { ~{{ iface.name() }}Proxy() override { ForeignCallback *callback_stub = reinterpret_cast({{ ffi_converter_name|class_name }}::fn_handle.load()); - RustBuffer out_buf = { - .capacity = 0, - .len = 0, - .data = nullptr, - }; + RustBuffer out_buf{}; + out_buf.capacity = 0; + out_buf.len = 0; + out_buf.data = nullptr; callback_stub(this->handle, 0, nullptr, 0, &out_buf); @@ -33,11 +32,10 @@ class {{ iface.name() }}Proxy: public {{ iface.name() }} { throw std::runtime_error("callback stub not initialized, this indicates a bug in the generated code"); } - RustBuffer out_buf = { - .capacity = 0, - .len = 0, - .data = nullptr, - }; + RustBuffer out_buf{}; + out_buf.capacity = 0; + out_buf.len = 0; + out_buf.data = nullptr; int32_t size = 0; {% for arg in m.arguments() %} @@ -131,5 +129,3 @@ int32_t {{ ffi_converter_name|class_name }}::allocation_size(const {{ type_name } std::atomic {{ ffi_converter_name|class_name }}::fn_handle = 0; - - diff --git a/bindgen/src/bindings/cpp/templates/scaffolding/object_map.cpp b/bindgen/src/bindings/cpp/templates/scaffolding/object_map.cpp index a48ca78..f08205f 100644 --- a/bindgen/src/bindings/cpp/templates/scaffolding/object_map.cpp +++ b/bindgen/src/bindings/cpp/templates/scaffolding/object_map.cpp @@ -11,8 +11,9 @@ template struct ObjectMap { std::lock_guard guard(this->mutex); auto key = (uint64_t)impl.get(); - if (this->map.contains(key)) { - this->map.at(key).ref_count += 1; + auto it = this->map.find(key); + if (it != this->map.end()) { + it->second.ref_count += 1; } else { this->map.insert({ key, {impl, 1} }); } diff --git a/bindgen/src/bindings/cpp/templates/wrapper.hpp b/bindgen/src/bindings/cpp/templates/wrapper.hpp index 91f1738..97842e7 100644 --- a/bindgen/src/bindings/cpp/templates/wrapper.hpp +++ b/bindgen/src/bindings/cpp/templates/wrapper.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include diff --git a/cpp-tests/CMakeLists.txt b/cpp-tests/CMakeLists.txt index 0d946cd..1243070 100644 --- a/cpp-tests/CMakeLists.txt +++ b/cpp-tests/CMakeLists.txt @@ -1,9 +1,15 @@ cmake_minimum_required(VERSION 3.10) project(binding-tests VERSION 1.0.0 LANGUAGES CXX) -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +if (MSVC) + add_compile_options(/permissive-) +else() + add_compile_options(-pedantic-errors) +endif() + include(CTest) enable_testing() diff --git a/cpp-tests/tests/coverall/main.cpp b/cpp-tests/tests/coverall/main.cpp index b2a05a2..2393cd5 100644 --- a/cpp-tests/tests/coverall/main.cpp +++ b/cpp-tests/tests/coverall/main.cpp @@ -261,7 +261,10 @@ void test_interface_in_dicts() { auto coveralls = coverall::Coveralls::init("test_interface_in_dicts"); coveralls->add_patch(coverall::Patch::init(coverall::Color::kRed)); - coveralls->add_repair(coverall::Repair {.when = std::chrono::system_clock::now(), .patch = coverall::Patch::init(coverall::Color::kGreen)}); + coverall::Repair repair; + repair.when = std::chrono::system_clock::now(); + repair.patch = coverall::Patch::init(coverall::Color::kGreen); + coveralls->add_repair(repair); ASSERT_EQ(2, coveralls->get_repairs().size()); } @@ -315,7 +318,7 @@ void test_dict_with_non_string_keys() { void test_return_only_dict() { auto d = coverall::ReturnOnlyDict{ - .e = std::make_shared() + std::make_shared() }; EXPECT_EXCEPTION(coverall::try_input_return_only_dict(d), std::runtime_error); } diff --git a/cpp-tests/tests/rondpoint/main.cpp b/cpp-tests/tests/rondpoint/main.cpp index 5b8ae87..2fa9e13 100644 --- a/cpp-tests/tests/rondpoint/main.cpp +++ b/cpp-tests/tests/rondpoint/main.cpp @@ -26,10 +26,10 @@ void affirm_enchaine(const T& c, const F& func, Args&& ...arg) { void test_copy() { auto dict = rondpoint::Dictionnaire { - .un = rondpoint::Enumeration::kDeux, - .deux = true, - .petit_nombre = 0, - .gros_nombre = 123456789u + rondpoint::Enumeration::kDeux, + true, + 0, + 123456789u }; auto copied_dict = rondpoint::copie_dictionnaire(dict); ASSERT_EQ(dict.un, copied_dict.un); @@ -44,8 +44,8 @@ void test_copy() { auto map = std::unordered_map { { "zero", rondpoint::EnumerationAvecDonnees::kZero {}}, - { "un", rondpoint::EnumerationAvecDonnees::kUn {.premier = 2}}, - { "deux", rondpoint::EnumerationAvecDonnees::kDeux {.premier= 1, .second = "test"}} + { "un", rondpoint::EnumerationAvecDonnees::kUn {2}}, + { "deux", rondpoint::EnumerationAvecDonnees::kDeux {1, "test"}} }; auto copied_map = rondpoint::copie_carte(map); ASSERT_EQ(map.size(), copied_map.size()); @@ -100,10 +100,10 @@ void test_roundtrip() { for (auto i : {-1, 0, 1}) { auto nombres_signes = rondpoint::DictionnaireNombresSignes { - .petit_nombre = (int8_t)i, - .court_nombre = (int16_t)i, - .nombre_simple = (int32_t)i, - .gros_nombre = (int64_t)i, + (int8_t)i, + (int16_t)i, + (int32_t)i, + (int64_t)i, }; auto ret = rt->identique_nombres_signes(nombres_signes); @@ -115,10 +115,10 @@ void test_roundtrip() { for (auto i : {0, 1}) { auto nombres = rondpoint::DictionnaireNombres { - .petit_nombre = (uint8_t)i, - .court_nombre = (uint16_t)i, - .nombre_simple = (uint32_t)i, - .gros_nombre = (uint64_t)i, + (uint8_t)i, + (uint16_t)i, + (uint32_t)i, + (uint64_t)i, }; auto ret = rt->identique_nombres(nombres); @@ -181,21 +181,21 @@ void test_default_parameter_literals_in_record() { auto rt = rondpoint::Retourneur::init(); auto dict = rondpoint::OptionneurDictionnaire { - .i8_var = -8, - .u8_var = 8, - .i16_var = -16, - .u16_var = 0x10, - .i32_var = -32, - .u32_var = 32, - .i64_var = -64, - .u64_var = 64, - .float_var = 4.0f, - .double_var = 8.0, - .boolean_var = true, - .string_var = "default", - .list_var = std::vector{}, - .enumeration_var = rondpoint::Enumeration::kDeux, - .dictionnaire_var = std::nullopt + -8, + 8, + -16, + 0x10, + -32, + 32, + -64, + 64, + 4.0f, + 8.0, + true, + "default", + std::vector{}, + rondpoint::Enumeration::kDeux, + std::nullopt }; auto copied_dict = rt->identique_optionneur_dictionnaire(dict); ASSERT_EQ(dict.i8_var, copied_dict.i8_var); diff --git a/docs/SCAFFOLDING.md b/docs/SCAFFOLDING.md index 6c79b83..3bd8440 100644 --- a/docs/SCAFFOLDING.md +++ b/docs/SCAFFOLDING.md @@ -34,7 +34,7 @@ This file should be included once in the C++ library, and it will contain all of To ensure that the generated code is able to interface with the target C++ library, the following guidelines should be followed: -- The library should be compiled with C++20 or later. +- The library should be compiled with C++17 or later. - When exposing a struct or class, all of the members mentioned in the UDL file should be public. - For object types, all constructors mentioned in the UDL file should have a matching public constructor in the C++ library. - When exposing callback interfaces, it is recommended to not have any processing-intensive or global data modifying logic in the constructors and destructors of the backing C++ class, as due to the way uniffi internally handles callback interfaces, callback instances may be dynamically constructed multiple times during the runtime of the application. @@ -61,7 +61,7 @@ struct Handle { struct UniffiCustomTypeConverterHandle { static Handle into_custom(uint64_t val) { - Handle handle = Handle { .inner = val } // or some other more intricate logic + Handle handle{val}; // or some other more intricate logic return handle; }