[][src]Trait structural::field::IntoVariantField

pub unsafe trait IntoVariantField<V, F>: GetVariantField<V, F> + DropFields {
    fn into_vfield_(self, variant_name: V, field_name: F) -> Option<Self::Ty>;
unsafe fn move_out_vfield_(
        &mut self,
        variant_name: V,
        field_name: F,
        moved_fields: &mut MovedOutFields
    ) -> Option<Self::Ty>; unsafe fn into_vfield_unchecked_(
        self,
        variant_name: V,
        field_name: F
    ) -> Self::Ty
    where
        Self: Sized
, { ... }
unsafe fn move_out_vfield_unchecked_(
        &mut self,
        variant_name: V,
        field_name: F,
        moved_fields: &mut MovedOutFields
    ) -> Self::Ty { ... } }

Provides shared and by-value access to an enum variant field.

The V and F type parameters are expected to be TStr.

Every instance of "the F field"/"the V variant" in the docs mean "in the field/variant named by the F/V type parameter"

Safety

IsVariant<V> and IntoVariantField<V, F> must agree on what variant the enum currently is. If IsVariant returns true for a particular V variant, then into_vfield_,and move_out_vfield_ must return Some(_).

If overriden, the *_unchecked methods must diverge (abort, panic, or call the equivalent of std::hint::unreachable_unchecked) if the enum is not currently the V variant, and return the same field as the checked equivalents if the enum is currently the V variant.

Implementing move_out_vfield_

The way this method is expected to be implemented like this:

  • Match on the enum,if it's the expected variant continue the steps, otherwise return None.

  • Move out the field using std::ptr::read or equivalent.

  • Mark the field in the moved_fields parameter as being moved out using the set_moved_out method, with a FieldBit argument unique to this field in the variant (fields from different variants can use the same FieldBit as fields in other variants).

Every implementation of IntoVariantField::move_out_vfield_ must return field(s) that no other implementation of IntoVariantField or IntoField for this type return.

The DropFields::drop_fields implementation for this type must then call is_moved_out on its MovedOutFields parameter to decide whether to drop the field, passing the same FieldBit argument as in the move_out_vfield_ implementation. If is_moved_out returns false, then the field must be dropped.

Example

use structural::field::IntoVariantField;
use structural::for_examples::{Bomb,WithBoom};
use structural::{StructuralExt,TS,fp};

fn example<T>(mut this: T)
where
    T: IntoVariantField<TS!(Boom),TS!(a),Ty= &'static str>+
       IntoVariantField<TS!(Boom),TS!(b),Ty= &'static [u16]>,
{
    assert_eq!( this.is_variant(fp!(Boom)), true );

    assert_eq!( this.field_(fp!(::Boom.a)), Some(&"Because.") );

    assert_eq!( this.cloned_fields(fp!(::Boom=>a,b)), Some(( "Because.", &[13,21][..] )) );

    assert_eq!( this.fields(fp!(::Boom=>a,b)), Some(( &"Because.", &&[13,21][..] )) );

    assert_eq!( this.into_field(fp!(::Boom.a)), Some("Because.") );
}

example(WithBoom::Boom{ a:"Because.", b:&[13,21] });
example(Bomb::Boom{ a:"Because.", b:&[13,21] });

Example: Manual implementation

While this trait is better derived, it can be implemented manually.

Note that the derive macro also declares trait aliases for the traits implemented here.

use structural::{
    field::ownership::{FieldBit, DropFields, MovedOutFields, RunDrop},
    FieldType, GetVariantField, IntoVariantField, FP, TS,
    StructuralExt,fp,structural_alias,
};
use structural::enums::{IsVariant, VariantCount};

// The `FooBounds` trait is defined below.
fn using_enum(bar: impl FooBounds, baz: impl FooBounds){
    assert_eq!( bar.fields(fp!(::Bar=>0,1)), Some((&34, &51)) );
    assert_eq!( bar.into_fields(fp!(::Bar=>0,1)), Some((34, 51)) );
    assert_eq!( bar.is_variant(fp!(Bar)), true );
    assert_eq!( bar.is_variant(fp!(Baz)), false );

    assert_eq!( baz.fields(fp!(::Bar=>0,1)), None );
    assert_eq!( baz.into_fields(fp!(::Bar=>0,1)), None );
    assert_eq!( baz.is_variant(fp!(Bar)), false );
    assert_eq!( baz.is_variant(fp!(Baz)), true );
}


using_enum(Foo::Bar(34,51), Foo::Baz);


#[derive(Copy,Clone)]
enum Foo{
    Bar(u32,u64),
    Baz,
}

const BAR_0_INDEX: FieldBit = FieldBit::new(0);
const BAR_1_INDEX: FieldBit = FieldBit::new(1);

unsafe impl VariantCount for Foo{
    type Count=TS!(2);
}

unsafe impl IsVariant<TS!(Bar)> for Foo {
    fn is_variant_(&self,_:TS!(Bar))->bool{
        match self {
            Foo::Bar{..}=>true,
            _=>false,
        }
    }
}

impl FieldType<FP!(::Bar.0)> for Foo{
    type Ty=u32;
}

unsafe impl GetVariantField<TS!(Bar),TS!(0)> for Foo{
    fn get_vfield_(&self, _:TS!(Bar), _:TS!(0)) -> Option<&u32>{
        match self {
            Foo::Bar(ret,_)=>Some(ret),
            _=>None,
        }
    }
}

unsafe impl IntoVariantField<TS!(Bar),TS!(0)> for Foo{
    fn into_vfield_(self, _:TS!(Bar), _:TS!(0)) -> Option<u32>{
        match self {
            Foo::Bar(ret,_)=>Some(ret),
            _=>None,
        }
    }

    unsafe fn move_out_vfield_(
        &mut self,
        _: TS!(Bar),
        _: TS!(0),
        moved_fields: &mut MovedOutFields,
    ) -> Option<u32> {
        match self {
            Foo::Bar(ret,_)=>{
                moved_fields.set_moved_out(BAR_0_INDEX);
                Some(std::ptr::read(ret))
            },
            _=>None,
        }
    }
}


impl FieldType<FP!(::Bar.1)> for Foo{
    type Ty=u64;
}

unsafe impl GetVariantField<TS!(Bar),TS!(1)> for Foo{
    fn get_vfield_(&self, _:TS!(Bar), _:TS!(1)) -> Option<&u64>{
        match self {
            Foo::Bar(_,ret)=>Some(ret),
            _=>None,
        }
    }
}

unsafe impl IntoVariantField<TS!(Bar),TS!(1)> for Foo{
    fn into_vfield_(self, _:TS!(Bar), _:TS!(1)) -> Option<u64>{
        match self {
            Foo::Bar(_,ret)=>Some(ret),
            _=>None,
        }
    }

    unsafe fn move_out_vfield_(
        &mut self,
        _: TS!(Bar),
        _: TS!(1),
        moved_fields: &mut MovedOutFields,
    ) -> Option<u64> {
        match self {
            Foo::Bar(_,ret)=>{
                moved_fields.set_moved_out(BAR_1_INDEX);
                Some(std::ptr::read(ret))
            },
            _=>None,
        }
    }
}

unsafe impl DropFields for Foo{
    // This type does nothing before fields are moved.
    fn pre_move(&mut self){}
     
    unsafe fn drop_fields(&mut self, moved_fields: MovedOutFields){
        match self {
            Foo::Bar(field0, field1)=>{
                // RunDrop here ensures that the destructors for all fields are ran 
                // even if any of them panics.
                let _a;
                if moved_fields.is_moved_out(BAR_0_INDEX){
                    _a = RunDrop::new(field0);
                }

                let _a;
                if moved_fields.is_moved_out(BAR_1_INDEX){
                    _a = RunDrop::new(field1);
                }
            }
            Foo::Baz=>{}
        }
    }
}

unsafe impl IsVariant<TS!(Baz)> for Foo {
    fn is_variant_(&self,_:TS!(Baz))->bool{
        match self {
            Foo::Baz{..}=>true,
            _=>false,
        }
    }
}

structural_alias!{
    trait FooBounds: Copy{
        move Bar(u32,u64),
        move Baz,
    }
}

Required methods

fn into_vfield_(self, variant_name: V, field_name: F) -> Option<Self::Ty>

Converts this into the F field in the V variant by value.

unsafe fn move_out_vfield_(
    &mut self,
    variant_name: V,
    field_name: F,
    moved_fields: &mut MovedOutFields
) -> Option<Self::Ty>

Moves out the F field from the V variant.

Safety

The same instance of MovedOutFields must be passed to every call to move_out_vfield_ on the same instance of this type, as well as not mutating that MovedOutFields instance outside of methods of this trait for this type.

Each field must be moved with any method at most once on the same instance of this type.

Loading content...

Provided methods

unsafe fn into_vfield_unchecked_(
    self,
    variant_name: V,
    field_name: F
) -> Self::Ty where
    Self: Sized

Converts this into the F field in the V variant by value.

Safety

The enum must be the V variant.

unsafe fn move_out_vfield_unchecked_(
    &mut self,
    variant_name: V,
    field_name: F,
    moved_fields: &mut MovedOutFields
) -> Self::Ty

Converts this into the F field in the V variant by value, without checking that the enum is currently the V variant.

This method exists so that Box<dyn Trait> can be converted into a field by value.

Safety

The enum must be the V variant.

The same instance of MovedOutFields must be passed to every call to move_out_vfield_unchecked_ on the same instance of this type, as well as not mutating that MovedOutFields instance outside of methods of this trait for this type.

Each field must be moved with any method at most once on the same instance of this type.

Loading content...

Implementations on Foreign Types

impl<T> IntoVariantField<TStr<__TS<(__S, __o, __m, __e)>>, TStr<__TS<(__0,)>>> for Option<T> where
    Self: DropFields
[src]

impl<T, E> IntoVariantField<TStr<__TS<(__O, __k)>>, TStr<__TS<(__0,)>>> for Result<T, E> where
    Self: DropFields
[src]

impl<T, E> IntoVariantField<TStr<__TS<(__E, __r, __r)>>, TStr<__TS<(__0,)>>> for Result<T, E> where
    Self: DropFields
[src]

impl<T: ?Sized, V, F, Ty> IntoVariantField<TStr<V>, F> for Box<T> where
    T: IntoVariantField<TStr<V>, F, Ty = Ty>, 
[src]

Loading content...

Implementors

impl<T, V, F> IntoVariantField<TStr<V>, F> for FieldCloner<T> where
    T: GetVariantField<TStr<V>, F>,
    T::Ty: Clone
[src]

impl<T, __V, __F, __Ty> IntoVariantField<TStr<__V>, __F> for StrucWrapper<T> where
    T: IntoVariantField<TStr<__V>, __F, Ty = __Ty>, 
[src]

Loading content...