Skip to main content

zbus_macros/
utils.rs

1use std::fmt::Display;
2
3use proc_macro_crate::{FoundCrate, crate_name};
4use proc_macro2::{Span, TokenStream};
5use quote::{format_ident, quote};
6use syn::{Attribute, FnArg, Ident, Pat, PatIdent, PatType};
7
8/// Parses the `crate` attribute value into a path.
9pub fn parse_crate_path(crate_attr: Option<&str>) -> Result<Option<syn::Path>, syn::Error> {
10    crate_attr.map(syn::parse_str).transpose()
11}
12
13/// Returns the path to the zbus crate.
14///
15/// If a custom crate path is provided via the `crate` attribute, it will be used.
16/// Otherwise, uses `proc-macro-crate` to detect the crate name.
17pub fn zbus_path(crate_path: Option<&syn::Path>) -> TokenStream {
18    if let Some(path) = crate_path {
19        quote! { ::#path }
20    } else if let Ok(FoundCrate::Name(name)) = crate_name("zbus") {
21        let ident = format_ident!("{}", name);
22        quote! { ::#ident }
23    } else {
24        quote! { ::zbus }
25    }
26}
27
28pub fn typed_arg(arg: &FnArg) -> Option<&PatType> {
29    match arg {
30        FnArg::Typed(t) => Some(t),
31        _ => None,
32    }
33}
34
35pub fn pat_ident(pat: &PatType) -> Option<&Ident> {
36    match &*pat.pat {
37        Pat::Ident(PatIdent { ident, .. }) => Some(ident),
38        _ => None,
39    }
40}
41
42pub fn get_doc_attrs(attrs: &[Attribute]) -> Vec<&Attribute> {
43    attrs.iter().filter(|x| x.path().is_ident("doc")).collect()
44}
45
46// Convert to pascal case, assuming snake case.
47// If `s` is already in pascal case, should yield the same result.
48pub fn pascal_case(s: &str) -> String {
49    let mut pascal = String::new();
50    let mut capitalize = true;
51    for ch in s.chars() {
52        if ch == '_' {
53            capitalize = true;
54        } else if capitalize {
55            pascal.push(ch.to_ascii_uppercase());
56            capitalize = false;
57        } else {
58            pascal.push(ch);
59        }
60    }
61    pascal
62}
63
64pub fn is_blank(s: &str) -> bool {
65    s.trim().is_empty()
66}
67
68/// Standard annotation `org.freedesktop.DBus.Property.EmitsChangedSignal`.
69///
70/// See <https://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format>.
71#[derive(Debug, Default, Clone, PartialEq)]
72pub enum PropertyEmitsChangedSignal {
73    #[default]
74    True,
75    Invalidates,
76    Const,
77    False,
78}
79
80impl Display for PropertyEmitsChangedSignal {
81    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82        let emits_changed_signal = match self {
83            PropertyEmitsChangedSignal::True => "true",
84            PropertyEmitsChangedSignal::Const => "const",
85            PropertyEmitsChangedSignal::False => "false",
86            PropertyEmitsChangedSignal::Invalidates => "invalidates",
87        };
88        write!(f, "{emits_changed_signal}")
89    }
90}
91
92impl PropertyEmitsChangedSignal {
93    pub fn parse(s: &str, span: Span) -> syn::Result<Self> {
94        use PropertyEmitsChangedSignal::*;
95
96        match s {
97            "true" => Ok(True),
98            "invalidates" => Ok(Invalidates),
99            "const" => Ok(Const),
100            "false" => Ok(False),
101            other => Err(syn::Error::new(
102                span,
103                format!("invalid value \"{other}\" for attribute `property(emits_changed_signal)`"),
104            )),
105        }
106    }
107}