Invoking generic function with similar trait bounds

I'm not really sure quite how to phrase this question...

I am using Arrow which implements the ArrowNativeType trait for u8, u16, etc.
I am also using another Rust crate that implements OtherNativeType for u8, u16, etc. In fact, an identical set of types.

Is it possible to write a function that is generic over OtherNativeType, and somehow perform the dispatch over ArrowNativeType? Since I cannot add a OtherNativeType: ArrowNativeType bound.

Perhaps this playground will help: Rust Playground

[edit] I realise I can add the bound O: OtherNativeType + ArrowNativeType, but is it possible without doing this? For instance, can I enumerate all known u8, u32, etc and dispatch that way?

The hint in the compiler error has the solution.

-fn some_function<O: OtherNativeType>() -> Vec<O> {
+fn some_function<O: OtherNativeType + ArrowNativeType>() -> Vec<O> {

The updated bound means O must implement both traits.

I forgot to mention in the original question, I'm aware I can add the bound like this. But I'd like to keep ArrowNativeType out of the API interface entirely. This also precludes defining a new trait MyNativeType: OtherNativeType + ArrowNativeType.

Is there a way to dispatch over types and invoke the corresponding ArrowNativeType implementation?

You can do that without the supertrait bound, hide the arrow functionality behind methods of your trait, and then implement it for concrete types instead of using a generic implementation. Then ArrowNativeType won't show up as a supertrait bound or requirement of the blanket implementation.

You could maybe do some MyTrait: Any + AsAny shenanigans that allow you to upcast Sized implementors of your trait into &dyn Any or Box<dyn Any> or whatnot and then attempt downcasting to concrete types you know implement ArrowNativeType, conditionally making use of the arrow trait that way, but I think it's a pretty bad idea.

I'd still like to expose a function that is generic over OtherNativeType though. I'm happy to use macros / implement something for concrete types, but AFAIK I couldn't then invoke it generically over OtherNativeType. Is there some way to create an associated type for the third-party OtherNativeType?

More concretely, a minimal reproduction would be this:

// Arrow
impl ArrowBuffer {
   pub fn typed_data<A: ArrowNativeType>(&self) -> &[A] { ... }
}

// Not Arrow
struct MyBuffer(ArrowBuffer);

impl MyBuffer {
  // How do I implement this function without exposing the Arrow internals?
  pub fn typed_data<O: OtherNativeType>(&self) -> &[O] {
    self.0.typed_data::<?>()
  }
}

Here's one possibility (but I may still not be understanding all the goals).

If I'm reading this correctly, this is what you have:

  • You need to make a function that matches the signature fn o<O: OtherNativeType>() -> Vec<O>
  • You need that function to call fn a<A: ArrowNativeType>() -> Vec<A>
  • The two traits are currently implemented for the same types

First of all, make sure this is absolutely necessary. Check if arrow or the other crate have one another as an optional dependency, because they might have interoperability already.

Otherwise, I don't think you can do it exactly, but if you add 'static, you can use unsafe to make it work Rust Playground

pub fn some_function<O: OtherNativeType + 'static>() -> Vec<O> {
    fn of<T: ?Sized + 'static>() -> core::any::TypeId {
        core::any::TypeId::of::<T>()
    }

    unsafe fn transmute_vec<T, O>(v: Vec<T>) -> Vec<O> {
        let mut v = std::mem::ManuallyDrop::new(v);
        unsafe { Vec::from_raw_parts(v.as_mut_ptr() as *mut O, v.len(), v.capacity()) }
    }

    unsafe {
        match of::<O>() {
            id if id == of::<u8>() => transmute_vec(arrow_buffer::<u8>()),
            id if id == of::<u32>() => transmute_vec(arrow_buffer::<u32>()),
            _ => unimplemented!(),
        }
    }
}

I'd need to know what the actual traits are to help further.

(Doing this without unsafe is...)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.