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