1use core::{
2 convert::TryFrom,
3 fmt::{self, Debug, Display, Formatter},
4 panic, str,
5};
6use serde::{
7 de::{Deserialize, Deserializer, Visitor},
8 ser::{Serialize, Serializer},
9};
10use static_assertions::assert_impl_all;
11use std::{
12 ops::{Bound, RangeBounds},
13 sync::Arc,
14};
15
16use 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)]
24enum Bytes<'b> {
25 Borrowed(&'b [u8]),
26 Static(&'static [u8]),
27 Owned(Arc<[u8]>),
28}
29
30impl<'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
40impl<'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)]
87pub struct Signature<'a> {
88 bytes: Bytes<'a>,
89 pos: usize,
90 end: usize,
91}
92
93assert_impl_all!(Signature<'_>: Send, Sync, Unpin);
94
95impl<'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
276impl<'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
282impl<'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
295impl<'a> Type for Signature<'a> {
296 fn signature() -> Signature<'static> {
297 Signature::from_static_str_unchecked(Self::SIGNATURE_STR)
298 }
299}
300
301impl<'a, 'b> From<&'b Signature<'a>> for Signature<'a> {
302 fn from(signature: &'b Signature<'a>) -> Signature<'a> {
303 signature.clone()
304 }
305}
306
307impl<'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.
319impl<'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
327impl<'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
337impl<'a> From<Signature<'a>> for String {
338 fn from(value: Signature<'a>) -> String {
339 String::from(value.as_str())
340 }
341}
342
343impl<'a> From<&Signature<'a>> for String {
344 fn from(value: &Signature<'a>) -> String {
345 String::from(value.as_str())
346 }
347}
348
349impl<'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
357impl<'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
363impl<'a> PartialEq<str> for Signature<'a> {
364 fn eq(&self, other: &str) -> bool {
365 self.as_bytes() == other.as_bytes()
366 }
367}
368
369impl<'a> PartialEq<&str> for Signature<'a> {
370 fn eq(&self, other: &&str) -> bool {
371 self.as_bytes() == other.as_bytes()
372 }
373}
374
375impl<'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
381impl<'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
390impl<'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
401struct SignatureVisitor;
402
403impl<'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
419fn 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)]
443pub struct OwnedSignature(Signature<'static>);
444
445assert_impl_all!(OwnedSignature: Send, Sync, Unpin);
446
447impl OwnedSignature {
448 pub fn into_inner(self) -> Signature<'static> {
449 self.0
450 }
451}
452
453impl std::ops::Deref for OwnedSignature {
454 type Target = Signature<'static>;
455
456 fn deref(&self) -> &Self::Target {
457 &self.0
458 }
459}
460
461impl std::convert::From<OwnedSignature> for Signature<'static> {
462 fn from(o: OwnedSignature) -> Self {
463 o.into_inner()
464 }
465}
466
467impl<'a> std::convert::From<Signature<'a>> for OwnedSignature {
468 fn from(o: Signature<'a>) -> Self {
469 OwnedSignature(o.into_owned())
470 }
471}
472
473impl std::convert::From<OwnedSignature> for crate::Value<'static> {
474 fn from(o: OwnedSignature) -> Self {
475 o.into_inner().into()
476 }
477}
478
479impl<'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
492impl 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)]
499mod 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