Margareth Reena
Margareth Reena

Reputation: 1430

Keeping a struct implementation generic but calling specific implementations

I'm trying to be generic on C's implementation, but use individual implementations of div_array for its member T. For example, C::something(&self) should use the correct implementation for the array [T; 2]. Since T: A, only 2 possible T can exist: T=u32, T=u64, so I implemented DivArray for [u32;2] and [u64;2] only. While I could do a generic implementation, I really want it to be specific on each array implementation because it could use some hardware operations only available for some types, etc.

use core::marker::PhantomData;
use num_traits::Zero;

pub trait A: Zero + Copy {}

impl A for u32{}
impl A for u64{}

pub trait DivArray<'a, Rhs>: Sized + Copy {
    type Output;
    fn div_array(
        self,
        denominator: Rhs,
    ) -> Result<Self::Output, ()>;
}
    
impl<'a, Rhs: Into<Rhs>> DivArray<'a, Rhs> for [u32; 2] {
    type Output = [u32; 2];
    fn div_array(
        self,
        denominator: Rhs,
    ) -> Result<Self::Output, ()> {
        unimplemented!();
    }
}

impl<'a, Rhs: Into<Rhs>> DivArray<'a, Rhs> for [u64; 2] {
    type Output = [u64; 2];
    fn div_array(
        self,
        denominator: Rhs,
    ) -> Result<Self::Output, ()> {
        unimplemented!();
    }
}

pub struct C<T>{
    _phantom: PhantomData<T>
}

impl<T: A> C<T>{
    pub fn something(&self) {
        let arr = [T::zero(); 2];
        arr.div_array(1u64);
    }
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=60694183a787b70e210a4612747a622c

error[E0599]: no method named `div_array` found for array `[T; 2]` in the current scope
  --> src/lib.rs:44:13
   |
44 |         arr.div_array(1u64);
   |             ^^^^^^^^^ method not found in `[T; 2]`
   |
   = help: items from traits can only be used if the trait is implemented and in scope
note: `DivArray` defines an item `div_array`, perhaps you need to implement it
  --> src/lib.rs:9:1
   |
9  | pub trait DivArray<'a, Rhs>: Sized + Copy {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

What is happening here? I clearly implemented DivArray for all T such that T:A

Upvotes: 1

Views: 123

Answers (1)

Masklinn
Masklinn

Reputation: 42472

What is happening here?

Traits are not "completable" so there's no such thing as "implementing for all T: A".

Not that the compiler would care because it doesn't check: Rust typechecks generic methods as-is, before any sort of expansion, so the information it has is that that arr: [T;2], and it needs an impl DivArray for that.

However all this mess seems completely unnecessary here, you can just implement your stuff for both types, possibly using a macro if you turn out to have more than two:

impl C<u32>{
    pub fn something(&self) {
        let arr = [0; 2];
        arr.div_array(1u64);
    }
}
impl C<u64>{
    pub fn something(&self) {
        let arr = [0; 2];
        arr.div_array(1u64);
    }
}

Though note that this will prevent a generic implementation: in the fulness of time an option might be specialisation (for both the original version and this one), but it's nowhere near done because it's full of unresolved soundness issues.

Upvotes: 1

Related Questions