[−][src]Macro structural::unsafe_delegate_structural_with
This macro allows delegating the implementation of the accessor traits.
This macro delegates the implementation of those traits for all fields, it doesn't provide a way to do so for only a list of fields.
Safety
In order to use this macro soundly,
you must ensure that side effects (including mutation) do not happen while
getting the delegated-to variable,
and that the delegated-to variable has a consistent value when
methods from structural
traits are called in a sequence
(with no method calls from non-structural
-traits in between).
You must ensure that the variable that you delegate Get*Field
to is the same as the one
you delegate Get*FieldMut
to,
as well as ensuring that there are no other impls of the Get*FieldMut
trait
borrowing from the same delegated-to variable mutably.
general
Example with all syntax
use structural::unsafe_delegate_structural_with; struct Foo<T>{ value:T } unsafe_delegate_structural_with!{ impl[T,] Foo<T> // This where clause is required syntax where[ T:Trait, ] // This is the identifier used for `self` in the blocks below. self_ident=this; // An optional macro argument that tells it how to specialize pointer methods. // // `specialization_params(Sized);` is the default when this the parameter is not passed, // it means that no specialization is used,always requiring `Self:Sized`. // specialization_params(Sized); // This means that the type is `?Sized` and not specialization is used, // this may be slower in debug builds because this always uses a // function pointer call in raw-pointer-taking methods. // // specialization_params(?Sized); // This means that the type is `?Sized` by default. // The `cfg(anything)` argument enables specialization conditionally, // // When specialization is disabled theres only a default impl for `Self:?Sized` // which may be slower in debug builds, // because this uses a function pointer call in raw-pointer methods. // // When specialization is enabled,the impl is specializes on `Self:Sized` // to remove the overhead of raw-pointer methods. // // specialization_params(cfg(anything)); // This is the type of the variable we delegate to, // this is required because Rust doesn't have a `typeof`/`decltype` construct. delegating_to_type=T; // This block of code is used to get the reference to the delegated-to variable // in GetField. GetField { &this.value } // This block of code is used to get a mutable reference to the delegated-to variable // in GetFieldMut // // This block must always evaluate to a mutable reference for the same variable, // and it must not be the same variable as other implementations of the GetFieldMut trait. // GetFieldMut where [ // This is an optional where clause // The last where predicate must have a trailing comma. T:Trait, ]{ &mut this.value } // This gets a raw mutable pointer to the variable this delegates to. as_delegating_raw{ &mut (*this).value as *mut T } // This block of code is used to get the delegated-to variable by value in IntoField. IntoField where [ // This is an optional where clause // The last where predicate must have a trailing comma. T:Trait, ]{ this.value } }
Example
This example is of a type wrapping a ManuallyDrop<T>
,delegating to the T
inside it.
use std::{ fmt::Debug, mem::ManuallyDrop, }; use structural::{StructuralExt,GetFieldMut,unsafe_delegate_structural_with,make_struct,fp}; struct Bar<T>{ value:ManuallyDrop<T> } impl<T> Bar<T>{ pub fn new(value:T)->Self{ Self{ value:ManuallyDrop::new(value) } } } unsafe_delegate_structural_with!{ // You must write a trailing comma. impl[T,] Bar<T> where[ // This requires T to implement Clone // for `Bar<T>` to implement the accessor traits T:Clone, ] self_ident=this; specialization_params(Sized); delegating_to_type=T; GetField { &*this.value } GetFieldMut where [T:Debug,] { &mut *this.value } as_delegating_raw{ &mut (*this).value as *mut ManuallyDrop<T> as *mut T } IntoField where [T:Debug,] { ManuallyDrop::into_inner(this.value) } } { let mut bar=Bar::new((2,3,5,8,13)); assert_eq!( bar.fields(fp!(4,3,2,1,0)), ( &13, &8, &5, &3, &2 ) ); assert_eq!( bar.fields_mut(fp!(1,2,3,4)), ( &mut 3, &mut 5, &mut 8, &mut 13 ) ); assert_eq!(bar.into_field(fp!(1)),3); } { let mut bar=Bar::new(make_struct!{ #![derive(Clone,Debug)] //This derives Clone and Debug for the anonymous struct a:"hello", b:"world", c:"tour", }); assert_eq!( bar.fields(fp!(a,b,c)), ( &"hello", &"world", &"tour" ) ); assert_eq!( bar.fields_mut(fp!(c,b,a)), ( &mut"tour", &mut"world", &mut"hello" ) ); assert_eq!( bar.into_field(fp!(c)), "tour" ); }