1 | use std::slice::SliceIndex; |
2 | |
3 | #[cfg (feature = "gvariant" )] |
4 | use crate::signature_parser::SignatureParser; |
5 | use crate::{Basic, EncodingFormat, Error, ObjectPath, Result, Signature}; |
6 | |
7 | #[cfg (unix)] |
8 | use crate::Fd; |
9 | |
10 | /// The prefix of ARRAY type signature, as a character. Provided for manual signature creation. |
11 | pub const ARRAY_SIGNATURE_CHAR: char = 'a' ; |
12 | /// The prefix of ARRAY type signature, as a string. Provided for manual signature creation. |
13 | pub const ARRAY_SIGNATURE_STR: &str = "a" ; |
14 | pub(crate) const ARRAY_ALIGNMENT_DBUS: usize = 4; |
15 | /// The opening character of STRUCT type signature. Provided for manual signature creation. |
16 | pub const STRUCT_SIG_START_CHAR: char = '(' ; |
17 | /// The closing character of STRUCT type signature. Provided for manual signature creation. |
18 | pub const STRUCT_SIG_END_CHAR: char = ')' ; |
19 | /// The opening character of STRUCT type signature, as a string. Provided for manual signature |
20 | /// creation. |
21 | pub const STRUCT_SIG_START_STR: &str = "(" ; |
22 | /// The closing character of STRUCT type signature, as a string. Provided for manual signature |
23 | /// creation. |
24 | pub const STRUCT_SIG_END_STR: &str = ")" ; |
25 | pub(crate) const STRUCT_ALIGNMENT_DBUS: usize = 8; |
26 | /// The opening character of DICT_ENTRY type signature. Provided for manual signature creation. |
27 | pub const DICT_ENTRY_SIG_START_CHAR: char = '{' ; |
28 | /// The closing character of DICT_ENTRY type signature. Provided for manual signature creation. |
29 | pub const DICT_ENTRY_SIG_END_CHAR: char = '}' ; |
30 | /// The opening character of DICT_ENTRY type signature, as a string. Provided for manual signature |
31 | /// creation. |
32 | pub const DICT_ENTRY_SIG_START_STR: &str = "{" ; |
33 | /// The closing character of DICT_ENTRY type signature, as a string. Provided for manual signature |
34 | /// creation. |
35 | pub const DICT_ENTRY_SIG_END_STR: &str = "}" ; |
36 | pub(crate) const DICT_ENTRY_ALIGNMENT_DBUS: usize = 8; |
37 | /// The VARIANT type signature. Provided for manual signature creation. |
38 | pub const VARIANT_SIGNATURE_CHAR: char = 'v' ; |
39 | /// The VARIANT type signature, as a string. Provided for manual signature creation. |
40 | pub const VARIANT_SIGNATURE_STR: &str = "v" ; |
41 | pub(crate) const VARIANT_ALIGNMENT_DBUS: usize = 1; |
42 | #[cfg (feature = "gvariant" )] |
43 | pub(crate) const VARIANT_ALIGNMENT_GVARIANT: usize = 8; |
44 | /// The prefix of MAYBE (GVariant-specific) type signature, as a character. Provided for manual |
45 | /// signature creation. |
46 | #[cfg (feature = "gvariant" )] |
47 | pub const MAYBE_SIGNATURE_CHAR: char = 'm' ; |
48 | /// The prefix of MAYBE (GVariant-specific) type signature, as a string. Provided for manual |
49 | /// signature creation. |
50 | #[cfg (feature = "gvariant" )] |
51 | pub const MAYBE_SIGNATURE_STR: &str = "m" ; |
52 | |
53 | pub(crate) fn padding_for_n_bytes(value: usize, align: usize) -> usize { |
54 | let len_rounded_up: usize = value.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); |
55 | |
56 | len_rounded_up.wrapping_sub(value) |
57 | } |
58 | |
59 | pub(crate) fn usize_to_u32(value: usize) -> u32 { |
60 | assert!( |
61 | value <= (std::u32::MAX as usize), |
62 | " {} too large for `u32`" , |
63 | value, |
64 | ); |
65 | |
66 | value as u32 |
67 | } |
68 | |
69 | pub(crate) fn usize_to_u8(value: usize) -> u8 { |
70 | assert!( |
71 | value <= (std::u8::MAX as usize), |
72 | " {} too large for `u8`" , |
73 | value, |
74 | ); |
75 | |
76 | value as u8 |
77 | } |
78 | |
79 | pub(crate) fn f64_to_f32(value: f64) -> f32 { |
80 | assert!( |
81 | value <= (std::f32::MAX as f64), |
82 | " {} too large for `f32`" , |
83 | value, |
84 | ); |
85 | |
86 | value as f32 |
87 | } |
88 | |
89 | // `signature` must be **one** complete and correct signature. Expect panics otherwise! |
90 | pub(crate) fn alignment_for_signature( |
91 | signature: &Signature<'_>, |
92 | format: EncodingFormat, |
93 | ) -> Result<usize> { |
94 | let alignment = match signature |
95 | .as_bytes() |
96 | .first() |
97 | .map(|b| *b as char) |
98 | .ok_or_else(|| -> Error { serde::de::Error::invalid_length(0, &">= 1 character" ) })? |
99 | { |
100 | u8::SIGNATURE_CHAR => u8::alignment(format), |
101 | bool::SIGNATURE_CHAR => bool::alignment(format), |
102 | i16::SIGNATURE_CHAR => i16::alignment(format), |
103 | u16::SIGNATURE_CHAR => u16::alignment(format), |
104 | i32::SIGNATURE_CHAR => i32::alignment(format), |
105 | u32::SIGNATURE_CHAR => u32::alignment(format), |
106 | #[cfg (unix)] |
107 | Fd::SIGNATURE_CHAR => u32::alignment(format), |
108 | i64::SIGNATURE_CHAR => i64::alignment(format), |
109 | u64::SIGNATURE_CHAR => u64::alignment(format), |
110 | f64::SIGNATURE_CHAR => f64::alignment(format), |
111 | <&str>::SIGNATURE_CHAR => <&str>::alignment(format), |
112 | ObjectPath::SIGNATURE_CHAR => ObjectPath::alignment(format), |
113 | Signature::SIGNATURE_CHAR => Signature::alignment(format), |
114 | VARIANT_SIGNATURE_CHAR => match format { |
115 | EncodingFormat::DBus => VARIANT_ALIGNMENT_DBUS, |
116 | #[cfg (feature = "gvariant" )] |
117 | EncodingFormat::GVariant => VARIANT_ALIGNMENT_GVARIANT, |
118 | }, |
119 | ARRAY_SIGNATURE_CHAR => alignment_for_array_signature(signature, format)?, |
120 | STRUCT_SIG_START_CHAR => alignment_for_struct_signature(signature, format)?, |
121 | DICT_ENTRY_SIG_START_CHAR => alignment_for_dict_entry_signature(signature, format)?, |
122 | #[cfg (feature = "gvariant" )] |
123 | MAYBE_SIGNATURE_CHAR => alignment_for_maybe_signature(signature, format)?, |
124 | _ => { |
125 | return Err(serde::de::Error::invalid_value( |
126 | serde::de::Unexpected::Str(signature), |
127 | &"a valid signature" , |
128 | )) |
129 | } |
130 | }; |
131 | |
132 | Ok(alignment) |
133 | } |
134 | |
135 | #[cfg (feature = "gvariant" )] |
136 | pub(crate) fn is_fixed_sized_signature<'a>(signature: &'a Signature<'a>) -> Result<bool> { |
137 | match signature |
138 | .as_bytes() |
139 | .first() |
140 | .map(|b| *b as char) |
141 | .ok_or_else(|| -> Error { serde::de::Error::invalid_length(0, &">= 1 character" ) })? |
142 | { |
143 | u8::SIGNATURE_CHAR |
144 | | bool::SIGNATURE_CHAR |
145 | | i16::SIGNATURE_CHAR |
146 | | u16::SIGNATURE_CHAR |
147 | | i32::SIGNATURE_CHAR |
148 | | u32::SIGNATURE_CHAR |
149 | | i64::SIGNATURE_CHAR |
150 | | u64::SIGNATURE_CHAR |
151 | | f64::SIGNATURE_CHAR => Ok(true), |
152 | #[cfg (unix)] |
153 | Fd::SIGNATURE_CHAR => Ok(true), |
154 | STRUCT_SIG_START_CHAR => is_fixed_sized_struct_signature(signature), |
155 | DICT_ENTRY_SIG_START_CHAR => is_fixed_sized_dict_entry_signature(signature), |
156 | _ => Ok(false), |
157 | } |
158 | } |
159 | |
160 | // Given an &str, create an owned (String-based) Signature w/ appropriate capacity |
161 | macro_rules! signature_string { |
162 | ($signature:expr) => {{ |
163 | let mut s = String::with_capacity(255); |
164 | s.push_str($signature); |
165 | |
166 | Signature::from_string_unchecked(s) |
167 | }}; |
168 | } |
169 | |
170 | macro_rules! check_child_value_signature { |
171 | ($expected_signature:expr, $child_signature:expr, $child_name:literal) => {{ |
172 | if $child_signature != $expected_signature { |
173 | let unexpected = format!("{} with signature `{}`" , $child_name, $child_signature,); |
174 | let expected = format!("{} with signature `{}`" , $child_name, $expected_signature); |
175 | |
176 | return Err(serde::de::Error::invalid_type( |
177 | serde::de::Unexpected::Str(&unexpected), |
178 | &expected.as_str(), |
179 | )); |
180 | } |
181 | }}; |
182 | } |
183 | |
184 | fn alignment_for_single_child_type_signature( |
185 | #[allow (unused)] signature: &Signature<'_>, |
186 | format: EncodingFormat, |
187 | dbus_align: usize, |
188 | ) -> Result<usize> { |
189 | match format { |
190 | EncodingFormat::DBus => Ok(dbus_align), |
191 | #[cfg (feature = "gvariant" )] |
192 | EncodingFormat::GVariant => { |
193 | let child_signature = signature.slice(1..); |
194 | |
195 | alignment_for_signature(&child_signature, format) |
196 | } |
197 | } |
198 | } |
199 | |
200 | fn alignment_for_array_signature( |
201 | signature: &Signature<'_>, |
202 | format: EncodingFormat, |
203 | ) -> Result<usize> { |
204 | alignment_for_single_child_type_signature(signature, format, ARRAY_ALIGNMENT_DBUS) |
205 | } |
206 | |
207 | #[cfg (feature = "gvariant" )] |
208 | fn alignment_for_maybe_signature( |
209 | signature: &Signature<'_>, |
210 | format: EncodingFormat, |
211 | ) -> Result<usize> { |
212 | alignment_for_single_child_type_signature(signature, format, 1) |
213 | } |
214 | |
215 | fn alignment_for_struct_signature( |
216 | #[allow (unused)] signature: &Signature<'_>, |
217 | format: EncodingFormat, |
218 | ) -> Result<usize> { |
219 | match format { |
220 | EncodingFormat::DBus => Ok(STRUCT_ALIGNMENT_DBUS), |
221 | #[cfg (feature = "gvariant" )] |
222 | EncodingFormat::GVariant => { |
223 | if signature.len() < 3 { |
224 | return Err(serde::de::Error::invalid_length( |
225 | signature.len(), |
226 | &">= 3 characters in struct signature" , |
227 | )); |
228 | } |
229 | let inner_signature = Signature::from_str_unchecked(&signature[1..signature.len() - 1]); |
230 | let mut sig_parser = SignatureParser::new(inner_signature); |
231 | let mut alignment = 0; |
232 | |
233 | while !sig_parser.done() { |
234 | let child_signature = sig_parser.parse_next_signature()?; |
235 | |
236 | let child_alignment = alignment_for_signature(&child_signature, format)?; |
237 | if child_alignment > alignment { |
238 | alignment = child_alignment; |
239 | |
240 | if alignment == 8 { |
241 | // 8 bytes is max alignment so we can short-circuit here |
242 | break; |
243 | } |
244 | } |
245 | } |
246 | |
247 | Ok(alignment) |
248 | } |
249 | } |
250 | } |
251 | |
252 | fn alignment_for_dict_entry_signature( |
253 | #[allow (unused)] signature: &Signature<'_>, |
254 | format: EncodingFormat, |
255 | ) -> Result<usize> { |
256 | match format { |
257 | EncodingFormat::DBus => Ok(DICT_ENTRY_ALIGNMENT_DBUS), |
258 | #[cfg (feature = "gvariant" )] |
259 | EncodingFormat::GVariant => { |
260 | if signature.len() < 4 { |
261 | return Err(serde::de::Error::invalid_length( |
262 | signature.len(), |
263 | &">= 4 characters in dict entry signature" , |
264 | )); |
265 | } |
266 | let key_signature = Signature::from_str_unchecked(&signature[1..2]); |
267 | let key_alignment = alignment_for_signature(&key_signature, format)?; |
268 | if key_alignment == 8 { |
269 | // 8 bytes is max alignment so we can short-circuit here |
270 | return Ok(8); |
271 | } |
272 | |
273 | let value_signature = Signature::from_str_unchecked(&signature[2..signature.len() - 1]); |
274 | let value_alignment = alignment_for_signature(&value_signature, format)?; |
275 | if value_alignment > key_alignment { |
276 | Ok(value_alignment) |
277 | } else { |
278 | Ok(key_alignment) |
279 | } |
280 | } |
281 | } |
282 | } |
283 | |
284 | #[cfg (feature = "gvariant" )] |
285 | fn is_fixed_sized_struct_signature<'a>(signature: &'a Signature<'a>) -> Result<bool> { |
286 | let inner_signature = Signature::from_str_unchecked(&signature[1..signature.len() - 1]); |
287 | let mut sig_parser = SignatureParser::new(inner_signature); |
288 | let mut fixed_sized = true; |
289 | |
290 | while !sig_parser.done() { |
291 | let child_signature = sig_parser.parse_next_signature()?; |
292 | |
293 | if !is_fixed_sized_signature(&child_signature)? { |
294 | // STRUCT is fixed-sized only if all its children are |
295 | fixed_sized = false; |
296 | |
297 | break; |
298 | } |
299 | } |
300 | |
301 | Ok(fixed_sized) |
302 | } |
303 | |
304 | #[cfg (feature = "gvariant" )] |
305 | fn is_fixed_sized_dict_entry_signature<'a>(signature: &'a Signature<'a>) -> Result<bool> { |
306 | let key_signature = Signature::from_str_unchecked(&signature[1..2]); |
307 | if !is_fixed_sized_signature(&key_signature)? { |
308 | return Ok(false); |
309 | } |
310 | |
311 | let value_signature = Signature::from_str_unchecked(&signature[2..signature.len() - 1]); |
312 | |
313 | is_fixed_sized_signature(&value_signature) |
314 | } |
315 | |
316 | /// Slice the given slice of bytes safely and return an error if the slice is too small. |
317 | pub(crate) fn subslice<I, T>(input: &[T], index: I) -> Result<&I::Output> |
318 | where |
319 | I: SliceIndex<[T]>, |
320 | { |
321 | input.get(index).ok_or(err:Error::OutOfBounds) |
322 | } |
323 | |