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