bon_macros/parsing/
mod.rs1mod bon_crate_path;
2mod docs;
3mod item_sig;
4mod simple_closure;
5mod spanned_key;
6
7pub(crate) use bon_crate_path::*;
8pub(crate) use docs::*;
9pub(crate) use item_sig::*;
10pub(crate) use simple_closure::*;
11pub(crate) use spanned_key::*;
12
13use crate::util::prelude::*;
14use darling::FromMeta;
15use syn::parse::Parser;
16use syn::punctuated::Punctuated;
17use syn::spanned::Spanned;
18
19pub(crate) fn parse_non_empty_paren_meta_list<T: FromMeta>(meta: &syn::Meta) -> Result<T> {
20 require_non_empty_paren_meta_list_or_name_value(meta)?;
21 T::from_meta(meta)
22}
23
24pub(crate) fn require_non_empty_paren_meta_list_or_name_value(meta: &syn::Meta) -> Result {
25 match meta {
26 syn::Meta::List(meta) => {
27 meta.require_parens_delim()?;
28
29 if meta.tokens.is_empty() {
30 bail!(
31 &meta.delimiter.span().join(),
32 "expected parameters in parentheses"
33 );
34 }
35 }
36 syn::Meta::Path(path) => bail!(
37 &meta,
38 "this empty `{0}` attribute is unexpected; \
39 remove it or pass parameters in parentheses: \
40 `{0}(...)`",
41 darling::util::path_to_string(path)
42 ),
43 syn::Meta::NameValue(_) => {}
44 }
45
46 Ok(())
47}
48
49pub(crate) fn parse_paren_meta_list_with_terminated<T, P>(
54 meta: &syn::Meta,
55) -> Result<Punctuated<T, P>>
56where
57 T: syn::parse::Parse,
58 P: syn::parse::Parse,
59{
60 let item = std::any::type_name::<T>();
61 let punct = std::any::type_name::<P>();
62
63 let name = |val: &str| {
64 format!(
65 "'{}'",
66 val.rsplit("::").next().unwrap_or(val).to_lowercase()
67 )
68 };
69
70 let meta = match meta {
71 syn::Meta::List(meta) => meta,
72 _ => bail!(
73 &meta,
74 "expected a list of {} separated by {}",
75 name(item),
76 name(punct),
77 ),
78 };
79
80 meta.require_parens_delim()?;
81
82 let punctuated = Punctuated::parse_terminated.parse2(meta.tokens.clone())?;
83
84 Ok(punctuated)
85}
86
87fn parse_path_mod_style(meta: &syn::Meta) -> Result<syn::Path> {
88 let expr = match meta {
89 syn::Meta::NameValue(meta) => &meta.value,
90 _ => bail!(meta, "expected a simple path, like `foo::bar`"),
91 };
92
93 Ok(expr.require_path_mod_style()?.clone())
94}
95
96#[allow(unknown_lints, clippy::ref_option)]
98pub(crate) fn reject_syntax<T: Spanned>(name: &'static str, syntax: &Option<T>) -> Result {
99 if let Some(syntax) = syntax {
100 bail!(syntax, "{name} is not allowed here")
101 }
102
103 Ok(())
104}