[][src]Macro structural::unsafe_delegate_structural_with

macro_rules! unsafe_delegate_structural_with {
    (
        $( #[doc=$doc:expr] )*
        impl $impl_params:tt $self:ty
        where $where_clause:tt
        self_ident=$this:ident;
        $( specialization_params($($raw_mut_impl:tt)*); )?
        delegating_to_type=$delegating_to_type:ty;

        $($rest:tt)*
    ) => { ... };
}

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:

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" );
}