predawn_macro_core/
util.rs1use 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}