[−][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, }