sword-macros 0.3.0

Structured web framework built on top of tokio ecosystem, providing powerful features for building robust web applications.
Documentation
mod codegen;
mod parse;
mod validate;

pub use parse::HttpErrorConfig;
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput, Error};

pub fn derive_http_error(input: DeriveInput) -> syn::Result<TokenStream> {
    let enum_name = &input.ident;

    let Data::Enum(data) = &input.data else {
        return Err(Error::new_spanned(
            input,
            "HttpError can only be derived for enums",
        ));
    };

    let defaults = HttpErrorConfig::from_attrs(&input.attrs)?;
    let mut from_arms = Vec::new();
    let mut variant_fns = Vec::new();

    for variant in &data.variants {
        let variant_config =
            HttpErrorConfig::parse_enum_variant_config(&variant.ident, &variant.attrs)?;

        let merged = variant_config.merged(&defaults);

        validate::HttpErrorValidator::validate_variant_config(
            enum_name,
            &variant.ident,
            &variant.fields,
            &merged,
        )?;

        variant_fns.push(codegen::HttpErrorCodegen::generate_variant_fn(
            &variant.ident,
            &variant.fields,
        ));
        from_arms.push(codegen::HttpErrorCodegen::generate_from_arm(
            enum_name,
            &variant.ident,
            &variant.fields,
            &merged,
        ));
    }

    Ok(quote! {
        impl From<#enum_name> for ::sword::web::JsonResponse {
            fn from(err: #enum_name) -> Self {
                let __sword_internal_error = err.to_string();

                match err {
                    #(#from_arms)*
                }
            }
        }

        impl ::sword::internal::web::IntoResponse for #enum_name {
            fn into_response(self) -> ::sword::internal::web::AxumResponse {
                ::sword::web::JsonResponse::from(self).into_response()
            }
        }

        #[allow(non_snake_case)]
        impl #enum_name {
            #(#variant_fns)*
        }
    })
}