zvariant_derive/
signature.rs1use std::str::FromStr;
2
3use proc_macro2::{Literal, TokenStream};
4use quote::quote;
5use syn::{Error, parse::Parse};
6use zvariant_utils::signature::Signature;
7
8pub fn expand_signature_macro(input: TokenStream) -> Result<TokenStream, Error> {
13 let SignatureInput {
14 literal: signature_str,
15 } = syn::parse2(input)?;
16
17 let signature_string = signature_str.to_string();
18 let signature_string = signature_string.trim_matches('"');
19
20 let signature = match signature_string {
21 "dict" => Signature::dict(Signature::Str, Signature::Variant),
22 s => Signature::from_str(s).map_err(|e| Error::new(signature_str.span(), e))?,
23 };
24
25 let signature_tokens = signature_to_tokens(&signature);
26
27 Ok(signature_tokens)
28}
29
30struct SignatureInput {
32 literal: Literal,
33}
34
35impl Parse for SignatureInput {
36 fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
37 Ok(SignatureInput {
38 literal: input.parse()?,
39 })
40 }
41}
42
43pub fn signature_to_tokens(signature: &Signature) -> TokenStream {
48 signature_to_tokens_with_crate(signature, "e! { ::zvariant })
49}
50
51pub fn signature_to_tokens_with_crate(signature: &Signature, zv: &TokenStream) -> TokenStream {
56 match signature {
57 Signature::Unit => quote! { #zv::Signature::Unit },
58 Signature::Bool => quote! { #zv::Signature::Bool },
59 Signature::U8 => quote! { #zv::Signature::U8 },
60 Signature::I16 => quote! { #zv::Signature::I16 },
61 Signature::U16 => quote! { #zv::Signature::U16 },
62 Signature::I32 => quote! { #zv::Signature::I32 },
63 Signature::U32 => quote! { #zv::Signature::U32 },
64 Signature::I64 => quote! { #zv::Signature::I64 },
65 Signature::U64 => quote! { #zv::Signature::U64 },
66 Signature::F64 => quote! { #zv::Signature::F64 },
67 Signature::Str => quote! { #zv::Signature::Str },
68 Signature::Signature => quote! { #zv::Signature::Signature },
69 Signature::ObjectPath => quote! { #zv::Signature::ObjectPath },
70 Signature::Variant => quote! { #zv::Signature::Variant },
71 #[cfg(unix)]
72 Signature::Fd => quote! { #zv::Signature::Fd },
73 Signature::Array(child) => {
74 let signature = signature_to_tokens_with_crate(child.signature(), zv);
75 quote! {
76 #zv::Signature::Array(#zv::signature::Child::Static {
77 child: &#signature,
78 })
79 }
80 }
81 Signature::Dict { key, value } => {
82 let key_sig = signature_to_tokens_with_crate(key.signature(), zv);
83 let value_sig = signature_to_tokens_with_crate(value.signature(), zv);
84 quote! {
85 #zv::Signature::Dict {
86 key: #zv::signature::Child::Static {
87 child: &#key_sig,
88 },
89 value: #zv::signature::Child::Static {
90 child: &#value_sig,
91 },
92 }
93 }
94 }
95 Signature::Structure(fields) => {
96 let fields = fields.iter().map(|f| signature_to_tokens_with_crate(f, zv));
97 quote! {
98 #zv::Signature::Structure(#zv::signature::Fields::Static {
99 fields: &[#(&#fields),*],
100 })
101 }
102 }
103 #[cfg(feature = "gvariant")]
104 Signature::Maybe(child) => {
105 let signature = signature_to_tokens_with_crate(child.signature(), zv);
106 quote! {
107 #zv::Signature::Maybe(#zv::signature::Child::Static {
108 child: &#signature,
109 })
110 }
111 }
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn signature_to_tokens_with_crate_uses_custom_path() {
121 let custom_path = quote! { ::zbus::zvariant };
122 let sig = Signature::Str;
123
124 let tokens = signature_to_tokens_with_crate(&sig, &custom_path).to_string();
125
126 assert!(
127 tokens.contains("zbus"),
128 "Expected custom path in output: {}",
129 tokens
130 );
131 }
132
133 #[test]
134 fn signature_to_tokens_with_crate_uses_custom_path_for_complex_types() {
135 let custom_path = quote! { ::zbus::zvariant };
136
137 let dict_sig = Signature::from_str("a{sv}").unwrap();
139 let tokens = signature_to_tokens_with_crate(&dict_sig, &custom_path).to_string();
140
141 assert!(
143 !tokens.contains(":: zvariant ::") || tokens.contains(":: zbus :: zvariant ::"),
144 "Found bare ::zvariant without ::zbus prefix: {}",
145 tokens
146 );
147 assert!(
148 tokens.contains(":: zbus :: zvariant ::"),
149 "Expected custom path in struct output: {}",
150 tokens
151 );
152
153 let struct_sig = Signature::from_str("(su)").unwrap();
155 let tokens = signature_to_tokens_with_crate(&struct_sig, &custom_path).to_string();
156
157 assert!(
159 tokens.contains("zbus"),
160 "Expected custom path in struct output: {}",
161 tokens
162 );
163 }
164}