Skip to main content

orion_error_derive/
lib.rs

1//! Derive macros for `orion-error`.
2//!
3//! Most downstream crates should depend on `orion-error` and use its default
4//! `derive` feature instead of depending on this crate directly.
5
6use proc_macro::TokenStream;
7use proc_macro2::TokenStream as TokenStream2;
8use quote::{quote, ToTokens};
9use syn::{
10    parse_macro_input, spanned::Spanned, Attribute, Data, DeriveInput, Error, Expr, ExprLit,
11    ExprPath, Fields, Ident, Lit, LitStr, Result, Variant,
12};
13
14#[proc_macro_derive(ErrorCode, attributes(orion_error))]
15pub fn derive_error_code(input: TokenStream) -> TokenStream {
16    expand_error_code(parse_macro_input!(input as DeriveInput)).into()
17}
18
19#[proc_macro_derive(ErrorIdentityProvider, attributes(orion_error))]
20pub fn derive_error_identity_provider(input: TokenStream) -> TokenStream {
21    expand_error_identity_provider(parse_macro_input!(input as DeriveInput)).into()
22}
23
24#[proc_macro_derive(OrionError, attributes(orion_error))]
25pub fn derive_orion_error(input: TokenStream) -> TokenStream {
26    expand_orion_error(parse_macro_input!(input as DeriveInput)).into()
27}
28
29fn expand_error_code(input: DeriveInput) -> TokenStream2 {
30    match impl_error_code(input, MissingCode::Error) {
31        Ok(tokens) => tokens,
32        Err(err) => err.to_compile_error(),
33    }
34}
35
36fn expand_error_identity_provider(input: DeriveInput) -> TokenStream2 {
37    match impl_error_identity_provider(input) {
38        Ok(tokens) => tokens,
39        Err(err) => err.to_compile_error(),
40    }
41}
42
43fn expand_orion_error(input: DeriveInput) -> TokenStream2 {
44    let display = impl_display(input.clone());
45    let error_code = impl_error_code(input.clone(), MissingCode::Default);
46    let identity_provider = impl_error_identity_provider(input.clone());
47    let domain_reason = impl_domain_reason(input.clone());
48
49    // Generate UnifiedReason delegate constructors if a transparent variant exists
50    let uvs_ctors = impl_uvs_constructors(&input)
51        .ok()
52        .flatten()
53        .unwrap_or_default();
54
55    let mut out = TokenStream2::new();
56    let mut errors = Vec::new();
57    for result in [display, error_code, identity_provider, domain_reason] {
58        match result {
59            Ok(tokens) => out.extend(tokens),
60            Err(err) => errors.push(err),
61        }
62    }
63    out.extend(uvs_ctors);
64
65    match errors.into_iter().reduce(|mut first, second| {
66        first.combine(second);
67        first
68    }) {
69        Some(first) => first.to_compile_error(),
70        None => out,
71    }
72}
73
74include!("domain.rs");
75include!("display.rs");
76include!("error_code.rs");
77include!("identity.rs");
78include!("attrs.rs");
79include!("patterns.rs");
80include!("constructors.rs");