dtolnay / cxx

Safe interop between Rust and C++
https://cxx.rs
Apache License 2.0
5.68k stars 320 forks source link

Is it possible to mark a C++ type as `Trivial`? #1332

Closed metasim closed 3 months ago

metasim commented 3 months ago

I have a situation where there's a fairly complex C++ enum (below) I wish to be able to return to Rust as Opaque, but by value. IOW, I'd like to mark the type as cxx::kind::Trivial, but don't want a) to duplicate the definition as a shared type, or b) wrap it in a UniquePtr. Is this at all possible with the current cxx?

enum class Type

enum class Type
{
    None = 0,
    Unsigned8 = unsigned(BaseType::Unsigned) | 1,
    Signed8 = unsigned(BaseType::Signed) | 1,
    Unsigned16 = unsigned(BaseType::Unsigned) | 2,
    Signed16 = unsigned(BaseType::Signed) | 2,
    Unsigned32 = unsigned(BaseType::Unsigned) | 4,
    Signed32 = unsigned(BaseType::Signed) | 4,
    Unsigned64 = unsigned(BaseType::Unsigned) | 8,
    Signed64 = unsigned(BaseType::Signed) | 8,
    Float = unsigned(BaseType::Floating) | 4,
    Double = unsigned(BaseType::Floating) | 8
};

dtolnay commented 3 months ago

Yep, something like this should work:

#[cxx::bridge]
mod ffi {
    unsafe extern "C++" {
        include!("example/include/metasim.h");

        type Type = crate::Type;
        fn metasim() -> Type;
    }
}

#[derive(Debug)]
#[repr(transparent)]
pub struct Type(std::ffi::c_int);

unsafe impl cxx::ExternType for Type {
    type Kind = cxx::kind::Trivial;
    type Id = cxx::type_id!("Type");
}

fn main() {
    println!("{:?}", ffi::metasim());
}
metasim commented 3 months ago

Wow! Perfect... and simple! Thank you 🙏