dioxus_core_macro/
utils.rs

1use quote::ToTokens;
2use syn::parse::{Parse, ParseStream};
3use syn::spanned::Spanned;
4use syn::{parse_quote, Expr, Lit, Meta, Token, Type};
5
6/// Attempts to convert the given literal to a string.
7/// Converts ints and floats to their base 10 counterparts.
8///
9/// Returns `None` if the literal is [`Lit::Verbatim`] or if the literal is [`Lit::ByteStr`]
10/// and the byte string could not be converted to UTF-8.
11pub fn lit_to_string(lit: Lit) -> Option<String> {
12    match lit {
13        Lit::Str(l) => Some(l.value()),
14        Lit::ByteStr(l) => String::from_utf8(l.value()).ok(),
15        Lit::Byte(l) => Some(String::from(l.value() as char)),
16        Lit::Char(l) => Some(l.value().to_string()),
17        Lit::Int(l) => Some(l.base10_digits().to_string()),
18        Lit::Float(l) => Some(l.base10_digits().to_string()),
19        Lit::Bool(l) => Some(l.value().to_string()),
20        Lit::Verbatim(_) => None,
21        _ => None,
22    }
23}
24
25pub fn format_type_string(ty: &Type) -> String {
26    let ty_unformatted = ty.into_token_stream().to_string();
27    let ty_unformatted = ty_unformatted.trim();
28
29    // simply remove all whitespace
30    let ty_formatted = ty_unformatted.replace(' ', "");
31
32    ty_formatted.to_string()
33}
34
35/// Represents the `#[deprecated]` attribute.
36///
37/// You can use the [`DeprecatedAttribute::from_meta`] function to try to parse an attribute to this struct.
38#[derive(Default)]
39pub struct DeprecatedAttribute {
40    pub since: Option<String>,
41    pub note: Option<String>,
42}
43
44impl DeprecatedAttribute {
45    /// Returns `None` if the given attribute was not a valid form of the `#[deprecated]` attribute.
46    pub fn from_meta(meta: &Meta) -> syn::Result<Self> {
47        if meta.path() != &parse_quote!(deprecated) {
48            return Err(syn::Error::new(
49                meta.span(),
50                "attribute path is not `deprecated`",
51            ));
52        }
53
54        match &meta {
55            Meta::Path(_) => Ok(Self::default()),
56            Meta::NameValue(name_value) => {
57                let Expr::Lit(expr_lit) = &name_value.value else {
58                    return Err(syn::Error::new(
59                        name_value.span(),
60                        "literal in `deprecated` value must be a string",
61                    ));
62                };
63
64                Ok(Self {
65                    since: None,
66                    note: lit_to_string(expr_lit.lit.clone()).map(|s| s.trim().to_string()),
67                })
68            }
69            Meta::List(list) => {
70                let parsed = list.parse_args::<DeprecatedAttributeArgsParser>()?;
71
72                Ok(Self {
73                    since: parsed.since.map(|s| s.trim().to_string()),
74                    note: parsed.note.map(|s| s.trim().to_string()),
75                })
76            }
77        }
78    }
79}
80
81mod kw {
82    use syn::custom_keyword;
83    custom_keyword!(since);
84    custom_keyword!(note);
85}
86
87struct DeprecatedAttributeArgsParser {
88    since: Option<String>,
89    note: Option<String>,
90}
91
92impl Parse for DeprecatedAttributeArgsParser {
93    fn parse(input: ParseStream) -> syn::Result<Self> {
94        let mut since: Option<String> = None;
95        let mut note: Option<String> = None;
96
97        if input.peek(kw::since) {
98            input.parse::<kw::since>()?;
99            input.parse::<Token![=]>()?;
100
101            since = lit_to_string(input.parse()?);
102        }
103
104        if input.peek(Token![,]) && input.peek2(kw::note) {
105            input.parse::<Token![,]>()?;
106            input.parse::<kw::note>()?;
107            input.parse::<Token![=]>()?;
108
109            note = lit_to_string(input.parse()?);
110        }
111
112        Ok(Self { since, note })
113    }
114}