[][src]Macro structural::fp

macro_rules! fp {
    ($ident:ident) => { ... };
    (0) => { ... };
    (1) => { ... };
    (2) => { ... };
    (3) => { ... };
    (4) => { ... };
    (5) => { ... };
    (6) => { ... };
    (7) => { ... };
    (8) => { ... };
    ($lit:literal) => { ... };
    ($($everything:tt)*) => { ... };
}

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 the foo field.
    A . prefixing the field name is required after other path components.
    Examples: fp!(foo), fp!(0)

  • ::Foo.bar: A VariantField, which accesses the bar field in the Foo variant.
    The :: prefix is required to distinguish between ::Foo and field access to a Foo field.
    Examples: fp!(::Foo.bar), fp!(::Boom.0)

  • ::Foo: A VariantName, which wraps the type in a VariantProxy<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 a Foo 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 the hello field.

  • fp!(100): accesses the 100 field.

  • fp!(::"@hello"),accesses the @hello variant.

  • fp!(::1337."wh.at"),accesses the wh.at field in the 1337 variant. (the . in "wh.at" is part of the field name)

  • fp!("hello") (equivalent to fp!(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<()>,
    },
}