dtolnay / cxx

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

Adding helper methods to `cxx_gen` for higher level code generators #1144

Open ahayzen-kdab opened 1 year ago

ahayzen-kdab commented 1 year ago

I couldn't see this discussed before (?), sorry if it has been.

Would it be accepted to add some helper methods to cxx_gen (or elsewhere?) for higher level code generators ? (If such methods would be accepted I would be happy to help contribute code to do this.)

In CXX-Qt we have a few places where it'd be useful for reuse some of the code from CXX itself rather than our fragile reimplementation of things, and other code generators using CXX may find this useful (eg maybe autocxx?). Furthermore this prevents breakage if CXX changes what it generates or adds support for more types.

Some of the possible scenarios we have come across so far that would be useful (note that API are just examples and could be different).

Retrieving the C++ name for a Rust type

This is useful when we are generating extra C++ code for Rust CXX bridges and need to match the type names for parameters or return types.

For a given syn::Type or syn::ReturnType it would be useful if there was a cxx_gen method to retrieve the corresponding C++ type name.

Note that this would also have to consider any namespaces and cxx_name attributes from the bridge.

For example with the following extern C++ block

#[namespace = "my_namespace"]
unsafe extern "C++" {
  #[cxx_name = "B"]
  type A;
}

If A is used as a type within a method, we need to have generation code to go from A to ::my_namespace::B. (and any other conversions need to occur like for UniquePtr or function pointers etc).

Would something like the following in cxx_gen be accepted?

pub fn syn_type_to_cxx_type(ty: &syn::Type, cxx_name_map: &BTreeMap<String, String>, namespace_map: &BTreeMap<String, String>) -> String {
    // calculates ::my_namespace::B from
    //  - reads syn::Type A
    //  - cxx_name_map with A -> B
    //  - namespace_map of A -> my_namespace
}

There would also likely need to be a similar method for syn::ReturnType as Result<T> can be used just in returns from my understanding (?).

Determining if the type is unsafe for CXX bridges

If certain types are used in CXX bridge functions the method needs to be marked as unsafe, eg if you use *mut T. Being able to determine by asking CXX which of it's supported types are unsafe would be much better than having to chase any new types.

Would something like the following in cxx_gen be accepted?

pub fn syn_type_is_cxx_bridge_unsafe(ty: &syn::Type) -> bool {
   // determine if syn::Type is unsafe
}

Retrieving the C++ bridge method name for a Rust method

In more advanced cases we need to friend the CXX bridge method (this is so that we can call protected methods from a C++ base class from Rust) it would be good if there was a helper to provide us the method name.

For example with the following CXX block

#[namespace = "my_namespace"]
unsafe extern "C++" {
    #[cxx_name = "B"]
    type A;
    fn method(self: &A);
}

CXX generates internal method names such as my_namespace$cxxbridge1$B$method.

Would something like the following in cxx_gen be accepted?

pub fn method_to_cxx_bridge_function_name(method: &syn::Ident, self_ty: Option<&syn::Type>, cxx_name_map: &BTreeMap<String, String>, namespace_map: &BTreeMap<String, String>) -> String {
    // calculates my_namespace$cxxbridge1$B$method from
    //  - reads the method ident "method"
    //  - reads the syn::Type Some(&A)
    //  - cxx_name_map with A -> B
    //  - namespace_map of method -> my_namespace
}
dtolnay commented 1 year ago

I would prefer not to build things like this into the cxx-gen crate for now. I'd recommend putting the things you'd like to see added into a separate crate, and if that crate ends up being useful to any other code generator tools, I can look into which of the functionality to pick up in cxx-gen.

ahayzen-kdab commented 1 year ago

Sure :-) We just wanted to check if it was worth pushing anything into cxx_gen so it could be like a library to other code generators. As we add support for parts of these we'll see if it's worth splitting these into our own utils crate or something.