Skip to content
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
12 changes: 7 additions & 5 deletions bindgen/src/bindings/cpp/templates/callback.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<void *>(&uniffi_free),
.uniffi_clone = reinterpret_cast<void *>(&uniffi_clone),
static inline {{ vtable|ffi_type_name }} vtable = [] {
{{ vtable|ffi_type_name }} value{};
value.uniffi_free = reinterpret_cast<void *>(&uniffi_free);
value.uniffi_clone = reinterpret_cast<void *>(&uniffi_clone);
{%- for (ffi_callback, meth) in vtable_methods.iter() %}
.{{ meth.name()|var_name }} = reinterpret_cast<void *>(&{{ meth.name()|var_name }}),
value.{{ meth.name()|var_name }} = reinterpret_cast<void *>(&{{ meth.name()|var_name }});
{%- endfor %}
};
return value;
}();
};
}
29 changes: 13 additions & 16 deletions bindgen/src/bindings/cpp/templates/cpp_scaffolding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

#include <stdio.h>
#include <stdint.h>
#include <bit>
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <cstdlib>
#include <memory>
Expand Down Expand Up @@ -125,23 +125,21 @@ 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);
}

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);

Expand All @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion bindgen/src/bindings/cpp/templates/enum_tmpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 %}
Expand Down
12 changes: 9 additions & 3 deletions bindgen/src/bindings/cpp/templates/rust_buf_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct RustStream: std::basic_iostream<char> {
RustStream &operator>>(T &val) {
read(reinterpret_cast<char *>(&val), sizeof(T));

if (std::endian::native != std::endian::big) {
if (native_byte_order_is_little_endian()) {
auto bytes = reinterpret_cast<char *>(&val);

std::reverse(bytes, bytes + sizeof(T));
Expand All @@ -34,7 +34,7 @@ struct RustStream: std::basic_iostream<char> {

template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
RustStream &operator<<(T val) {
if (std::endian::native != std::endian::big) {
if (native_byte_order_is_little_endian()) {
auto bytes = reinterpret_cast<char *>(&val);

std::reverse(bytes, bytes + sizeof(T));
Expand All @@ -45,6 +45,12 @@ struct RustStream: std::basic_iostream<char> {
return *this;
}
private:
// Avoid platform-specific endian APIs while retaining C++17 compatibility.
static bool native_byte_order_is_little_endian() {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the biggest loss of the downgrade, not having native std::endian support is unfortunate. But this is a very small impl to get equivalency

const std::uint16_t value = 1;
const auto *bytes = reinterpret_cast<const unsigned char *>(&value);
return bytes[0] == 1;
}

RustStreamBuffer streambuf;
};

20 changes: 8 additions & 12 deletions bindgen/src/bindings/cpp/templates/scaffolding/callback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ class {{ iface.name() }}Proxy: public {{ iface.name() }} {
~{{ iface.name() }}Proxy() override {
ForeignCallback *callback_stub = reinterpret_cast<ForeignCallback *>({{ 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);

Expand All @@ -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() %}
Expand Down Expand Up @@ -131,5 +129,3 @@ int32_t {{ ffi_converter_name|class_name }}::allocation_size(const {{ type_name
}

std::atomic<uint64_t> {{ ffi_converter_name|class_name }}::fn_handle = 0;


5 changes: 3 additions & 2 deletions bindgen/src/bindings/cpp/templates/scaffolding/object_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ template <typename T> struct ObjectMap {
std::lock_guard<std::mutex> 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} });
}
Expand Down
1 change: 0 additions & 1 deletion bindgen/src/bindings/cpp/templates/wrapper.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once

#include <algorithm>
#include <bit>
#include <chrono>
#include <cstdint>
#include <exception>
Expand Down
8 changes: 7 additions & 1 deletion cpp-tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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()

Expand Down
7 changes: 5 additions & 2 deletions cpp-tests/tests/coverall/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}

Expand Down Expand Up @@ -315,7 +318,7 @@ void test_dict_with_non_string_keys() {

void test_return_only_dict() {
auto d = coverall::ReturnOnlyDict{
.e = std::make_shared<coverall::coverall_flat_error::TooManyVariants>()
std::make_shared<coverall::coverall_flat_error::TooManyVariants>()
};
EXPECT_EXCEPTION(coverall::try_input_return_only_dict(d), std::runtime_error);
}
Expand Down
58 changes: 29 additions & 29 deletions cpp-tests/tests/rondpoint/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -44,8 +44,8 @@ void test_copy() {

auto map = std::unordered_map<std::string, rondpoint::EnumerationAvecDonnees> {
{ "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());
Expand Down Expand Up @@ -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);

Expand All @@ -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);

Expand Down Expand Up @@ -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<std::string>{},
.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<std::string>{},
rondpoint::Enumeration::kDeux,
std::nullopt
};
auto copied_dict = rt->identique_optionneur_dictionnaire(dict);
ASSERT_EQ(dict.i8_var, copied_dict.i8_var);
Expand Down
4 changes: 2 additions & 2 deletions docs/SCAFFOLDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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;
}
Expand Down
Loading