Derive_delegate: The generic derive macro for all traits

Portrait v0.3.0 introduces the derive_delegate derive filler, which derives trait implementations by delegating trait calls to all fields of a struct/enum. Unlike manually written derive macros that only support one specific trait , derive_delegate works for any trait with a #[portrait::make] attribute.

The behavior of derive_delegate is similar to many macros from the standard library. Here is an all-in-one example that compiles:

#[portrait::make]
trait Foo {
    fn new(arg1: i32, arg2: &str, arg3: &mut i64) -> Self;
    fn print(&self);
    fn clone(&self) -> Self;
    #[portrait(derive_delegate(reduce = |a, b| a && b))]
    fn eq(&self, other: &Self) -> bool;
}

impl Foo for i32 {
 // omitted
}
impl Foo for String {
  // omitted
}

#[portrait::derive(Foo with portrait::derive_delegate)]
struct Fields {
    a: i32,
    b: String,
}

Here is the extra code expanded from #[portrait::derive]:

Expanded code
const _: () = {
    use foo_portrait::imports::*;
    impl Foo for Fields
    where
        i32: Foo,
        String: Foo,
    {
        fn new(arg1: i32, arg2: &str, arg3: &mut i64) -> Self {
            Self {
                a: Foo::new(arg1, arg2, arg3),
                b: Foo::new(arg1, arg2, arg3),
            }
        }
        fn print(&self) {
            let Self { a: __portrait_self_0, b: __portrait_self_1 } = self;
            Foo::print(__portrait_self_0);
            Foo::print(__portrait_self_1);
        }
        fn clone(&self) -> Self {
            let Self { a: __portrait_self_0, b: __portrait_self_1 } = self;
            Self {
                a: Foo::clone(__portrait_self_0),
                b: Foo::clone(__portrait_self_1),
            }
        }
        fn eq(&self, other: &Self) -> bool {
            let Self { a: __portrait_self_0, b: __portrait_self_1 } = self;
            (|a, b| {
                a && b
            })(
                Foo::eq(
                    __portrait_self_0,
                    {
                        let Self { a: __portrait_other, .. } = self;
                        __portrait_other
                    },
                ),
                Foo::eq(
                    __portrait_self_1,
                    {
                        let Self { b: __portrait_other, .. } = self;
                        __portrait_other
                    },
                ),
            )
        }
    }
};

See the documentation on docs.rs for more information.

About portrait

Portrait is a framework for building dynamically-known (at user crate compile time, macro crate runtime) derive/attribute macros by passing both the syn::ItemTrait and the syn::DeriveInput/syn::ItemImpl to the proc macro function. Current macros include log (log all function calls), default (always return Default::default()), delegate (impl by delegation to a single field) and derive_delegate (impl by delegation to all fields).

3 Likes