Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

C++ Backend

Type Conversion

The C++ type conversions are built upon the C ABI, with some additionall STL types to make working with the C ABI more intuitive from a C++ standpoint.

Primitives

See C Primitives.

Struct Types

Diplomat TypeC++ Type
#[diplomat::opaque] pub struct Typeclass Type {...}
pub struct Typeclass Type{...}
pub enum Typeclass Type{...}

Opaques

Opaques are treated as classes that wrap their C ABI pointer, but upon return either wrapped in a std::unique_ptr<Type> or a simple Type* pointer.

Structs

Structs are represented as C++ structs with methods. Each C++ struct is converted from the C ABI into its relevant C++ type.

Enums

Enum classes hold an inner enum Type::Value which mirrors the Rust enum. This will be converted to a C-friendly Enum on being passed to the ABI.

Options

All options (with the exception of options of opaque types) are represented as std::optional<InnerType>.

Opaque Options

All opaque types are behind a reference (const Opaque* or Opaque *) or a unique_ptr, so options of these types are correspondingly behind nullable * pointers and nullable unique_ptrs.

Results

All results are returned as diplomat::result<T, E>, which is backed by std::variant.

auto result = MyClass::get_result();
// Get the ok value:
if (result.is_ok()) {
    auto ok = std::move(result).ok().value();
} else if (result.is_err()) {
    auto err = std::move(result).err().value();
}

Slices

Diplomat TypeC++ Type
&[Primitive]diplomat::span<const Primitive>
&mut[Primitive]diplomat::span<Primitive>
&str or &DiplomatStr or DiplomatStrSlice or DiplomatUtf8StrSlicestd::string_view
&DiplomatStr16 or DiplomatStr16Slicestd::u16string_view
&[&str] or &[DiplomatStrSlice] or &[DiplomatUtf8StrSlice]diplomat::span<diplomat::string_view_for_slice>
&[DiplomatStr16Slice]diplomat::span<diplomat::u16string_view_for_slice>

diplomat::span

All slices are stored in the diplomat::span struct. For C++17, this is the std::span struct. Otherwise, it is implemented in diplomat with the following rough structure:

constexpr size_t dynamic_extent = std::numeric_limits<std::size_t>::max();
template <class T, std::size_t Extent = dynamic_extent>
class span {
    private:
    T* data;
    size_t size;
};

With helper method for constructing diplomat::span from arrays and pointers to sized data.

DiplomatWrite

C++ will return std::string for DiplomatWrite functions. The function

pub fn to_string(w : &mut DiplomatWrite);

Becomes

inline std::string to_string() const;
// and
template<typename W>
inline void somelib::Float64Vec::to_string_write(W& writeable) const;

Where W implements WriteTrait:

// This "trait" allows one to use _write() methods to efficiently
// write to a custom string type. To do this you need to write a specialized
// `WriteTrait<YourType>` (see WriteTrait<std::string> below)
// that is capable of constructing a DiplomatWrite, which can wrap
// your string type with appropriate resize/flush functionality.
template<typename T> struct WriteTrait {
  // Fill in this method on a specialization to implement this trait
  // static inline capi::DiplomatWrite Construct(T& t);
};

If you use WriteTrait, you will be interfacing with the C ABI of DiplomatWrite.

Callbacks

Callbacks are represented as std::function<Ret(Args...)>, where Ret and Args... are diplomat-friendly C++ types. These work just like any other C++ callback function and are converted in to the C ABI with some templating.

Struct References

&mut Struct

Any structure tagged with #[diplomat::attr(auto, mut_struct_ref)] will be codegenned with different fields than you might expect. Currently, this only holds for structures that hold references:

#[diplomat::bridge]
mod ffi {
    pub struct SomeStruct {
        a : &Opaque,
    }

    impl SomeStruct {
        pub fn takes_mut(&mut self);
    }
}
Immutable Behavior

In normal C++ codegen, this will look like:

struct SomeStruct {
    const Opaque& a;
};

Note that this is struct is currently not considered ABI compatible, so we cannot pass it directly as a pointer. Instead, we must convert it into an ABI-compatible struct:

struct SomeStructCFriendly {
    const Opaque* a;
};

Which we then copy over after converting:

SomeStructCFriendly* ffiFriendly = this->AsFFI();
// Call the Rust function:
SomeStruct_takes_mut(ffiFriendly);
// ffiFriendly has now been mutated, we must clone its values:
*this = SomeStruct::FromFFI(ffiFriendly);
// This will not compile.

C++ does not support “reseating” references, or changing the underlying pointer they access.

Mutable Behavior

To ensure our structure is “mutable” on a clone, each reference to an opaque must be stored as a pointer. So any structure tagged with #[diplomat::attr(auto, mut_struct_ref)] will replace its references with pointers:

struct SomeStruct {
    Opaque* a;
};

Supports

  • Namespaces

  • Memory Sharing

  • Non Exhaustive Structs

  • Method Overloading

  • UTF8 Strings

  • UTF16 Strings

  • Static Slices

  • Defaults

  • Constructors

  • Named Constructors

  • Fallible Constructors

  • Getters/Setters

  • Static Getters/Setters

  • Stringifiers

  • Comparators

  • Iterators

  • Iterables

  • Indexers

  • Arithmetic

  • Options

  • Callbacks

  • Traits

  • Custom Errors

  • Traits are Send

  • Traits are Sync

  • Generate Mocking Interface

  • ABI Compatible Structs

  • Struct References. See References for more.

  • Mutable Struct References. See References for more.

  • Free Functions

  • Custom Bindings

  • Owned Slices

  • Default Arguments

  • Mutable Slices (&mut [T])