diff --git a/zvariant/src/signature.rs b/zvariant/src/signature.rs index c13b43a17..772b6204f 100644 --- a/zvariant/src/signature.rs +++ b/zvariant/src/signature.rs @@ -187,7 +187,7 @@ impl<'a> Signature<'a> { /// [`Signature::into_owned`] do not clone the underlying bytes. pub fn from_static_str(signature: &'static str) -> Result { let bytes = signature.as_bytes(); - ensure_correct_signature_str(bytes)?; + SignatureParser::validate(bytes)?; Ok(Self { bytes: Bytes::Static(bytes), @@ -202,7 +202,7 @@ impl<'a> Signature<'a> { /// `&'static [u8]`. The former will ensure that [`Signature::to_owned`] and /// [`Signature::into_owned`] do not clone the underlying bytes. pub fn from_static_bytes(bytes: &'static [u8]) -> Result { - ensure_correct_signature_str(bytes)?; + SignatureParser::validate(bytes)?; Ok(Self { bytes: Bytes::Static(bytes), @@ -325,9 +325,9 @@ impl<'a> TryFrom<&'a [u8]> for Signature<'a> { type Error = Error; fn try_from(value: &'a [u8]) -> Result { - ensure_correct_signature_str(value)?; + SignatureParser::validate(value)?; - // SAFETY: ensure_correct_signature_str checks UTF8 + // SAFETY: validate checks UTF8 unsafe { Ok(Self::from_bytes_unchecked(value)) } } } @@ -345,7 +345,7 @@ impl<'a> TryFrom for Signature<'a> { type Error = Error; fn try_from(value: String) -> Result { - ensure_correct_signature_str(value.as_bytes())?; + SignatureParser::validate(value.as_bytes())?; Ok(Self::from_string_unchecked(value)) } @@ -433,28 +433,6 @@ impl<'de> Visitor<'de> for SignatureVisitor { } } -fn ensure_correct_signature_str(signature: &[u8]) -> Result<()> { - if signature.len() > 255 { - return Err(serde::de::Error::invalid_length( - signature.len(), - &"<= 255 characters", - )); - } - - if signature.is_empty() { - return Ok(()); - } - - // SAFETY: SignatureParser never calls as_str - let signature = unsafe { Signature::from_bytes_unchecked(signature) }; - let mut parser = SignatureParser::new(signature); - while !parser.done() { - let _ = parser.parse_next_signature()?; - } - - Ok(()) -} - /// Owned [`Signature`](struct.Signature.html) #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, Type)] pub struct OwnedSignature(Signature<'static>); diff --git a/zvariant/src/signature_parser.rs b/zvariant/src/signature_parser.rs index f999dbf6e..37c8937e2 100644 --- a/zvariant/src/signature_parser.rs +++ b/zvariant/src/signature_parser.rs @@ -30,6 +30,26 @@ impl<'s> SignatureParser<'s> { } } + pub(crate) unsafe fn from_bytes_unchecked(signature: &'s [u8]) -> Result { + if signature.len() > 255 { + return Err(serde::de::Error::invalid_length( + signature.len(), + &"<= 255 characters", + )); + } + + let signature = Signature::from_bytes_unchecked(signature); + Ok(Self::new(signature)) + } + + pub fn validate(signature: &'s [u8]) -> Result<()> { + // SAFETY: the parser is only used to validate the signature + for s in unsafe { Self::from_bytes_unchecked(signature)? } { + s?; + } + Ok(()) + } + pub fn signature(&self) -> Signature<'_> { self.signature.slice(self.pos..self.end) } @@ -297,3 +317,15 @@ impl<'s> SignatureParser<'s> { self.signature.slice(self.pos + idx..self.pos + end) } } + +impl<'a> Iterator for SignatureParser<'a> { + type Item = Result>; + + fn next(&mut self) -> Option { + if self.done() { + None + } else { + Some(self.parse_next_signature()) + } + } +}