Is it possible convert &T to &Wrapper<T> when Wrapper is marked #[repr(transparent)]?

Suppose we have

#[repr(transparent)]
struct Wrapper<T>(T);

We could easily convert T to Wrapper<T> and Wrapper<T> to T

but if we have a &T or &mut T, things become different: we could only convert &Wrapper<T> to &T, but we could not easily convert &T into &Wrapper<T>

Is there any solution?
Or, we must use some really unsafe function like transmute?

The converts I've found:

trait SayMyName {
    fn name(self);
}
impl<T> SayMyName for T {
    fn name(self) {
        let s:String=std::any::type_name::<T>().into();
        println!("{}",s)
    }
}
#[repr(transparent)]
#[derive(Copy,Clone)]
struct Wrapper<T>(T);
fn main(){
    type T=i32;
    let mut t:T=1;
    let mut wrapper_t=Wrapper(t);
    t.name();
    wrapper_t.name();
    Wrapper(t).name();//T->Wrapper<T>
    wrapper_t.0.name();//Wrapper<T>->T
    (&t).name();
    (&wrapper_t).name();
    (Wrapper(&t)).name();// not &T->&Wrapper<T>, what is the solution?
    (&wrapper_t.0).name();// &Wrapper<T>->&T
    (Wrapper(&mut t)).name();// not &mut T->&mut Wrapper<T>, what is the solution?
    (&mut wrapper_t.0).name();// &Wrapper<T>->&T
}

Is it possible impl such converts?

Neat example of such convert:

Such converts may help writing specialization by adding extra wrappers:

struct Wrapper<const SEQ:usize,T>(T);
impl<T> Spec for Wrapper<0,T>{fn spec(...)...}
impl<T> Spec for Wrapper<1,T> where Wrapper<0,T>:Spec{default fn spec(...)...}
impl<T> Spec for Wrapper<1,T> where T:/*write down more specific items here.*/{fn spec(...)...}
...
impl<T> Spec for Wrapper<100,T> where Wrapper<99,T>:Spec{default fn spec(...)...}
//suppose we have already written all the specializations.
impl<T> Spec for T where T:Wrapper<100,T>{
    fn spec(&self){
        &Wrapper(*self).spec()//will find the maximum SEQ that impl Spec for Wrapper<SEQ,T>
    }
}

Yes, it's possible. You can do it like this:

#[repr(transparent)]
struct Wrapper<T>(T);

impl<T> Wrapper<T> {
    fn from_ref(r: &T) -> &Wrapper<T> {
        unsafe {
            &*(r as *const T as *const Wrapper<T>)
        }
    }
}

You can't avoid the unsafe.

2 Likes

Is such API worth a rfc discussion in IRLO?

I cannot find any reason that such code should be unsafe.

What's more, a bare unsafe code may sometimes scare for some rustaceans.

It could be worth thinking about a safe way to provide the operation.

2 Likes

well..

you're right.

A safe way exists in my neat example:

#![feature(min_specialization)]
use std::fmt::Debug;
struct Spec<T:Debug,U:Debug>(T,U);
impl<T:Debug,U:Debug> Spec<T,U>{
    fn byref(&self){println!("(T={:?},U={:?}),byref",self.0,self.1)}
    fn bymut(&mut self){println!("(T={:?},U={:?}),bymut",self.0,self.1)}
    fn bytake(self)->(T,U){println!("(T={:?},U={:?}),take and drop",self.0,self.1);(self.0,self.1)}
}
#[repr(transparent)]
struct Wrapper<const SEQ:usize,T>(T);
trait SpecSpec<T,U>{
    fn show_spec();
    fn ref_spec(&self){}
    fn mut_spec(&mut self){}
    fn take_spec(self)->(T,U) where Self: Sized{unimplemented!("We must implement take for every specific type.")}
}
trait WrapperSpec<T,U> where Self: Sized{
    fn show_spec(){}
    fn ref_spec(self){}
    fn mut_spec(mut self){}
    fn take_spec(self)->(T,U){unimplemented!("We must implement take for every specific type.")}
}
// first default level, could be overwrite.
impl<T:Debug,U:Debug> WrapperSpec<T,U> for Wrapper<0,Spec<T,U>>{
    fn show_spec(){println!("neither T({}) nor U({}) is the specialization version",std::any::type_name::<T>(),std::any::type_name::<U>())}
    fn take_spec(self)->(T,U){self.0.bytake()}
}
impl<T:Debug,U:Debug> WrapperSpec<T,U> for Wrapper<0,&Spec<T,U>>{
    fn ref_spec(self)where Self: Sized{self.0.byref()}
}
impl<T:Debug,U:Debug> WrapperSpec<T,U> for Wrapper<0,&mut Spec<T,U>>{
    fn mut_spec(mut self)where Self: Sized{self.0.bymut()}
}
// second default level, using default impl to enable the further modification.
impl<T:Debug,U:Debug,G> WrapperSpec<T,U> for Wrapper<1,G> where Wrapper<0,G>:WrapperSpec<T,U>{
    default fn show_spec(){Wrapper::<0,G>::show_spec()}
    default fn ref_spec(self){Wrapper::<0,G>::ref_spec(Wrapper(self.0))}
    default fn mut_spec(mut self){Wrapper::<0,G>::mut_spec(Wrapper(self.0))}
    default fn take_spec(self)->(T,U){Wrapper::<0,G>::take_spec(Wrapper(self.0))}
}
impl<U:Debug,G> WrapperSpec<i16,U> for Wrapper<1,G> where Wrapper<0,G>:WrapperSpec<i16,U>{
    fn show_spec(){println!("T({}) is the specialization version, but U({}) is not.",std::any::type_name::<i16>(),std::any::type_name::<U>())}
}


// second default level, using default impl to enable the further modification.
impl<T:Debug,U:Debug,G> WrapperSpec<T,U> for Wrapper<2,G> where Wrapper<1,G>:WrapperSpec<T,U>{
    default fn show_spec(){Wrapper::<1,G>::show_spec()}
    default fn ref_spec(self){Wrapper::<1,G>::ref_spec(Wrapper(self.0))}
    default fn mut_spec(mut self){Wrapper::<1,G>::mut_spec(Wrapper(self.0))}
    default fn take_spec(self)->(T,U){Wrapper::<1,G>::take_spec(Wrapper(self.0))}
}
impl<T:Debug,G> WrapperSpec<T,i32> for Wrapper<2,G> where Wrapper<1,G>:WrapperSpec<T,i32>{
    fn show_spec(){println!("U({}) is the specialization version, but T({}) is not.",std::any::type_name::<i32>(),std::any::type_name::<T>())}
} // no conflict here, even if we do not provide a SpecSpec<i16,i32> type.


// second default level, using default impl to enable the further modification.
impl<T:Debug,U:Debug,G> WrapperSpec<T,U> for Wrapper<3,G> where Wrapper<2,G>:WrapperSpec<T,U>{
    default fn show_spec(){Wrapper::<2,G>::show_spec()}
    default fn ref_spec(self){Wrapper::<2,G>::ref_spec(Wrapper(self.0))}
    default fn mut_spec(mut self){Wrapper::<2,G>::mut_spec(Wrapper(self.0))}
    default fn take_spec(self)->(T,U){Wrapper::<2,G>::take_spec(Wrapper(self.0))}
}
impl<G> WrapperSpec<i16,i32> for Wrapper<3,G> where Wrapper<2,G>:WrapperSpec<i16,i32>{
    fn show_spec(){println!("both T and U have a specialization version, we need to specific them.")}
} // no conflict here, even if we do not provide a SpecSpec<i16,i32> type.

// second default level, using default impl to enable the further modification.
impl<T:Debug,U:Debug,G> WrapperSpec<T,U> for Wrapper<4,G> where Wrapper<3,G>:WrapperSpec<T,U>{
    default fn show_spec(){Wrapper::<3,G>::show_spec()}
    default fn ref_spec(self){Wrapper::<3,G>::ref_spec(Wrapper(self.0))}
    default fn mut_spec(mut self){Wrapper::<3,G>::mut_spec(Wrapper(self.0))}
    default fn take_spec(self)->(T,U){Wrapper::<3,G>::take_spec(Wrapper(self.0))}
}
impl<G> WrapperSpec<i32,i16> for Wrapper<4,G> where Wrapper<3,G>:WrapperSpec<i32,i16>{
    fn show_spec(){println!("Although there is no specialization version, but we do concern about that.")}
}
impl<T:Debug,U:Debug> SpecSpec<T,U> for Spec<T,U> where Wrapper<4,Spec<T,U>>:WrapperSpec<T,U>{
    fn show_spec(){<Wrapper<4,Spec<T,U>>>::show_spec()}
    fn ref_spec(&self){<Wrapper<4,&Spec<T,U>>>::ref_spec(Wrapper(self))}
    fn mut_spec(&mut self){<Wrapper<4,&mut Spec<T,U>>>::mut_spec(Wrapper(self))}
    fn take_spec(self)->(T,U){<Wrapper<4,Spec<T,U>>>::take_spec(Wrapper(self))}
}
impl<T:Debug,U:Debug> Spec<T,U> where Spec<T,U>:SpecSpec<T,U>{
    fn check(mut self){
        Spec::<T,U>::show_spec();
        self.ref_spec();
        self.mut_spec();
        println!("  take returns {:?}",self.take_spec());
    }
}
fn main(){
    Spec(1i8,2i8).check();
    Spec(3i16,4i8).check();
    Spec(5i8,6i32).check();
    Spec(7i16,8i32).check();
    Spec(9i32,10i16).check();
}

Do you have a question regarding that code? I'm not going to read it otherwise — it's quite long and dense.

1 Like

I have no question since "we already have a safe solution".

Thank you for your suggestion.

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.