Option types

Option types in Diplomat are relatively straightforward, you simply use Option<T> and it turns into the idiomatic equivalent over FFI.

Option<T> currently only works when wrapping reference types (Box<OpaqueType> and &OpaqueType), wrapping structs/enums/primitives, or in return type position:

#![allow(unused)]
fn main() {
#[diplomat::bridge]
mod ffi {
    // just exists so we can get methods
    #[diplomat::opaque]
    pub struct Thingy;

    impl Thingy {
        pub fn maybe_create() -> Option<Box<Thingy>> {
            Some(Box::new(Thingy))
        }

        pub fn increment_option(x: Option<u8>) -> Option<u8> {
            x.map(|inner| inner + 1)
        }
    }
}
}

In C++ maybe_create will return a std::optional<std::unique_ptr<Thingy>>, and in JS it will return a potentially-null object.

make_option will have similar behavior, returning std::optional<uint8_t> and an integer-or-null in JS. It will accept std::optional<uint8_t> in C++ and null-check the parameter in JS.

DiplomatOption

Option<T> is FFI-safe for reference types but not for other arbitrary types. When used in function parameters, Diplomat will automatically use FFI-safe types over the boundary, however with structs layout concerns prevent automatically doing this. Instead, if you wish to use an Option<T> in a struct (for struct, enum, or primitive T), use DiplomatOption<T>

#![allow(unused)]
fn main() {
#[diplomat::bridge]
mod ffi {
    use diplomat_runtime::DiplomatOption;

    #[diplomat::opaque]
    pub struct MyOpaque(u8);

    pub enum MyEnum {
        Foo, Bar
    }

    pub struct MyStruct<'a> {
        a: DiplomatOption<u8>,
        b: DiplomatOption<MyEnum>,
        c: Option<&'a MyOpaque>
    }
}
}