[−][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
/Into*Field
to,
as well as ensuring that there are no other impls of the Get*FieldMut
/Into*Field
traits
accessing the same delegated-to variable.
Drop behavior
When converting a type into multiple fields by value
(using StructuralExt::into_fields
or StrucWrapper::vals
),
the regular destructor (Drop::drop
) won't run,
instead the steps in the section below will happen.
If your type has code that must run when it's dropped,
you can pass DropFields= { ..... pre_move = foo_function; }
to this macro
to run that code before the type is converted into multiple fields by value
(using StructuralExt::into_fields
or StrucWrapper::vals
),
Drop order
The order of operations when invoking StructuralExt::into_fields
or StrucWrapper::vals
is this by default:
-
Call
DropFields::pre_move
. -
Move out the fields.
-
Drop the fields passed to
dropped_fields[]
, in the order that they were passed. -
Drop the delegated-to variable with
DropFields::drop_fields
. -
Return the moved out fields
Example with all syntax
use structural::unsafe_delegate_structural_with; struct Foo<T>{ a: (), b: (), c: (), d: Bar, value:T } struct Bar{ e: (), } 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`. // // This is the default value for the parameter: // `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 in IntoField::into_field. IntoField where [ // This is an optional where clause // The last where predicate must have a trailing comma. T:Trait, ]{ this.value } // This block of code is used to get the delegated-to variable in // IntoField::move_out_field_. move_out_field{ &mut this.value } // `DropFields = .... ` determines what happens in the DropFields implementation // for the type, which isn't as trivial as delegating to the delegated_to type. // DropFields = { // Which fields are dropped in `DropFields::drop_fields`, // in the order that they're dropped. // // If you're dropping a nested field,it must be wrapped in parentheses(ie:`(a.b.c)`). dropped_fields[ a,b,c,(d.e) ] // An optional argument for code to run right before fields are moved. // // `some_function` is called in the implementation of // `DropFields::pre_move` generated for this type. // // The passed in function must have this signature: `fn(&mut Self)` // in this example it would be `fn<T: Trait>(&mut Foo<T>)` // // `pre_move = some_function;` // An optional argument which determines whether there's pre/post field-drop logic // in `DropFields::drop_fields`. // // With `pre_post_drop_fields=true;` this inserts // a `PrePostDropFields::pre_drop(self)` call before the fields are dropped, // and a `PrePostDropFields::post_drop(self)` call after the fields are dropped, // // To use this the type must implement the `PrePostDropFields` trait // to do something before and after the listed fields (and the delegated_to variable) // are dropped. // // This is the default value: // `pre_post_drop_fields=false;` // Whether to drop the fields in the delegated_to variable,with `DropFields::drop_fields`. // // With `drop_delegated_drop_variable=true;`, // this calls `DropFields::drop_fields` on the delegated to variable. // // With `drop_delegated_drop_variable=false;`, // it does not drop the delegated to variable in an way. // drop_delegated_to_variable=true; } // Requires that the DropFields trait is implemented manually. // DropFields = manual; // This is an optional parameter, // which determines how the FromStructural and TryFromStructural traits are delegated. // // If this parameter is not passed, // then neither FromStructural and TryFromStructural is implemented. FromStructural // An optional where clause, with additional constraints where [ u32: Copy, ] { // An optional parameter, defaults to the delegated-to type. converted_from = T; // The function that constructs this type from the `converted_from` type. constructor = Foo::new; } } impl<T> Foo<T>{ pub fn new(value: T)->Self{ Self{ a: (), b: (), c: (), d: Bar{e: ()}, 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) } move_out_field{ &mut *this.value } DropFields = { dropped_fields[] } } { 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" ); }