getditto/safer_ffi

Using generics in struct does not create separate monomorphized types

TheButlah opened this issue · 2 comments

I have a function that returns a repr_c::Box<MyOpaqueType<AnotherOpaqueType>>. It is generating on the C side as a * MyOpaqueType. instead of a MyOpaqueType_AnotherOpaqueType. This dilutes the type safety on the C side and makes it easier to accidentally cast a MyOpaqueType<A> to a MyOpaqueType<B>.

Thanks for reporting this, this is indeed a limitation of safer-ffi's design: we can't really know how to stringify the generic parameters (in the non-opaque case, we get away thanks to the recursive ReprC obligation on the generic parameters, which is the one providing the stringified sub name (the short_name, for those curious about the internals)).

A way to palliate the issue, which I've used in some cases, is to use the undocumented1 rename feature of ReprC::opaque:

#[derive_ReprC]
#[ReprC::opaque(format!(
    "Foo_{}",
    ::std::any::type_name::<T>()
        .splitn(2, "<")
        .next().unwrap()
        .rsplitn(2, ":")
        .next().unwrap()
))]
struct Foo<T> { /* … */ }

it's not pretty, but at the time I did not want to provide this as a default implementation, thence hiding nested collisions.


In the near future

I now think that such implementation, especially if recursing into the generic parameters, is not that bad, and definitely better than just disregarding the type parameters in the name.

Thus, as part of the incoming cleanup and refactoring of safer-ffi, such an implementation will be available by default, thence fixing this very issue 🙂

Footnotes

  1. an oversight, I guess

This was fixed as of #97 (to be released to crates.io)