readonly
readonly copied to clipboard
Error on pattern destructuring on readonly structs
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?
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.
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?
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.