dtolnay / cxx

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

Extern C++ Enums #1340

Closed djlalo08 closed 2 months ago

djlalo08 commented 2 months ago

Is it possible to use an extern C++ enum to call extern C++ function?

//colors.cpp
enum Color {red, blue};

void printColor(Color c){
    std::cout << c << std::endl;
}

I'm imagining something like this:

//main.rs
#[cxx::bridge]
mod ffi {
    extern unsafe "C++" {
        type Color;
        fn printColor(c: Color);
    }
}

fn main(){
    ffi::printColor(ffi::Color::red);
}
dtolnay commented 2 months ago

Yes, this is equivalent to https://github.com/dtolnay/cxx/issues/1332. You need to provide an ABI-compatible Rust definition of the type using ExternType.

djlalo08 commented 2 months ago

Ah, I actually came across that issue in my search, but that example was going in the other direction (call a function that returns an enum, rather than takes one). I was able to replicate #1332 but haven't been able to to pass in an extern enum -- after Your response, my guess is I've just made a mistake somewhere...

In any case, thanks for responding, and for developing this awesome crate!

mystchonky commented 1 month ago

@djlalo08 did you figure out how to do this ?

haven't been able to to pass in an extern enum -- after Your response, my guess is I've just made a mistake somewhere...

djlalo08 commented 1 month ago

Yes! Here's an example:

//src/enums.rs

//This is the C++ enum. The repr part means it's effectively being treated as an integer (corresponding to the enum variant)
#[repr(transparent)]
pub struct MyEnum(pub std::ffi::c_int);
unsafe impl cxx::ExternType for MyEnum {
    type Kind = cxx::kind::Trivial;
    type Id = cxx::type_id("MyEnum");
}

//This is a regular rust enum You can use in Rust code
pub enum MyEnumR { 
    Variant1,
    Variant2,
    Variant3
}

//lib.rs
mod enums;

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

        type MyEnum = crate::enums::MyEnum;

        fn setEnum(e: MyEnum);
    }
}

pub fn do_stuff(e_r: MyEnumR) {
    let e_cpp = MyEnum(e_r as i32);
    ffi::setEnum(e_cpp);
}
djlalo08 commented 1 month ago

@mystchonky This is an example based off what ultimately worked for me, but I've forgotten some of the finer points on how it works by now. This example is an untested simplification of my actual full program, so if this doesn't work, let me know and I can fix the example.