Hi, I have a following problem, I need to implement the trait IsType for the Wrapper structure. But I was unable to implement the from_ref and from_mut functions. At this point I am not even sure if it's possible to do. Any suggestions, including unsafe Rust are welcomed. Also the OriginalStruct and IsType cannot be altered. The Wrapper structure can be altered in any way possible, the main constraint, is that it has to implement the IsType trait.
// the following structure and trait cannot be altered
#[derive(Clone)]
struct OriginalStructure {
pub data: u32,
}
trait IsType<T> {
fn from_ref(t: &T) -> &Self;
fn into_ref(&self) -> &T;
fn from_mut(t: &mut T) -> &mut Self;
fn into_mut(&mut self) -> &mut T;
}
// This is the wrapper, which can be changed.
// It must implement the IsType trait
#[derive(Clone)]
struct Wrapper(pub *mut OriginalStructure);
impl Wrapper {
pub fn wrap(orig: OriginalStructure) -> Self {
let orig = Box::into_raw(Box::new(orig));
Self(orig)
}
}
impl IsType<OriginalStructure> for Wrapper {
fn from_ref(t: &OriginalStructure) -> &Self {
todo!()
}
fn into_ref(&self) -> &OriginalStructure {
todo!()
}
fn from_mut(t: &mut OriginalStructure) -> &mut Self {
todo!()
}
fn into_mut(&mut self) -> &mut OriginalStructure {
todo!()
}
}
The signature of IsType::from_ref and IsType::from_mut methods won't allow you to return a Wrapper from a &[mut] OriginalStructure. You have to create a new instance of Wrapper inside of these functions. But you can't return a reference to function-local data, as it is dropped at the end of the function, making the returned references immediately dangling.
I am not sure what you mean by that, since this code is accepted by the compiler without any errors. These 2 functions that you specified are not a problem at all, since a simple change to the Wrapper structure and the self will have the same lifetime with the returned value, I believe, I am having a problem with the from_ref and from_mut. Also, maybe I didn't make it clear enough, but the Wrapper structure can be changed in any way, the main part is that it has to implement the IsType trait
// the following structure and trait cannot be altered
#[derive(Clone)]
struct OriginalStructure {
pub data: u32,
}
trait IsType<T> {
fn from_ref(t: &T) -> &Self;
fn into_ref(&self) -> &T;
fn from_mut(t: &mut T) -> &mut Self;
fn into_mut(&mut self) -> &mut T;
}
// This is the wrapper, which can be changed.
// It must implement the IsType trait
#[derive(Clone)]
struct Wrapper(pub OriginalStructure);
impl IsType<OriginalStructure> for Wrapper {
fn from_ref(t: &OriginalStructure) -> &Self {
todo!()
}
fn into_ref(&self) -> &OriginalStructure {
&self.0
}
fn from_mut(t: &mut OriginalStructure) -> &mut Self {
todo!()
}
fn into_mut(&mut self) -> &mut OriginalStructure {
&mut self.0
}
}
My bad, I meant from_ref and from_mut, not into_ref and into_mut. Amended the post above. You can only return &[mut] Self from a function that takes &[mut] T as its only argument, if Self is part of T and we can return a partial reborrow from T. We can't create a new instance of Self in the function and return a reference to it, as I explained above.
Okay, I see, thanks for the answer. I have just came up with this btw, but kinda skeptical I am not going to create a memory leak by accident
It seems to go around the compiler, but any idea if it's going to properly deallocate the data?
// This is the wrapper, which can be changed.
// It must implement the IsType trait
#[repr(transparent)]
#[derive(Clone)]
struct Wrapper(pub OriginalStructure);
impl IsType<OriginalStructure> for Wrapper {
fn from_ref(t: &OriginalStructure) -> &Self {
unsafe { &*(t as *const OriginalStructure as *const Self) }
}
fn into_ref(&self) -> &OriginalStructure {
&self.0
}
fn from_mut(t: &mut OriginalStructure) -> &mut Self {
todo!()
}
fn into_mut(&mut self) -> &mut OriginalStructure {
&mut self.0
}
}