orion-error-derive 0.8.1

Derive macros for orion-error
Documentation
#[derive(Clone, Copy)]
enum MissingCode {
    Error,
    Default,
}

fn impl_error_code(input: DeriveInput, missing_code: MissingCode) -> Result<TokenStream2> {
    let ident = input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    match input.data {
        Data::Enum(data) => {
            let arms = data
                .variants
                .iter()
                .map(|variant| {
                    let args = OrionAttrs::from_attrs(&variant.attrs)?;
                    if args.transparent {
                        let (pattern, inner) = transparent_variant_pattern(variant)?;
                        Ok(quote! {
                            #pattern => ::orion_error::reason::ErrorCode::error_code(#inner)
                        })
                    } else if let Some(code) = args.code {
                        let pattern = variant_pattern(variant);
                        Ok(quote! {
                            #pattern => #code
                        })
                    } else if matches!(missing_code, MissingCode::Default) {
                        let pattern = variant_pattern(variant);
                        Ok(quote! {
                            #pattern => 500
                        })
                    } else {
                        Err(Error::new(
                            variant.span(),
                            "missing #[orion_error(code = ...)] or #[orion_error(transparent)]",
                        ))
                    }
                })
                .collect::<Result<Vec<_>>>()?;

            Ok(quote! {
                impl #impl_generics ::orion_error::reason::ErrorCode for #ident #ty_generics #where_clause {
                    fn error_code(&self) -> i32 {
                        match self {
                            #(#arms,)*
                        }
                    }
                }
            })
        }
        Data::Struct(data) => {
            let args = OrionAttrs::from_attrs(&input.attrs)?;
            let body = if args.transparent {
                let inner = transparent_struct_binding(&data.fields)?;
                let pattern = struct_pattern(&ident, &data.fields);
                quote! {
                    match self {
                        #pattern => ::orion_error::reason::ErrorCode::error_code(#inner),
                    }
                }
            } else if let Some(code) = args.code {
                quote! { #code }
            } else if matches!(missing_code, MissingCode::Default) {
                quote! { 500 }
            } else {
                return Err(Error::new(
                    ident.span(),
                    "missing container #[orion_error(code = ...)] or #[orion_error(transparent)]",
                ));
            };

            Ok(quote! {
                impl #impl_generics ::orion_error::reason::ErrorCode for #ident #ty_generics #where_clause {
                    fn error_code(&self) -> i32 {
                        #body
                    }
                }
            })
        }
        Data::Union(_) => Err(Error::new(
            ident.span(),
            "ErrorCode can only be derived for enums or structs",
        )),
    }
}