derive-system 0.1.0

Rust implementation of https://github.com/stuartsierra/component
Documentation
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::{punctuated::Punctuated, token::Comma, Data, DataStruct, Error, Field, Fields, Ident};

pub fn expand(type_name: &Ident, data: &Data) -> Result<TokenStream2, Error> {
    match data {
        Data::Struct(ref data_struct) => expand_struct(type_name, data_struct),
        Data::Enum(ref data_enum) => Err(Error::new(
            data_enum.enum_token.span,
            "derive-system does not support derive for enums yet",
        )),
        Data::Union(ref data_union) => Err(Error::new(
            data_union.union_token.span,
            "derive-system does not support derive for unions",
        )),
    }
}

fn expand_struct(struct_name: &Ident, data_struct: &DataStruct) -> Result<TokenStream2, Error> {
    match data_struct.fields {
        Fields::Named(ref fields) => Ok(expand_named_struct(struct_name, &fields.named)),
        Fields::Unnamed(_) => Err(Error::new(
            data_struct.struct_token.span,
            "derive-system does not support derive for unnamed structs yet",
        )),
        Fields::Unit => Err(Error::new(
            data_struct.struct_token.span,
            "derive-system does not support derive for unit structs yet",
        )),
    }
}

fn expand_named_struct(struct_name: &Ident, fields: &Punctuated<Field, Comma>) -> TokenStream2 {
    let field_name = fields.iter().map(|field| &field.ident);
    let field_name_rev = fields.iter().map(|field| &field.ident).rev();

    quote! {
        impl lifecycle::Lifecycle for #struct_name {
            fn start(self) -> Self {
                let mut s = self;

                #(s.#field_name = s.#field_name.start();)*

                s
            }

            fn stop(self) -> Self {
                let mut s = self;

                #(s.#field_name_rev = s.#field_name_rev.stop();)*

                s
            }
        }
    }
}