Skip to content

ExternTypes may be safely passed and returned by value #313

@adetaylor

Description

@adetaylor
        unsafe impl cxx::ExternType for bindgen::Bob {
            type Id = cxx::type_id!("Bob");
        }
        mod bindgen {
            #[repr(C)]
            pub struct Bob {
                pub a: u32,
                pub b: u32,
            }
        }
        #[cxx::bridge]
        pub mod cxxbridge {
            extern "C" {
                include!("input.h");
                pub fn give_bob() -> Bob;
                type Bob = super::bindgen::Bob;
            }
        }

doesn't work because we can't return ExternTypes by value.

Each extern type may be one of three fundamental categories of type:

  • An alias to another cxx::bridge type (in which case it's a simple alias and we don't do anything in the current instantiation)
  • A type which is_trivially_move_constructible && is_trivially_destructible. If so, we allow allow it to be passed by value into/our of cxx types, and we check this with static_asserts as discussed in Provide builtin handling of exposing a C++ constructor #280. ("trivial" types for short henceforth)
  • A type which isn't trivially move constructable/destructable. In these cases we don't allow use by value but we do allow generation of UniquePtr traits etc. as per Trait impls needed for type aliases #312.

This distinction is implied by #280 but this could be done as a pre-requisite step first. I also feel it would be desirable to pin this down before finalizing design for #312.

The question is, for a given ExternType, how does cxx know which of these three categories of type it is? What's your plan there? Is it to require the developer to implement an extra trait for trivial types which is then checked for safety using static_assert? Or did you plan to do something funky to auto-detect trivial types at build time?

(NB for this last category of types, my higher-level code generator plans to create shims which allow us to call pre-existing C++ APIs that take a T by instead passing a UniquePtr<T>. I have yet to do this bit. It makes superficial sense that "complicated" types need to be entirely allocated, accessed, and managed within C++ but can still be owned by Rust. Figuring out whether this is ergonomic in practice is arguably the entire point of my https://github.com/google/autocxx experiments... if this doesn't work out it's back to the drawing board!)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions