readonly icon indicating copy to clipboard operation
readonly copied to clipboard

Error on pattern destructuring on readonly structs

Open CGMossa opened this issue 5 years ago • 3 comments

First, I love this crate and I am using it everywhere.

I've this scenario where

#[readonly::make]
#[derive(Debug, Default)]
pub struct TallySpecificType { 
pub a_field: usize,
}

And somewhere along the way, I want to

let TallySpecificType { a_field } = some_tally_specific_type;

But I get erros on a_field being a private-field. I understand that this prevents me from constructing this struct "outside" of it, which is something I want to keep, but the destructuring should be possible irregardless.

What am I missing here? Some &*? Or is there as misunderstanding somehow?

CGMossa avatar Jul 02 '20 08:07 CGMossa

For this you have to dig into what the macro generates. It generates a ReadOnlyOriginalTypeName struct that is created via a Deref trait implementation.

Here's an example of how you can get it to work (use .deref() and ReadOnlyTallySpecificType):

mod lib {
    #[readonly::make]
    pub struct TallySpecificType {
        pub a_field: usize,
    }

    impl TallySpecificType {
        pub fn new(a_field: usize) -> TallySpecificType {
            TallySpecificType { a_field }
        }
    }
}

mod bin {
    use crate::lib::*;
    use std::ops::Deref;

    pub fn test_with_value() {
        let a_value = TallySpecificType::new(10);

        let ReadOnlyTallySpecificType { a_field } = a_value.deref();
        println!("{}", a_field)
    }

    pub fn test_with_ref() {
        let a_reference = &TallySpecificType::new(20);

        let ReadOnlyTallySpecificType { a_field } = a_reference.deref();
        println!("{}", a_field)
    }
}

fn main() {
    bin::test_with_value();
    bin::test_with_ref();
}

Now if I use cargo expand to expand the macros:

$ cargo expand > expanded.rs

Results in:

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
mod lib {
    #[repr(C)]
    pub struct TallySpecificType {
        a_field: usize,
    }
    #[doc(hidden)]
    #[repr(C)]
    pub struct ReadOnlyTallySpecificType {
        pub a_field: usize,
    }
    #[doc(hidden)]
    impl core::ops::Deref for TallySpecificType {
        type Target = ReadOnlyTallySpecificType;
        fn deref(&self) -> &Self::Target {
            unsafe { &*(self as *const Self as *const Self::Target) }
        }
    }
    impl TallySpecificType {
        pub fn new(a_field: usize) -> TallySpecificType {
            TallySpecificType { a_field }
        }
    }
}
mod bin {
    use crate::lib::*;
    use std::ops::Deref;
    pub fn test_with_value() {
        let a_value = TallySpecificType::new(10);
        let ReadOnlyTallySpecificType { a_field } = a_value.deref();
        {
            ::std::io::_print(::core::fmt::Arguments::new_v1(
                &["", "\n"],
                &match (&a_field,) {
                    (arg0,) => [::core::fmt::ArgumentV1::new(
                        arg0,
                        ::core::fmt::Display::fmt,
                    )],
                },
            ));
        }
    }
    pub fn test_with_ref() {
        let a_reference = &TallySpecificType::new(20);
        let ReadOnlyTallySpecificType { a_field } = a_reference.deref();
        {
            ::std::io::_print(::core::fmt::Arguments::new_v1(
                &["", "\n"],
                &match (&a_field,) {
                    (arg0,) => [::core::fmt::ArgumentV1::new(
                        arg0,
                        ::core::fmt::Display::fmt,
                    )],
                },
            ));
        }
    }
}
fn main() {
    bin::test_with_value();
    bin::test_with_ref();
}

you can see the generated code, most importantly the Deref impl and the extra struct.

However maybe there's a more elegant way that this crate could solve this problem? I'm just suggesting a way you can do it currently. Also maybe if this intended it should be documented.

RAnders00 avatar Jul 12 '20 13:07 RAnders00

Some time has passed and this issue might have no longer any relevance, or maybe something else could be done? I'm also thinking about if this could be done for enums?

CGMossa avatar Jan 14 '22 23:01 CGMossa

Some time has passed and this issue might have no longer any relevance, or maybe something else could be done? I'm also thinking about if this could be done for enums?

I would really need this for enums.

gl-yziquel avatar Mar 11 '24 23:03 gl-yziquel