1 | use core::{ |
2 | convert::TryFrom, |
3 | fmt::{self, Debug, Display, Formatter}, |
4 | panic, str, |
5 | }; |
6 | use serde::{ |
7 | de::{Deserialize, Deserializer, Visitor}, |
8 | ser::{Serialize, Serializer}, |
9 | }; |
10 | use static_assertions::assert_impl_all; |
11 | use std::{ |
12 | ops::{Bound, RangeBounds}, |
13 | sync::Arc, |
14 | }; |
15 | |
16 | use crate::{signature_parser::SignatureParser, Basic, EncodingFormat, Error, Result, Type}; |
17 | |
18 | // A data type similar to Cow and [`bytes::Bytes`] but unlike the former won't allow us to only keep |
19 | // the owned bytes in Arc and latter doesn't have a notion of borrowed data and would require API |
20 | // breakage. |
21 | // |
22 | // [`bytes::Bytes`]: https://docs.rs/bytes/0.5.6/bytes/struct.Bytes.html |
23 | #[derive (PartialEq, Eq, Hash, Clone)] |
24 | enum Bytes<'b> { |
25 | Borrowed(&'b [u8]), |
26 | Static(&'static [u8]), |
27 | Owned(Arc<[u8]>), |
28 | } |
29 | |
30 | impl<'b> Bytes<'b> { |
31 | const fn borrowed<'s: 'b>(bytes: &'s [u8]) -> Self { |
32 | Self::Borrowed(bytes) |
33 | } |
34 | |
35 | fn owned(bytes: Vec<u8>) -> Self { |
36 | Self::Owned(bytes.into()) |
37 | } |
38 | } |
39 | |
40 | impl<'b> std::ops::Deref for Bytes<'b> { |
41 | type Target = [u8]; |
42 | |
43 | fn deref(&self) -> &[u8] { |
44 | match self { |
45 | Bytes::Borrowed(borrowed: &&[u8]) => borrowed, |
46 | Bytes::Static(borrowed: &&[u8]) => borrowed, |
47 | Bytes::Owned(owned: &Arc<[u8]>) => owned, |
48 | } |
49 | } |
50 | } |
51 | |
52 | /// String that [identifies] the type of an encoded value. |
53 | /// |
54 | /// # Examples |
55 | /// |
56 | /// ``` |
57 | /// use core::convert::TryFrom; |
58 | /// use zvariant::Signature; |
59 | /// |
60 | /// // Valid signatures |
61 | /// let s = Signature::try_from("" ).unwrap(); |
62 | /// assert_eq!(s, "" ); |
63 | /// let s = Signature::try_from("y" ).unwrap(); |
64 | /// assert_eq!(s, "y" ); |
65 | /// let s = Signature::try_from("xs" ).unwrap(); |
66 | /// assert_eq!(s, "xs" ); |
67 | /// let s = Signature::try_from("(ysa{sd})" ).unwrap(); |
68 | /// assert_eq!(s, "(ysa{sd})" ); |
69 | /// let s = Signature::try_from("a{sd}" ).unwrap(); |
70 | /// assert_eq!(s, "a{sd}" ); |
71 | /// |
72 | /// // Invalid signatures |
73 | /// Signature::try_from("z" ).unwrap_err(); |
74 | /// Signature::try_from("(xs" ).unwrap_err(); |
75 | /// Signature::try_from("xs)" ).unwrap_err(); |
76 | /// Signature::try_from("s/" ).unwrap_err(); |
77 | /// Signature::try_from("a" ).unwrap_err(); |
78 | /// Signature::try_from("a{yz}" ).unwrap_err(); |
79 | /// ``` |
80 | /// |
81 | /// This is implemented so that multiple instances can share the same underlying signature string. |
82 | /// Use [`slice`] method to create new signature that represents a portion of a signature |
83 | /// |
84 | /// [identifies]: https://dbus.freedesktop.org/doc/dbus-specification.html#type-system |
85 | /// [`slice`]: #method.slice |
86 | #[derive (Eq, Hash, Clone)] |
87 | pub struct Signature<'a> { |
88 | bytes: Bytes<'a>, |
89 | pos: usize, |
90 | end: usize, |
91 | } |
92 | |
93 | assert_impl_all!(Signature<'_>: Send, Sync, Unpin); |
94 | |
95 | impl<'a> Signature<'a> { |
96 | /// The signature as a string. |
97 | pub fn as_str(&self) -> &str { |
98 | // SAFETY: non-UTF8 characters in Signature are rejected by safe constructors |
99 | unsafe { str::from_utf8_unchecked(self.as_bytes()) } |
100 | } |
101 | |
102 | /// The signature bytes. |
103 | pub fn as_bytes(&self) -> &[u8] { |
104 | &self.bytes[self.pos..self.end] |
105 | } |
106 | |
107 | /// Create a new Signature from given bytes. |
108 | /// |
109 | /// Since the passed bytes are not checked for correctness, it's provided for ease of |
110 | /// `Type` implementations. |
111 | /// |
112 | /// # Safety |
113 | /// |
114 | /// This method is unsafe as it allows creating a `str` that is not valid UTF-8. |
115 | pub unsafe fn from_bytes_unchecked<'s: 'a>(bytes: &'s [u8]) -> Self { |
116 | Self { |
117 | bytes: Bytes::borrowed(bytes), |
118 | pos: 0, |
119 | end: bytes.len(), |
120 | } |
121 | } |
122 | |
123 | /// Same as `from_bytes_unchecked`, except it takes a static reference. |
124 | /// |
125 | /// # Safety |
126 | /// |
127 | /// This method is unsafe as it allows creating a `str` that is not valid UTF-8. |
128 | pub unsafe fn from_static_bytes_unchecked(bytes: &'static [u8]) -> Self { |
129 | Self { |
130 | bytes: Bytes::Static(bytes), |
131 | pos: 0, |
132 | end: bytes.len(), |
133 | } |
134 | } |
135 | |
136 | /// Same as `from_bytes_unchecked`, except it takes a string reference. |
137 | pub const fn from_str_unchecked<'s: 'a>(signature: &'s str) -> Self { |
138 | Self { |
139 | bytes: Bytes::borrowed(signature.as_bytes()), |
140 | pos: 0, |
141 | end: signature.len(), |
142 | } |
143 | } |
144 | |
145 | /// Same as `from_str_unchecked`, except it takes a static string reference. |
146 | pub const fn from_static_str_unchecked(signature: &'static str) -> Self { |
147 | Self { |
148 | bytes: Bytes::Static(signature.as_bytes()), |
149 | pos: 0, |
150 | end: signature.len(), |
151 | } |
152 | } |
153 | |
154 | /// Same as `from_str_unchecked`, except it takes an owned `String`. |
155 | pub fn from_string_unchecked(signature: String) -> Self { |
156 | let bytes = signature.into_bytes(); |
157 | let end = bytes.len(); |
158 | |
159 | Self { |
160 | bytes: Bytes::owned(bytes), |
161 | pos: 0, |
162 | end, |
163 | } |
164 | } |
165 | |
166 | /// Same as `from_static_str_unchecked`, except it checks validity of the signature. |
167 | /// |
168 | /// It's recommended to use this method instead of `TryFrom<&str>` implementation for |
169 | /// `&'static str`. The former will ensure that [`Signature::to_owned`] and |
170 | /// [`Signature::into_owned`] do not clone the underlying bytes. |
171 | pub fn from_static_str(signature: &'static str) -> Result<Self> { |
172 | let bytes = signature.as_bytes(); |
173 | ensure_correct_signature_str(bytes)?; |
174 | |
175 | Ok(Self { |
176 | bytes: Bytes::Static(bytes), |
177 | pos: 0, |
178 | end: signature.len(), |
179 | }) |
180 | } |
181 | |
182 | /// Same as `from_static_bytes_unchecked`, except it checks validity of the signature. |
183 | /// |
184 | /// It's recommended to use this method instead of the `TryFrom<&[u8]>` implementation for |
185 | /// `&'static [u8]`. The former will ensure that [`Signature::to_owned`] and |
186 | /// [`Signature::into_owned`] do not clone the underlying bytes. |
187 | pub fn from_static_bytes(bytes: &'static [u8]) -> Result<Self> { |
188 | ensure_correct_signature_str(bytes)?; |
189 | |
190 | Ok(Self { |
191 | bytes: Bytes::Static(bytes), |
192 | pos: 0, |
193 | end: bytes.len(), |
194 | }) |
195 | } |
196 | |
197 | /// the signature's length. |
198 | pub fn len(&self) -> usize { |
199 | self.end - self.pos |
200 | } |
201 | |
202 | /// if the signature is empty. |
203 | pub fn is_empty(&self) -> bool { |
204 | self.as_bytes().is_empty() |
205 | } |
206 | |
207 | /// Creates an owned clone of `self`. |
208 | pub fn to_owned(&self) -> Signature<'static> { |
209 | match &self.bytes { |
210 | Bytes::Borrowed(_) => { |
211 | let bytes = Bytes::owned(self.as_bytes().to_vec()); |
212 | let pos = 0; |
213 | let end = bytes.len(); |
214 | |
215 | Signature { bytes, pos, end } |
216 | } |
217 | Bytes::Static(b) => Signature { |
218 | bytes: Bytes::Static(b), |
219 | pos: self.pos, |
220 | end: self.end, |
221 | }, |
222 | Bytes::Owned(owned) => Signature { |
223 | bytes: Bytes::Owned(owned.clone()), |
224 | pos: self.pos, |
225 | end: self.end, |
226 | }, |
227 | } |
228 | } |
229 | |
230 | /// Creates an owned clone of `self`. |
231 | pub fn into_owned(self) -> Signature<'static> { |
232 | self.to_owned() |
233 | } |
234 | |
235 | /// Returns a slice of `self` for the provided range. |
236 | /// |
237 | /// # Panics |
238 | /// |
239 | /// Requires that begin <= end and end <= self.len(), otherwise slicing will panic. |
240 | #[must_use ] |
241 | pub fn slice(&self, range: impl RangeBounds<usize>) -> Self { |
242 | let len = self.len(); |
243 | |
244 | let pos = match range.start_bound() { |
245 | Bound::Included(&n) => n, |
246 | Bound::Excluded(&n) => n + 1, |
247 | Bound::Unbounded => 0, |
248 | }; |
249 | |
250 | let end = match range.end_bound() { |
251 | Bound::Included(&n) => n + 1, |
252 | Bound::Excluded(&n) => n, |
253 | Bound::Unbounded => len, |
254 | }; |
255 | |
256 | assert!( |
257 | pos <= end, |
258 | "range start must not be greater than end: {:?} > {:?}" , |
259 | pos, |
260 | end, |
261 | ); |
262 | assert!(end <= len, "range end out of bounds: {:?} > {:?}" , end, len,); |
263 | |
264 | if end == pos { |
265 | return Self::from_str_unchecked("" ); |
266 | } |
267 | |
268 | let mut clone = self.clone(); |
269 | clone.pos += pos; |
270 | clone.end = self.pos + end; |
271 | |
272 | clone |
273 | } |
274 | } |
275 | |
276 | impl<'a> Debug for Signature<'a> { |
277 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
278 | f.debug_tuple(name:"Signature" ).field(&self.as_str()).finish() |
279 | } |
280 | } |
281 | |
282 | impl<'a> Basic for Signature<'a> { |
283 | const SIGNATURE_CHAR: char = 'g' ; |
284 | const SIGNATURE_STR: &'static str = "g" ; |
285 | |
286 | fn alignment(format: EncodingFormat) -> usize { |
287 | match format { |
288 | EncodingFormat::DBus => 1, |
289 | #[cfg (feature = "gvariant" )] |
290 | EncodingFormat::GVariant => 1, |
291 | } |
292 | } |
293 | } |
294 | |
295 | impl<'a> Type for Signature<'a> { |
296 | fn signature() -> Signature<'static> { |
297 | Signature::from_static_str_unchecked(Self::SIGNATURE_STR) |
298 | } |
299 | } |
300 | |
301 | impl<'a, 'b> From<&'b Signature<'a>> for Signature<'a> { |
302 | fn from(signature: &'b Signature<'a>) -> Signature<'a> { |
303 | signature.clone() |
304 | } |
305 | } |
306 | |
307 | impl<'a> TryFrom<&'a [u8]> for Signature<'a> { |
308 | type Error = Error; |
309 | |
310 | fn try_from(value: &'a [u8]) -> Result<Self> { |
311 | ensure_correct_signature_str(signature:value)?; |
312 | |
313 | // SAFETY: ensure_correct_signature_str checks UTF8 |
314 | unsafe { Ok(Self::from_bytes_unchecked(bytes:value)) } |
315 | } |
316 | } |
317 | |
318 | /// Try to create a Signature from a string. |
319 | impl<'a> TryFrom<&'a str> for Signature<'a> { |
320 | type Error = Error; |
321 | |
322 | fn try_from(value: &'a str) -> Result<Self> { |
323 | Self::try_from(value.as_bytes()) |
324 | } |
325 | } |
326 | |
327 | impl<'a> TryFrom<String> for Signature<'a> { |
328 | type Error = Error; |
329 | |
330 | fn try_from(value: String) -> Result<Self> { |
331 | ensure_correct_signature_str(signature:value.as_bytes())?; |
332 | |
333 | Ok(Self::from_string_unchecked(signature:value)) |
334 | } |
335 | } |
336 | |
337 | impl<'a> From<Signature<'a>> for String { |
338 | fn from(value: Signature<'a>) -> String { |
339 | String::from(value.as_str()) |
340 | } |
341 | } |
342 | |
343 | impl<'a> From<&Signature<'a>> for String { |
344 | fn from(value: &Signature<'a>) -> String { |
345 | String::from(value.as_str()) |
346 | } |
347 | } |
348 | |
349 | impl<'a> std::ops::Deref for Signature<'a> { |
350 | type Target = str; |
351 | |
352 | fn deref(&self) -> &Self::Target { |
353 | self.as_str() |
354 | } |
355 | } |
356 | |
357 | impl<'a, 'b> PartialEq<Signature<'a>> for Signature<'b> { |
358 | fn eq(&self, other: &Signature<'_>) -> bool { |
359 | self.as_bytes() == other.as_bytes() |
360 | } |
361 | } |
362 | |
363 | impl<'a> PartialEq<str> for Signature<'a> { |
364 | fn eq(&self, other: &str) -> bool { |
365 | self.as_bytes() == other.as_bytes() |
366 | } |
367 | } |
368 | |
369 | impl<'a> PartialEq<&str> for Signature<'a> { |
370 | fn eq(&self, other: &&str) -> bool { |
371 | self.as_bytes() == other.as_bytes() |
372 | } |
373 | } |
374 | |
375 | impl<'a> Display for Signature<'a> { |
376 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
377 | std::fmt::Display::fmt(&self.as_str(), f) |
378 | } |
379 | } |
380 | |
381 | impl<'a> Serialize for Signature<'a> { |
382 | fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error> |
383 | where |
384 | S: Serializer, |
385 | { |
386 | serializer.serialize_str(self.as_str()) |
387 | } |
388 | } |
389 | |
390 | impl<'de: 'a, 'a> Deserialize<'de> for Signature<'a> { |
391 | fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error> |
392 | where |
393 | D: Deserializer<'de>, |
394 | { |
395 | let visitor: SignatureVisitor = SignatureVisitor; |
396 | |
397 | deserializer.deserialize_str(visitor) |
398 | } |
399 | } |
400 | |
401 | struct SignatureVisitor; |
402 | |
403 | impl<'de> Visitor<'de> for SignatureVisitor { |
404 | type Value = Signature<'de>; |
405 | |
406 | fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
407 | formatter.write_str(data:"a Signature" ) |
408 | } |
409 | |
410 | #[inline ] |
411 | fn visit_borrowed_str<E>(self, value: &'de str) -> core::result::Result<Signature<'de>, E> |
412 | where |
413 | E: serde::de::Error, |
414 | { |
415 | Signature::try_from(value).map_err(op:serde::de::Error::custom) |
416 | } |
417 | } |
418 | |
419 | fn ensure_correct_signature_str(signature: &[u8]) -> Result<()> { |
420 | if signature.len() > 255 { |
421 | return Err(serde::de::Error::invalid_length( |
422 | signature.len(), |
423 | &"<= 255 characters" , |
424 | )); |
425 | } |
426 | |
427 | if signature.is_empty() { |
428 | return Ok(()); |
429 | } |
430 | |
431 | // SAFETY: SignatureParser never calls as_str |
432 | let signature: Signature<'_> = unsafe { Signature::from_bytes_unchecked(bytes:signature) }; |
433 | let mut parser: SignatureParser<'_> = SignatureParser::new(signature); |
434 | while !parser.done() { |
435 | let _ = parser.parse_next_signature()?; |
436 | } |
437 | |
438 | Ok(()) |
439 | } |
440 | |
441 | /// Owned [`Signature`](struct.Signature.html) |
442 | #[derive (Debug, Clone, PartialEq, Eq, serde::Serialize, Type)] |
443 | pub struct OwnedSignature(Signature<'static>); |
444 | |
445 | assert_impl_all!(OwnedSignature: Send, Sync, Unpin); |
446 | |
447 | impl OwnedSignature { |
448 | pub fn into_inner(self) -> Signature<'static> { |
449 | self.0 |
450 | } |
451 | } |
452 | |
453 | impl std::ops::Deref for OwnedSignature { |
454 | type Target = Signature<'static>; |
455 | |
456 | fn deref(&self) -> &Self::Target { |
457 | &self.0 |
458 | } |
459 | } |
460 | |
461 | impl std::convert::From<OwnedSignature> for Signature<'static> { |
462 | fn from(o: OwnedSignature) -> Self { |
463 | o.into_inner() |
464 | } |
465 | } |
466 | |
467 | impl<'a> std::convert::From<Signature<'a>> for OwnedSignature { |
468 | fn from(o: Signature<'a>) -> Self { |
469 | OwnedSignature(o.into_owned()) |
470 | } |
471 | } |
472 | |
473 | impl std::convert::From<OwnedSignature> for crate::Value<'static> { |
474 | fn from(o: OwnedSignature) -> Self { |
475 | o.into_inner().into() |
476 | } |
477 | } |
478 | |
479 | impl<'de> Deserialize<'de> for OwnedSignature { |
480 | fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error> |
481 | where |
482 | D: Deserializer<'de>, |
483 | { |
484 | let visitor: SignatureVisitor = SignatureVisitor; |
485 | |
486 | deserializer |
487 | .deserialize_str(visitor) |
488 | .map(|v: Signature<'_>| OwnedSignature(v.to_owned())) |
489 | } |
490 | } |
491 | |
492 | impl std::fmt::Display for OwnedSignature { |
493 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
494 | std::fmt::Display::fmt(&self.as_str(), f) |
495 | } |
496 | } |
497 | |
498 | #[cfg (test)] |
499 | mod tests { |
500 | use super::Signature; |
501 | |
502 | #[test ] |
503 | fn signature_slicing() { |
504 | let sig = Signature::from_str_unchecked("(asta{sv})" ); |
505 | assert_eq!(sig, "(asta{sv})" ); |
506 | |
507 | let slice = sig.slice(1..); |
508 | assert_eq!(slice.len(), sig.len() - 1); |
509 | assert_eq!(slice, &sig[1..]); |
510 | assert_eq!(slice.as_bytes()[1], b's' ); |
511 | assert_eq!(slice.as_bytes()[2], b't' ); |
512 | |
513 | let slice = slice.slice(2..3); |
514 | assert_eq!(slice.len(), 1); |
515 | assert_eq!(slice, "t" ); |
516 | assert_eq!(slice.slice(1..), "" ); |
517 | } |
518 | } |
519 | |