errore_impl/
util.rs

1use proc_macro2::TokenStream;
2
3use quote::{format_ident, quote};
4use syn::{GenericArgument, Member, PathArguments, Type};
5
6use crate::ast::Field;
7
8pub fn use_as_display(needs_as_display: bool) -> Option<TokenStream> {
9    if needs_as_display {
10        Some(quote! {
11            use errore::__private::AsDisplay as _;
12        })
13    } else {
14        None
15    }
16}
17
18pub fn from_initializer(from_field: &Field) -> TokenStream {
19    let from_member = &from_field.member;
20    let some_source = if type_is_option(from_field.ty) {
21        quote!(::core::option::Option::Some(source))
22    } else {
23        quote!(source)
24    };
25    quote!({
26        #from_member: #some_source,
27    })
28}
29
30pub fn type_is_option(ty: &Type) -> bool {
31    type_parameter_of_option(ty).is_some()
32}
33
34pub fn unoptional_type(ty: &Type) -> TokenStream {
35    let unoptional = type_parameter_of_option(ty).unwrap_or(ty);
36    quote!(#unoptional)
37}
38
39pub fn type_parameter_of_option(ty: &Type) -> Option<&Type> {
40    let path = match ty {
41        Type::Path(ty) => &ty.path,
42        _ => return None,
43    };
44
45    let last = path.segments.last().unwrap();
46    if last.ident != "Option" {
47        return None;
48    }
49
50    let bracketed = match &last.arguments {
51        PathArguments::AngleBracketed(bracketed) => bracketed,
52        _ => return None,
53    };
54
55    if bracketed.args.len() != 1 {
56        return None;
57    }
58
59    match &bracketed.args[0] {
60        GenericArgument::Type(arg) => Some(arg),
61        _ => None,
62    }
63}
64
65pub fn fields_pat(fields: &[Field]) -> TokenStream {
66    let mut members = fields.iter().map(|field| &field.member).peekable();
67    match members.peek() {
68        Some(Member::Named(_)) => quote!({ #(#members),* }),
69        Some(Member::Unnamed(_)) => {
70            let vars = members.map(|member| match member {
71                Member::Unnamed(member) => format_ident!("_{}", member),
72                Member::Named(_) => unreachable!(),
73            });
74            quote!((#(#vars),*))
75        }
76        None => quote!({}),
77    }
78}