predawn_macro_core/
util.rs

1use from_attr::FlagOrValue;
2use proc_macro2::TokenStream;
3use quote::quote;
4use quote_use::quote_use;
5use syn::{parse_quote, Attribute, Expr, ExprLit, Lit, Meta, MetaNameValue, Path, Type};
6
7fn get_crate_name() -> TokenStream {
8    #[cfg(not(feature = "schema"))]
9    quote! { ::predawn }
10    #[cfg(feature = "schema")]
11    quote! { ::predawn_schema }
12}
13
14pub fn extract_description(attrs: &[Attribute]) -> String {
15    let mut docs = String::new();
16
17    attrs.iter().for_each(|attr| {
18        let meta = if attr.path().is_ident("doc") {
19            &attr.meta
20        } else {
21            return;
22        };
23
24        let doc = if let Meta::NameValue(MetaNameValue {
25            value: Expr::Lit(ExprLit {
26                lit: Lit::Str(doc), ..
27            }),
28            ..
29        }) = meta
30        {
31            doc.value()
32        } else {
33            return;
34        };
35
36        if !docs.is_empty() {
37            docs.push('\n');
38        }
39
40        docs.push_str(doc.trim());
41    });
42
43    docs
44}
45
46pub fn generate_string_expr(s: &str) -> Expr {
47    parse_quote! {
48        ::std::string::ToString::to_string(#s)
49    }
50}
51
52pub fn generate_default_expr(
53    ty: &Type,
54    serde_default: FlagOrValue<String>,
55    schema_default: FlagOrValue<Expr>,
56) -> syn::Result<Option<Expr>> {
57    let default_expr: Expr = match (serde_default, schema_default) {
58        (FlagOrValue::None, FlagOrValue::None) => return Ok(None),
59
60        (FlagOrValue::None, FlagOrValue::Flag { .. })
61        | (FlagOrValue::Flag { .. }, FlagOrValue::Flag { .. })
62        | (FlagOrValue::Flag { .. }, FlagOrValue::None) => {
63            parse_quote! {
64                <#ty as ::core::default::Default>::default()
65            }
66        }
67
68        (FlagOrValue::Value { value, .. }, FlagOrValue::None)
69        | (FlagOrValue::Value { value, .. }, FlagOrValue::Flag { .. }) => {
70            let path = syn::parse_str::<Path>(&value)?;
71
72            parse_quote! {
73                #path()
74            }
75        }
76
77        (FlagOrValue::None, FlagOrValue::Value { value: expr, .. })
78        | (FlagOrValue::Flag { .. }, FlagOrValue::Value { value: expr, .. })
79        | (FlagOrValue::Value { .. }, FlagOrValue::Value { value: expr, .. }) => expr,
80    };
81
82    Ok(Some(default_expr))
83}
84
85pub fn generate_json_value(ty: &Type, expr: &Expr) -> TokenStream {
86    let crate_name = get_crate_name();
87
88    quote_use! {
89        # use std::{concat, stringify, file, line, column};
90        # use #crate_name::__internal::serde_json;
91
92        serde_json::to_value::<#ty>(#expr)
93            .expect(concat!(
94                "failed to serialize expression `", stringify!(#expr), "` of type `", stringify!(#ty),
95                "`, at ", file!(), ":", line!(), ":", column!()
96            ))
97    }
98}