[−][src]Module structural::docs::structural_macro
The Structural derive macro implements the Structural trait, as well as accessor traits(GetField/GetFieldMut/IntoField) for fields.
Default Behavior
By default,this derive generates:
-
Implementation of the structural trait for the deriving type.
-
Implementations of the accessor traits (GetField/GetFieldMut/IntoField) for pub fields.
-
A trait named
<deriving_type>_SI
,aliasing the accessor traits for the type, with a blanket implementation for all types with the same fields.
All of these can be overriden.
Container Attributes
#[struc(debug_print)]
Prints the output of the derive macro by panicking.
#[struc(no_trait)]
Disables the generation of the <deriving_type>_SI
trait.
Here is an example using this attribute
Field Attributes
#[struc(rename="<new_name>")]
Changes the name for the field in the accessor trait impls.
#[struc(impl="<trait bounds>")]
This requires the nightly_impl_fields
cargo feature
(or impl_fields
if associated type bounds stabilized after the latest release).
Changes the <deriving_type>_SI
trait (which aliases the accessor traits for this type)
not to refer to the type of this field,
instead it will be required to implement the bounds passed to this attribute.
Note that these bounds are only added to the <deriving_type>_SI
trait.
Here is the example for this attribute.
#[struc(delegate_to)]
Delegates the implementation of the Structural and accessor traits to this field.
You can only delegate the implementation and Structural and accessor traits to a single field.
Using this attribute will disable the generation of the <deriving_type>_SI
trait.
Container/Field Attributes
Unless stated otherwise, when these attributes are put on the container it will have the same effect as being put on the field,and are overriden by attributes directly on the field.
#[struc(public)]
Marks the fields as public,generating the accessor traits for the field.
#[struc(not_public)]
Marks the fields as private,not generating the accessor traits for the field.
#[struc(access="")]
Changes the implemented accessor traits for the field(s).
#[struc(access="ref")]
:
Generates impls of the GetField
trait for the field(s).
#[struc(access="mut")]
:
Generates impls of the GetField
+GetFieldMut
traits for the field(s).
#[struc(access="move")]
:
Generates impls of the GetField
+IntoField
traits for the field(s).
#[struc(access="mut move")]
:
Generates impls of the GetField
+GetFieldMut
+IntoField
traits for the field(s).
When this attribute is used on a non-pub field, it'll mark the field as public for the purpose of generating accessor trait impls.
Examples
Basic example
use structural::{Structural,GetFieldExt,structural_alias,fp}; fn reads_pair<O>(pair:&O) where // This uses the trait generated by `#[derive(Structural)]`, // aliasing the accessor traits implemented for `Hello`, // allowing any type with (at least) those fields to be passed here. O:Hello_SI { let (a,b)=pair.fields(fp!( a, b )); assert_eq!(a,&11); assert_eq!(b,&33); } #[derive(Debug,Structural,PartialEq,Eq)] #[struc(public)] struct Hello{ a:u32, b:u32 } #[derive(Structural)] #[struc(access="mut move")] #[struc(public)] struct World{ run:String, a:u32, b:u32, } fn main(){ reads_pair(&Hello{ a:11, b:33 }); reads_pair(&World{ run:"nope".into(), a:11, b:33 }); }
Mutating fields
use structural::{Structural,GetFieldExt,structural_alias,fp}; structural_alias!{ trait Tuple2<T>{ 0:T, 1:T, } } fn mutates_pair<O>(pair:&mut O) where O:Tuple2<u32> { let a=pair.field_mut(fp!(0)); assert_eq!(a,&mut 14); *a*=2; let b=pair.field_mut(fp!(1)); assert_eq!(b,&mut 16); *b*=2; } #[derive(Debug,Structural,PartialEq,Eq)] struct Point( #[struc(public)] u32, #[struc(public)] u32, #[struc(not_public)] pub u32, ); fn main(){ let mut point=Point(14,16,11); let mut tuple=(14,16); mutates_pair(&mut point); mutates_pair(&mut tuple); assert_eq!(point,Point(28,32,11)); assert_eq!(tuple,(28,32)); }
Disabling the trait alias
This example demonstrates how one disables the generation of the
<deriving_type>_SI
trait to declare it manually.
use structural::{Structural,IntoFieldMut,GetFieldExt,FP}; #[derive(Debug,Structural,PartialEq,Eq)] #[struc(no_trait)] #[struc(access="mut move")] struct Hello{ pub hello:u32, pub world:String, } pub trait Hello_SI: // From `1.40` onwards you can write those bounds like this: // ``` // IntoFieldMut<FP!(hello), Ty=u32>+ // IntoFieldMut<FP!(world), Ty=String> // ``` // Alternatively,you could use the `field_path_aliases` macro, // and use those aliases here instead of using `FP!`. IntoFieldMut<FP!(h e l l o), Ty=u32>+ IntoFieldMut<FP!(w o r l d), Ty=String> {} impl<T> Hello_SI for T where T:?Sized+ IntoFieldMut<FP!(h e l l o), Ty=u32>+ IntoFieldMut<FP!(w o r l d), Ty=String> {}
Impl trait fields
This is an example of using the #[struc(impl="<trait_bounds>")]
attribute
This requires the nightly_impl_fields
cargo feature
(or impl_fields
if associated type bounds stabilized after the latest release).
// Remove this if associated type bounds (eg: `T: Iterator<Item: Debug>`) // work without it. #![feature(associated_type_bounds)] use std::borrow::Borrow; use structural::{Structural,fp,make_struct,GetFieldExt}; #[derive(Structural)] #[struc(public)] struct Person{ #[struc(impl="Borrow<str>")] name:String, #[struc(impl="Copy+Into<u64>")] height_nm:u64 } fn takes_person(this:&impl Person_SI){ let (name,height)=this.fields(fp!(name,height_nm)); assert_eq!( name.borrow(), "bob" ); assert_eq!( (*height).into(), 1_500_000_000 ); } // Notice how `name` is a `&'static str`,and `height_nm` is a `u32`? // // This is possible because the concrete types of the fields weren't used in // the `Person_SI` trait. takes_person(&make_struct!{ name:"bob", height_nm: 1_500_000_000_u32, }); takes_person(&Person{ name:"bob".to_string(), height_nm: 1_500_000_000_u64, });
Delegation
This is an example of using the #[struc(delegate_to)]
attribute.
use structural::{fp,make_struct,GetFieldExt,Structural}; #[derive(Structural,Clone)] struct Foo<T>{ #[struc(delegate_to)] value:T } #[derive(Structural,Clone)] #[struc(public,access="ref")] struct AnimalCounts{ cows:u32, chickens:u32, pigs:u32, } fn total_count(animals:&dyn AnimalCounts_SI)->u64{ *animals.field_(fp!(cows)) as u64+ *animals.field_(fp!(chickens)) as u64+ *animals.field_(fp!(pigs)) as u64 } { let count=total_count(&Foo{ value:make_struct!{ cows:100, chickens:200, pigs:300, } }); assert_eq!( count, 600 ); } { let count=total_count(&Foo{ value:AnimalCounts{ cows:0, chickens:500, pigs:0, } }); assert_eq!( count, 500 ); } { let count=total_count(&AnimalCounts{ cows:0, chickens:500, pigs:1_000_000_000, }); assert_eq!( count, 1_000_000_500 ); }