[−][src]Trait structural::StructuralExt
A trait defining the primary way to call methods from structural traits.
For a wrapper type that defines inherent methods equivalent to the ones in this trait,
you can use the StrucWrapper wrapper type.
Provided methods
fn field_<'a, P>(
&'a self,
path: P
) -> NormalizeFieldsOut<Result<&'a P::Ty, P::Err>> where
P: RevGetFieldImpl<'a, Self>,
Result<&'a P::Ty, P::Err>: NormalizeFields,
&'a self,
path: P
) -> NormalizeFieldsOut<Result<&'a P::Ty, P::Err>> where
P: RevGetFieldImpl<'a, Self>,
Result<&'a P::Ty, P::Err>: NormalizeFields,
Gets a reference to a field,determined by path.
This is named field_ instead of field
because field collides with the DebugTuple/DebugStruct method
Example
use structural::{StructuralExt,fp,structural_alias}; structural_alias!{ trait EvenFields<A,B,C>{ 0:A, 2:B, 4:C, } } fn with_even<T>(this:&T) where T:EvenFields<u32,u32,u32> { assert_eq!( this.field_(fp!(0)), &1 ); assert_eq!( this.field_(fp!(2)), &2 ); assert_eq!( this.field_(fp!(4)), &5 ); } fn main(){ with_even( &(1,0,2,0,5) ); with_even( &(1,0,2,0,5,0) ); with_even( &(1,0,2,0,5,0,0) ); with_even( &(1,0,2,0,5,0,0,0) ); }
Enum Example
use structural::{StructuralExt,Structural,fp}; with_circle( &Shape::Circle{ x:3, y:5, radius:8 } ); with_circle( &MoreShapes::Circle{ x:3, y:5, radius:8 } ); fn with_circle<T>(circle:&T) where // `Shape_SI` was generated for Shape by the `Structural` derive. T: Shape_SI { assert_eq!( circle.field_(fp!(::Circle.x)), Some(&3) ); assert_eq!( circle.field_(fp!(::Circle.y)), Some(&5) ); assert_eq!( circle.field_(fp!(::Circle.radius)), Some(&8) ); // Constructing the variant proxy is the only Option we have to handle here, // instead of every access to the fields in the Circle variant being optional. // // For a more ergonomic alternative, // you can look at the example for the `fields` method let proxy=circle.field_(fp!(::Circle)).expect("Expected a circle"); assert_eq!( proxy.field_(fp!(x)), &3 ); assert_eq!( proxy.field_(fp!(y)), &5 ); assert_eq!( proxy.field_(fp!(radius)), &8 ); } #[derive(Structural)] enum Shape{ Circle{x:u32,y:u32,radius:u32}, Square{x:u32,y:u32,width:u32}, } #[derive(Structural)] enum MoreShapes{ Circle{x:u32,y:u32,radius:u32}, Square{x:u32,y:u32,width:u32}, Rectangle{x:u32,y:u32,width:u32,height:u32}, }
fn fields<'a, P>(&'a self, path: P) -> RevGetMultiFieldOut<'a, P, Self> where
P: RevGetMultiField<'a, Self>,
P: RevGetMultiField<'a, Self>,
Gets references to multiple fields,determined by path.
Example
use structural::{StructuralExt,fp,structural_alias}; structural_alias!{ trait OddFields<A,B,C>{ 1:A, 3:B, 5:C, } } fn with_even(this:&impl OddFields<u32,u32,u32>){ assert_eq!( this.fields(fp!(1,3,5)), (&22,&44,&77) ); } fn main(){ with_even( &(0,22,0,44,0,77) ); with_even( &(0,22,0,44,0,77,0) ); with_even( &(0,22,0,44,0,77,0,0) ); with_even( &(0,22,0,44,0,77,0,0,0) ); }
Enum Example
use structural::{StructuralExt,Structural,fp}; with_car( &Vehicle::Car{ name:"initial-c", km:9001 } ); with_car( &MoreVehicles::Car{ name:"initial-c", km:9001 } ); fn with_car<T>(car:&T) where // `Vehicle_SI` was generated for Vehicle by the `Structural` derive. T: Vehicle_SI { assert_eq!( car.fields(fp!(::Car.name, ::Car.km)), ( Some(&"initial-c"), Some(&9001) ) ); // You can use `=>` to access multiple fields inside of a nested field(or a variant) // this allows accessing multiple fields inside an enum variant without having to // create an intermediate variant proxy // (look at the next assert for what that looks like). assert_eq!( car.fields(fp!(::Car=>name,km)), Some((&"initial-c",&9001)) ); assert_eq!( // This is equivalent to the field access in the previous assert car.field_(fp!(::Car)).map(|vp| vp.fields(fp!(name,km)) ), Some((&"initial-c",&9001)) ); assert_eq!( car.cloned_fields(fp!(::Truck=>weight_kg,driven_km)), None); } #[derive(Structural)] enum Vehicle{ Car{name: &'static str, km:u32}, Truck{ weight_kg:u32, driven_km:u32 }, } #[derive(Structural)] enum MoreVehicles{ Car{name: &'static str, km:u32}, Truck{ weight_kg:u32, driven_km:u32 }, Boat, }
fn cloned_fields<'a, P>(
&'a self,
path: P
) -> ClonedOut<RevGetMultiFieldOut<'a, P, Self>> where
P: RevGetMultiField<'a, Self>,
RevGetMultiFieldOut<'a, P, Self>: Cloned,
&'a self,
path: P
) -> ClonedOut<RevGetMultiFieldOut<'a, P, Self>> where
P: RevGetMultiField<'a, Self>,
RevGetMultiFieldOut<'a, P, Self>: Cloned,
Gets clones of multiple fields,determined by path.
Example
This example also uses the reexported IntoArray trait,
which allows converting homogeneous tuples to arrays,
in this case it's used to iterate over the fields.
use structural::{StructuralExt,Structural,fp,make_struct}; use structural::reexports::IntoArray; // The `Fruits_SI` trait was declared by the `Structural` derive on `Fruits`. fn total_fruit_count(fruits:&dyn Fruits_SI)->u32{ fruits .cloned_fields(fp!( apples, oranges, tangerines, tomatoes )) .into_array() .iter() .sum() } { let fruits=Fruits{ apples:1, oranges:2, tangerines:3, tomatoes:5, }; assert_eq!( total_fruit_count(&fruits), 11 ); } { let fruits=make_struct!{ apples:8, oranges:13, tangerines:21, tomatoes:34, }; assert_eq!( total_fruit_count(&fruits), 76 ); } #[derive(Structural)] // We only get read access to the fields. #[struc(public,access="ref")] struct Fruits{ apples:u32, oranges:u32, tangerines:u32, tomatoes:u32, }
Enum Example
use structural::{StructuralExt,Structural,fp}; with_pc( &Device::Pc{ manufacturer:"dawn", year:2038 } ); with_pc( &MoreDevices::Pc{ manufacturer:"dawn", year:2038 } ); fn with_pc<T>(pc:&T) where // `Device_SI` was generated for Device by the `Structural` derive. T: Device_SI { assert_eq!( pc.cloned_fields(fp!(::Pc.manufacturer, ::Pc.year)), ( Some("dawn"), Some(2038) ) ); // You can use `=>` to access multiple fields inside of a nested field(or a variant) // this allows accessing multiple fields inside an enum variant without having to // create an intermediate variant proxy // (look at the next assert for what that looks like). assert_eq!( pc.cloned_fields(fp!(::Pc=>manufacturer,year)), Some(("dawn",2038)) ); assert_eq!( // This is equivalent to the field access in the previous assert pc.field_(fp!(::Pc)).map(|vp| vp.cloned_fields(fp!(manufacturer,year)) ), Some(("dawn",2038)) ); assert_eq!( pc.cloned_fields(fp!(::Phone=>number,charge)), None); } #[derive(Structural)] enum Device{ Pc{manufacturer: &'static str, year:u32}, Phone{number:&'static str,charge:u8}, } #[derive(Structural)] enum MoreDevices{ Pc{manufacturer: &'static str, year:u32}, Phone{number:&'static str,charge:u8}, Tablet, }
fn field_mut<'a, P>(
&'a mut self,
path: P
) -> NormalizeFieldsOut<Result<&'a mut P::Ty, P::Err>> where
P: RevGetFieldMutImpl<'a, Self>,
Result<&'a mut P::Ty, P::Err>: NormalizeFields,
&'a mut self,
path: P
) -> NormalizeFieldsOut<Result<&'a mut P::Ty, P::Err>> where
P: RevGetFieldMutImpl<'a, Self>,
Result<&'a mut P::Ty, P::Err>: NormalizeFields,
Gets a mutable reference to a field,determined by path.
Example
use structural::{StructuralExt,fp,make_struct,Structural}; #[derive(Structural)] struct Human{ pub x:i32, pub y:i32, pub health:u32, flags:u32, } // The `Human_SI` trait was declared by the `Structural` derive on `Human`. fn move_human( this:&mut dyn Human_SI, dx:i32, dy:i32 ){ *this.field_mut(fp!(x))+=dx; *this.field_mut(fp!(y))+=dy; } { let mut entity=make_struct!{ x: 0, y: 0, health: 100, }; move_human(&mut entity,-100,300); assert_eq!( entity.fields(fp!(x,y,health)), (&-100,&300,&100) ) } { let mut entity=Human{ x: -1000, y: 1000, health: 1, flags: 0b11111, }; move_human(&mut entity,500,-200); assert_eq!( entity.x, -500 ); assert_eq!( entity.y, 800 ); assert_eq!( entity.health, 1 ); assert_eq!( entity.flags, 0b11111 ); }
Enum Example
use structural::{StructuralExt,Structural,fp}; with_soda( &mut Beverage::Soda{ ml:600, cents:400 } ); with_soda( &mut MoreBeverages::Soda{ ml:600, cents:400 } ); fn with_soda<T>(soda:&mut T) where // `Beverage_SI` was generated for Beverage by the `Structural` derive. T: Beverage_SI { assert_eq!( soda.field_mut(fp!(::Soda.ml)), Some(&mut 600) ); assert_eq!( soda.field_mut(fp!(::Soda.cents)), Some(&mut 400) ); // Constructing the variant proxy is the only Option we have to handle here, // instead of every access to the fields in the Soda variant being optional. let proxy=soda.field_mut(fp!(::Soda)).expect("Expected a soda"); assert_eq!( proxy.field_mut(fp!(ml)), &mut 600 ); assert_eq!( proxy.field_mut(fp!(cents)), &mut 400 ); } #[derive(Structural)] enum Beverage{ Soda{ ml:u32, cents:u32 }, Water, } #[derive(Structural)] enum MoreBeverages{ Soda{ ml:u32, cents:u32 }, Water, Beer, }
fn fields_mut<'a, P>(
&'a mut self,
path: P
) -> RevGetMultiFieldMutOut<'a, P, Self> where
P: RevGetMultiFieldMut<'a, Self>,
&'a mut self,
path: P
) -> RevGetMultiFieldMutOut<'a, P, Self> where
P: RevGetMultiFieldMut<'a, Self>,
Gets mutable references to multiple fields,determined by path.
Example
use structural::{ StructuralExt,GetFieldMut,GetFieldType,Structural, fp,field_path_aliases, }; field_path_aliases!{ mod names{x,y} } fn swap_coordinates<T,U>(this:&mut T) where T:GetFieldMut<names::x,Ty=U>, T:GetFieldMut<names::y,Ty=U>, { let (x,y)=this.fields_mut(fp!(x,y)); std::mem::swap(x,y); } { let mut this=Point2D{ x:100, y:300 }; swap_coordinates(&mut this); assert_eq!( this.x, 300 ); assert_eq!( this.y, 100 ); } { let mut this=Point3D{ x:30, y:0, z:500 }; swap_coordinates(&mut this); assert_eq!( this.x, 0 ); assert_eq!( this.y, 30 ); assert_eq!( this.z, 500 ); } #[derive(Structural)] struct Point2D<T>{ pub x:T, pub y:T, } #[derive(Structural)] struct Point3D<T>{ pub x:T, pub y:T, pub z:T, }
Example
An example of how this method does not allow multiple mutable borrows of the same field.
use structural::{StructuralExt,fp}; let mut tup=(1,1,2,3,5,8); let _=tup.fields_mut(fp!(4,4));
Enum Example
use structural::{StructuralExt,Structural,fp}; with_book( &mut Medium::Book{ pages:500, title:"Dracular" } ); with_book( &mut MoreMedia::Book{ pages:500, title:"Dracular" } ); fn with_book<T>(book:&mut T) where // `Medium_SI` was generated for Medium by the `Structural` derive. T: Medium_SI { assert_eq!( book.fields_mut(fp!(::Book.pages, ::Book.title)), ( Some(&mut 500), Some(&mut "Dracular") ) ); // You can use `=>` to access multiple fields inside of a nested field(or a variant) // this allows accessing multiple fields inside an enum variant without having to // create an intermediate variant proxy // (look at the next assert for what that looks like). assert_eq!( book.fields_mut(fp!(::Book=>pages,title)), Some((&mut 500,&mut "Dracular")), ); assert_eq!( // This is equivalent to the field access in the previous assert book.field_mut(fp!(::Book)).map(|vp| vp.fields_mut(fp!(pages,title)) ), Some((&mut 500,&mut "Dracular")) ); assert_eq!( book.fields_mut(fp!(::Comic=>artist,in_color)), None); } #[derive(Structural)] enum Medium{ Book{ pages:u32, title:&'static str }, Comic{artist:&'static str,in_color:bool}, } #[derive(Structural)] enum MoreMedia{ Book{ pages:u32, title:&'static str }, Comic{artist:&'static str,in_color:bool}, Television, }
fn into_field<'a, P>(self, path: P) -> NormalizeFieldsOut<Result<P::Ty, P::Err>> where
P: RevIntoFieldImpl<'a, Self>,
P::Ty: Sized,
Result<P::Ty, P::Err>: NormalizeFields,
Self: Sized,
P: RevIntoFieldImpl<'a, Self>,
P::Ty: Sized,
Result<P::Ty, P::Err>: NormalizeFields,
Self: Sized,
Converts ´self´ into a field,determined by path.
Example
use structural::{StructuralExt,Structural,fp}; #[derive(Structural,Clone)] #[struc(public,access="move")] struct Tupled<T>(T,T,T,T); // The `Tupled_SI` trait was declared by the `Structural` derive on `Tupled`. fn pick_index<T>(this:impl Tupled_SI<T>,which_one:u32)->T{ match which_one % 4 { 0=>this.into_field(fp!(0)), 1=>this.into_field(fp!(1)), 2=>this.into_field(fp!(2)), _=>this.into_field(fp!(3)), } } { let tup=Tupled(13,21,34,55); assert_eq!( pick_index(tup.clone(),0), 13 ); assert_eq!( pick_index(tup.clone(),1), 21 ); assert_eq!( pick_index(tup.clone(),2), 34 ); assert_eq!( pick_index(tup ,3), 55 ); } { let array=[13,21,34,55]; assert_eq!( pick_index(array.clone(),0), 13 ); assert_eq!( pick_index(array.clone(),1), 21 ); assert_eq!( pick_index(array.clone(),2), 34 ); assert_eq!( pick_index(array ,3), 55 ); }
Enum Example
use structural::{StructuralExt,Structural,fp}; with_table( &Furniture::Table{ height_cm:101, width_cm:333 } ); with_table( &MoreFurniture::Table{ height_cm:101, width_cm:333 } ); fn with_table<T>(table:&T) where // `Furniture_SI` was generated for Furniture by the `Structural` derive. T: Furniture_SI + Clone { assert_eq!( table.clone().into_field(fp!(::Table.height_cm)), Some(101) ); assert_eq!( table.clone().into_field(fp!(::Table.width_cm)), Some(333) ); // Constructing the variant proxy is the only Option we have to handle here, // instead of every access to the fields in the Table variant being optional. let proxy=table.clone().into_field(fp!(::Table)).expect("Expected a table"); assert_eq!( proxy.clone().into_field(fp!(height_cm)), 101 ); assert_eq!( proxy.clone().into_field(fp!(width_cm)), 333 ); } #[derive(Structural,Clone)] enum Furniture{ Table{ height_cm:u32, width_cm:u32 }, Chair, } #[derive(Structural,Clone)] enum MoreFurniture{ Table{ height_cm:u32, width_cm:u32 }, Chair, Sofa, }
fn is_variant<P>(&self, _path: P) -> bool where
P: IsTStr,
Self: IsVariant<P>,
P: IsTStr,
Self: IsVariant<P>,
Checks whether an enum is a particular variant.
Example
use structural::{StructuralExt,Structural,fp}; check_colors( &Color::Red, &Color::Blue, &Color::Green ); check_colors( &ColorPlus::Red, &ColorPlus::Blue, &ColorPlus::Green ); fn check_colors<T>( red:&T, blue:&T, green:&T ) where // `Color_SI` was declared by the `Structural` derive on `Color`. T: Color_SI { assert!( red.is_variant(fp!(Red)) ); assert!( !red.is_variant(fp!(Blue)) ); assert!( !red.is_variant(fp!(Green)) ); assert!( !blue.is_variant(fp!(Red)) ); assert!( blue.is_variant(fp!(Blue)) ); assert!( !blue.is_variant(fp!(Green)) ); assert!( !green.is_variant(fp!(Red)) ); assert!( !green.is_variant(fp!(Blue)) ); assert!( green.is_variant(fp!(Green)) ); } #[derive(Structural)] enum Color{ Red, Blue, Green, } #[derive(Structural)] enum ColorPlus{ Red, Blue, Green, Teal, White, Gray, Black, }