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