pub unsafe trait IntoVariantField<V, F>: GetVariantField<V, F> + DropFields {
// Required methods
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>;
// Provided methods
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 { ... }
}Expand description
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::reador equivalent. -
Mark the field in the
moved_fieldsparameter as being moved out using theset_moved_outmethod, with aFieldBitargument unique to this field in the variant (fields from different variants can use the sameFieldBitas 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§
Sourcefn into_vfield_(self, variant_name: V, field_name: F) -> Option<Self::Ty>
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.
Sourceunsafe fn move_out_vfield_(
&mut self,
variant_name: V,
field_name: F,
moved_fields: &mut MovedOutFields,
) -> Option<Self::Ty>
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.
Provided Methods§
Sourceunsafe fn into_vfield_unchecked_(
self,
variant_name: V,
field_name: F,
) -> Self::Tywhere
Self: Sized,
unsafe fn into_vfield_unchecked_(
self,
variant_name: V,
field_name: F,
) -> Self::Tywhere
Self: Sized,
Sourceunsafe fn move_out_vfield_unchecked_(
&mut self,
variant_name: V,
field_name: F,
moved_fields: &mut MovedOutFields,
) -> Self::Ty
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.