[−][src]Macro structural::fp
Constructs a field path value, which determines the field(s) accessed in StructuralExt methods.
Type
The type produced by fp
can be one of:
-
A path component:
When it's the only thing passed to the macro. This allows accessing a non-nested field.
Eg:fp!(a)
,fp!(::Foo.bar)
,fp!(::Foo)
-
NestedFieldPath, example:
When multiple path components are passed to the macro. This allows accessing a nested field.
Eg:fp!(a.b)
,fp!(::Foo.bar.baz)
,fp!(a.b?.c)
,fp!(::Foo.bar?.baz)
-
FieldPathSet, example:
When a comma separated list of paths are passed to the macro. This allows accessing multiple fields.
Eg:fp!(a, b.c.d, c::Some.0.bar)
,fp!(::Foo.bar, baz, ::Boo)
-
NestedFieldPathSet, example:
When a=>
is passed to the macro. This allows accessing multiple fields from within a nested field.
Eg:fp!(a => b, c)
,fp!(::Foo => bar, baz, bam)
If you want type aliases and constants for a particular field path, you can use the field_path_aliases macro.
You can use the FP macro to get the type of any field path.
Identifier
The macro takes in identifiers,integers,or strings literals for the names of variants and fields.
String literals are used as a workaround for non-ascii identifiers not being
supported in Rust.
If the contents of the string literal is a valid identifier,
then you can also write it as one,
eg:fp!("Foo")
is equivalent to fp!(Foo)
.
Path Components
These are the basic building blocks for field paths:
-
foo
: A TStr with the name of a field,which accesses thefoo
field.
A.
prefixing the field name is required after other path components.
Examples:fp!(foo)
,fp!(0)
-
::Foo.bar
: A VariantField, which accesses thebar
field in theFoo
variant.
The::
prefix is required to distinguish between::Foo
and field access to aFoo
field.
Examples:fp!(::Foo.bar)
,fp!(::Boom.0)
-
::Foo
: A VariantName, which wraps the type in aVariantProxy<Self,TS!(Foo)>
. If this is directly followed by a field access, it'll be a VariantField instead.
The::
prefix is required to distinguish between::Foo
and field access to aFoo
field.
Examples:fp!(::Foo)
,fp!(::Boom)
-
?
: Syntactic sugar for::Some.0
,used to access the value inside an Option. Examples:fp!(foo?.bar)
,fp!(::Quax.foo?.0)
These can be passed to the
StructuralExt::{field_,field_mut,into_field,box_into_field}
methods
to access a single non-nested field.
More Examples:
-
fp!(hello)
: accesses thehello
field. -
fp!(100)
: accesses the100
field. -
fp!(::"@hello")
,accesses the@hello
variant. -
fp!(::1337."wh.at")
,accesses thewh.at
field in the1337
variant. (the.
in"wh.at"
is part of the field name) -
fp!("hello")
(equivalent tofp!(hello)
)
Nested fields
You can construct field paths with a sequence of path components
to access nested fields,eg:fp!(a.b.c)
.
Doing this.field_(fp!(0.1.2))
is equivalent to &((this.0).1).2
(except that it can also be done in a generic context).
This can be passed to the
StructuralExt::{field_,field_mut,into_field,box_into_field}
methods
to access a nested field.
Multiple fields
You can access multiple fields simultaneously with fp!(0,1,2)
where doing this.fields_mut(fp!(a,b,c))
is equivalent to (&mut this.a,&mut this.b,&mut this.c)
This can be passed to the StructuralExt::*fields*
methods.
StructuralExt::fields_mut
requires the field paths to be for disjoint fields.
Nested Multiple fields
You can access multiple fields inside of a nested field with the =>
in
fp!(foo.bar.baz => 0,1,2)
.
This is most useful when accessing multiple fields inside of an enum.
The =>
operator was defined for ergonomics,
this.fields(fp!(::Foo=>0,1,2))
is equivalent to
this.field_(fp!(::Foo)).map(|v| v.fields(fp!(0,1,2)) )
.
This can be passed to the StructuralExt::*fields*
methods.
StructuralExt::fields_mut
requires the field paths to be for disjoint fields.
Aliasing
For the purpose of detecting aliasing field paths,
fp!(::foo)
and fp!(foo)
are considered to be the same path,
which means that you can't pass fp!(::foo, foo)
to StructuralExt::fields_mut
.
Example:Multiple fields
use structural::{StructuralExt,fp,structural_alias}; structural_alias!{ trait Tuple3<A,B,C>{ 0:A, 1:B, 2:C, } } fn with_tuple3<'a>(tup:impl Tuple3<&'a str,&'a str,&'a str>){ assert_eq!( tup.field_(fp!(0)), &"I" ); assert_eq!( tup.field_(fp!(1)), &"you" ); assert_eq!( tup.field_(fp!(2)), &"they" ); assert_eq!( tup.fields(fp!(0,1)), (&"I",&"you") ); assert_eq!( tup.fields(fp!(0,1,2)), (&"I",&"you",&"they") ); } fn main(){ with_tuple3(("I","you","they")); with_tuple3(("I","you","they","this is not used")); with_tuple3(("I","you","they","_","this isn't used either")); }
Example:Nested Fields
use structural::{StructuralExt,Structural,fp,make_struct}; #[derive(Structural)] #[struc(public)] struct Foo{ bar:Bar, baz:u32, ooo:Option<(u32,u32)>, } #[derive(Debug,Clone,PartialEq,Structural)] #[struc(public)] struct Bar{ aaa:(u32,u32), } // `Foo_SI` was declared by the `Structural` derive on `Foo` fn with_foo(foo:&mut dyn Foo_SI){ let expected_bar=Bar{aaa: (300,301) }; assert_eq!( foo.field_(fp!(bar)), &expected_bar ); assert_eq!( foo.field_(fp!(bar.aaa)), &(300,301) ); assert_eq!( foo.field_(fp!(bar.aaa.0)), &300 ); assert_eq!( foo.field_(fp!(bar.aaa.1)), &301 ); assert_eq!( foo.field_mut(fp!( bar.aaa )), &mut (300,301) ); assert_eq!( foo.field_mut(fp!( ooo )), &mut Some((66,99)) ); // You can use the `?` operator inside of `fp` to access fields from inside an Option. // // `?` is syntactic sugar for `::Some.0`,so if you defined your own enum with // a `Some(T)` variant,you could also use the operator with that enum. assert_eq!( foo.field_mut(fp!( ooo? )), Some(&mut (66,99)) ); assert_eq!( foo.field_mut(fp!( ooo?.0 )), Some(&mut 66) ); assert_eq!( foo.field_mut(fp!( ooo?.1 )), Some(&mut 99) ); } fn main(){ let bar=Bar{aaa: (300,301) }; with_foo(&mut Foo{ bar:bar.clone(), baz:44, ooo:Some((66,99)), }); with_foo(&mut make_struct!{ bar:bar.clone(), baz:44, ooo:Some((66,99)), }); }
Example:Multiple fields insde a nested field
use structural::{StructuralExt,Structural,fp}; // `EnumA_SI` was declared by the `Structural` derive on `EnumA` fn with_foo(foo:&mut impl EnumA_SI){ assert_eq!( foo.fields(fp!(::Foo=>0,1)), Some((&5,&8)) ); assert_eq!( foo.fields_mut(fp!(::Foo=>0,1)), Some((&mut 5,&mut 8)) ); assert_eq!( foo.fields(fp!(::Bar=>x,y)), None ); assert_eq!( foo.fields_mut(fp!(::Bar=>x,y)), None ); } // `EnumA_SI` was declared by the `Structural` derive on `EnumA` fn with_bar(bar:&mut impl EnumA_SI){ assert_eq!( bar.fields(fp!(::Foo=>0,1)), None ); assert_eq!( bar.fields_mut(fp!(::Foo=>0,1)), None ); assert_eq!( bar.fields(fp!(::Bar=>x,y)), Some((&"wha",&false)) ); assert_eq!( bar.fields_mut(fp!(::Bar=>x,y)), Some((&mut "wha",&mut false)) ); } with_foo(&mut EnumA::Foo(5,8)); with_foo(&mut EnumB::Foo(5,8,13)); with_bar(&mut EnumA::Bar{ x:"wha", y:false }); with_bar(&mut EnumB::Bar{ x:"wha", y:false, z:None }); #[derive(Structural)] enum EnumA{ Foo(u32,u64), Bar{ x:&'static str, y:bool, }, } #[derive(Structural)] enum EnumB{ Foo(u32,u64,i32), Bar{ x:&'static str, y:bool, z:Option<()>, }, }