Achieve generic field access api without `min_specialization`

Hello, do you have any ideas how to replicate api used in main, but without min_specialization?

#![feature(min_specialization)]

trait FieldAccess<T> {
    fn get_ref_(&self) -> Option<&T>;
    fn get_mut_(&mut self) -> Option<&mut T>;
}

impl<A, T> FieldAccess<T> for A {
    default fn get_ref_(&self) -> Option<&T> {
        None
    }
    default fn get_mut_(&mut self) -> Option<&mut T> {
        None
    }
}

trait Device {
    fn get_ref<T>(&self) -> Option<&T>
    where
        Self: FieldAccess<T>,
    {
        <Self as FieldAccess<T>>::get_ref_(self)
    }
    fn get_mut<T>(&mut self) -> Option<&mut T>
    where
        Self: FieldAccess<T>,
    {
        <Self as FieldAccess<T>>::get_mut_(self)
    }
}

#[derive(Debug, Clone, Copy)]
struct A;
#[derive(Debug, Clone, Copy)]
struct B;
#[derive(Debug, Clone, Copy)]
struct C;

#[derive(Debug, Clone, Copy)]
struct Foo(A, B);
#[derive(Debug, Clone, Copy)]
struct Bar(A, C);

impl Device for Foo {}
impl Device for Bar {}

impl FieldAccess<A> for Foo {
    fn get_ref_(&self) -> Option<&A> {
        Some(&self.0)
    }
    fn get_mut_(&mut self) -> Option<&mut A> {
        Some(&mut self.0)
    }
}
impl FieldAccess<B> for Foo {
    fn get_ref_(&self) -> Option<&B> {
        Some(&self.1)
    }
    fn get_mut_(&mut self) -> Option<&mut B> {
        Some(&mut self.1)
    }
}

impl FieldAccess<A> for Bar {
    fn get_ref_(&self) -> Option<&A> {
        Some(&self.0)
    }
    fn get_mut_(&mut self) -> Option<&mut A> {
        Some(&mut self.0)
    }
}
impl FieldAccess<C> for Bar {
    fn get_ref_(&self) -> Option<&C> {
        Some(&self.1)
    }
    fn get_mut_(&mut self) -> Option<&mut C> {
        Some(&mut self.1)
    }
}

fn main() {
    let mut foo = Foo(A, B);
    let mut bar = Bar(A, C);

    println!("{:?}", foo.get_ref::<A>());
    println!("{:?}", foo.get_mut::<B>());
    println!("{:?}", foo.get_ref::<C>());
    println!("{:?}", bar.get_ref::<A>());
    println!("{:?}", bar.get_ref::<B>());
    println!("{:?}", bar.get_ref::<C>());
}

Output:

Some(A)
Some(B)
None
Some(A)
None
Some(C)

I see Tracking Issue for `error_generic_member_access` · Issue #99301 · rust-lang/rust · GitHub that uses a stable technique with dynamic any magic, but for my case I do not need dyn access. Is there a way to have it using type system?

I also can manually implement FieldAccess manually for all devices with all "components", but it feels very unproductive.

Not great, but if Any is an acceptable limitation.

1 Like

Disassembly shows that there is no cost, so it is a solution for me. Thank you!