| //! ASN.1 `OCTET STRING` support. |
| |
| use crate::{ |
| asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind, |
| FixedTag, Header, Length, Reader, Result, Tag, Writer, |
| }; |
| |
| #[cfg(feature = "alloc")] |
| use alloc::vec::Vec; |
| |
| /// ASN.1 `OCTET STRING` type: borrowed form. |
| /// |
| /// Octet strings represent contiguous sequences of octets, a.k.a. bytes. |
| /// |
| /// This is a zero-copy reference type which borrows from the input data. |
| #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] |
| pub struct OctetStringRef<'a> { |
| /// Inner value |
| inner: ByteSlice<'a>, |
| } |
| |
| impl<'a> OctetStringRef<'a> { |
| /// Create a new ASN.1 `OCTET STRING` from a byte slice. |
| pub fn new(slice: &'a [u8]) -> Result<Self> { |
| ByteSlice::new(slice) |
| .map(|inner| Self { inner }) |
| .map_err(|_| ErrorKind::Length { tag: Self::TAG }.into()) |
| } |
| |
| /// Borrow the inner byte slice. |
| pub fn as_bytes(&self) -> &'a [u8] { |
| self.inner.as_slice() |
| } |
| |
| /// Get the length of the inner byte slice. |
| pub fn len(&self) -> Length { |
| self.inner.len() |
| } |
| |
| /// Is the inner byte slice empty? |
| pub fn is_empty(&self) -> bool { |
| self.inner.is_empty() |
| } |
| } |
| |
| impl AsRef<[u8]> for OctetStringRef<'_> { |
| fn as_ref(&self) -> &[u8] { |
| self.as_bytes() |
| } |
| } |
| |
| impl<'a> DecodeValue<'a> for OctetStringRef<'a> { |
| fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { |
| let inner = ByteSlice::decode_value(reader, header)?; |
| Ok(Self { inner }) |
| } |
| } |
| |
| impl EncodeValue for OctetStringRef<'_> { |
| fn value_len(&self) -> Result<Length> { |
| self.inner.value_len() |
| } |
| |
| fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> { |
| self.inner.encode_value(writer) |
| } |
| } |
| |
| impl FixedTag for OctetStringRef<'_> { |
| const TAG: Tag = Tag::OctetString; |
| } |
| |
| impl OrdIsValueOrd for OctetStringRef<'_> {} |
| |
| impl<'a> From<&OctetStringRef<'a>> for OctetStringRef<'a> { |
| fn from(value: &OctetStringRef<'a>) -> OctetStringRef<'a> { |
| *value |
| } |
| } |
| |
| impl<'a> TryFrom<AnyRef<'a>> for OctetStringRef<'a> { |
| type Error = Error; |
| |
| fn try_from(any: AnyRef<'a>) -> Result<OctetStringRef<'a>> { |
| any.decode_into() |
| } |
| } |
| |
| impl<'a> From<OctetStringRef<'a>> for AnyRef<'a> { |
| fn from(octet_string: OctetStringRef<'a>) -> AnyRef<'a> { |
| AnyRef::from_tag_and_value(Tag::OctetString, octet_string.inner) |
| } |
| } |
| |
| impl<'a> From<OctetStringRef<'a>> for &'a [u8] { |
| fn from(octet_string: OctetStringRef<'a>) -> &'a [u8] { |
| octet_string.as_bytes() |
| } |
| } |
| |
| /// ASN.1 `OCTET STRING` type: owned form.. |
| /// |
| /// Octet strings represent contiguous sequences of octets, a.k.a. bytes. |
| /// |
| /// This type provides the same functionality as [`OctetStringRef`] but owns |
| /// the backing data. |
| #[cfg(feature = "alloc")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] |
| #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] |
| pub struct OctetString { |
| /// Bitstring represented as a slice of bytes. |
| inner: Vec<u8>, |
| } |
| |
| #[cfg(feature = "alloc")] |
| impl OctetString { |
| /// Create a new ASN.1 `OCTET STRING`. |
| pub fn new(bytes: impl Into<Vec<u8>>) -> Result<Self> { |
| let inner = bytes.into(); |
| |
| // Ensure the bytes parse successfully as an `OctetStringRef` |
| OctetStringRef::new(&inner)?; |
| |
| Ok(Self { inner }) |
| } |
| |
| /// Borrow the inner byte slice. |
| pub fn as_bytes(&self) -> &[u8] { |
| self.inner.as_slice() |
| } |
| |
| /// Get the length of the inner byte slice. |
| pub fn len(&self) -> Length { |
| self.value_len().expect("invalid OCTET STRING length") |
| } |
| |
| /// Is the inner byte slice empty? |
| pub fn is_empty(&self) -> bool { |
| self.inner.is_empty() |
| } |
| } |
| |
| #[cfg(feature = "alloc")] |
| impl AsRef<[u8]> for OctetString { |
| fn as_ref(&self) -> &[u8] { |
| self.as_bytes() |
| } |
| } |
| |
| #[cfg(feature = "alloc")] |
| impl<'a> DecodeValue<'a> for OctetString { |
| fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { |
| Self::new(reader.read_vec(header.length)?) |
| } |
| } |
| |
| #[cfg(feature = "alloc")] |
| impl EncodeValue for OctetString { |
| fn value_len(&self) -> Result<Length> { |
| self.inner.len().try_into() |
| } |
| |
| fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> { |
| writer.write(&self.inner) |
| } |
| } |
| |
| #[cfg(feature = "alloc")] |
| impl FixedTag for OctetString { |
| const TAG: Tag = Tag::OctetString; |
| } |
| |
| #[cfg(feature = "alloc")] |
| impl<'a> From<&'a OctetString> for OctetStringRef<'a> { |
| fn from(octet_string: &'a OctetString) -> OctetStringRef<'a> { |
| // Ensured to parse successfully in constructor |
| OctetStringRef::new(&octet_string.inner).expect("invalid OCTET STRING") |
| } |
| } |
| |
| #[cfg(feature = "alloc")] |
| impl OrdIsValueOrd for OctetString {} |