use crate::{CborError, DecodeLimits, ErrorCode};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CanonicalCborRef<'a> {
bytes: &'a [u8],
}
impl<'a> CanonicalCborRef<'a> {
#[inline]
pub(crate) const fn new(bytes: &'a [u8]) -> Self {
Self { bytes }
}
#[inline]
#[must_use]
pub const fn as_bytes(self) -> &'a [u8] {
self.bytes
}
#[cfg(feature = "unsafe")]
#[cfg_attr(docsrs, doc(cfg(feature = "unsafe")))]
#[inline]
#[must_use]
pub const unsafe fn from_canonical(bytes: &'a [u8]) -> Self {
Self { bytes }
}
#[inline]
#[must_use]
pub const fn len(self) -> usize {
self.bytes.len()
}
#[inline]
#[must_use]
pub const fn is_empty(self) -> bool {
self.bytes.is_empty()
}
#[cfg(feature = "sha2")]
#[cfg_attr(docsrs, doc(cfg(feature = "sha2")))]
#[must_use]
pub fn sha256(self) -> [u8; 32] {
use sha2::{Digest, Sha256};
let mut h = Sha256::new();
h.update(self.bytes);
let out = h.finalize();
let mut digest = [0u8; 32];
digest.copy_from_slice(out.as_slice());
digest
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn to_owned(self) -> Result<CanonicalCbor, CborError> {
use crate::alloc_util::try_vec_from_slice;
Ok(CanonicalCbor {
bytes: try_vec_from_slice(self.bytes, 0)?,
})
}
#[inline]
#[must_use]
pub fn bytes_eq(self, other: Self) -> bool {
self.bytes == other.bytes
}
}
impl AsRef<[u8]> for CanonicalCborRef<'_> {
fn as_ref(&self) -> &[u8] {
self.bytes
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EncodedTextKey<'a> {
bytes: &'a [u8],
}
impl<'a> EncodedTextKey<'a> {
#[cfg(feature = "alloc")]
#[inline]
pub(crate) const fn new_unchecked(bytes: &'a [u8]) -> Self {
Self { bytes }
}
pub fn parse(bytes: &'a [u8]) -> Result<Self, CborError> {
if bytes.is_empty() {
return Err(CborError::new(ErrorCode::UnexpectedEof, 0));
}
let limits = DecodeLimits::for_bytes(bytes.len());
crate::validate_canonical(bytes, limits)?;
if bytes[0] >> 5 != 3 {
return Err(CborError::new(ErrorCode::MapKeyMustBeText, 0));
}
Ok(Self { bytes })
}
#[inline]
#[must_use]
pub const fn as_bytes(self) -> &'a [u8] {
self.bytes
}
}
impl AsRef<[u8]> for EncodedTextKey<'_> {
fn as_ref(&self) -> &[u8] {
self.bytes
}
}
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CanonicalCbor {
bytes: Vec<u8>,
}
#[cfg(feature = "alloc")]
impl CanonicalCbor {
#[inline]
pub(crate) const fn new_unchecked(bytes: Vec<u8>) -> Self {
Self { bytes }
}
#[inline]
#[must_use]
pub fn bytes_eq(&self, other: &Self) -> bool {
self.bytes == other.bytes
}
pub fn from_slice(bytes: &[u8], limits: DecodeLimits) -> Result<Self, CborError> {
let canon = crate::validate_canonical(bytes, limits)?;
canon.to_owned()
}
pub fn from_vec(bytes: Vec<u8>, limits: DecodeLimits) -> Result<Self, CborError> {
crate::validate_canonical(&bytes, limits)?;
Ok(Self { bytes })
}
pub fn from_vec_default_limits(bytes: Vec<u8>) -> Result<Self, CborError> {
let limits = DecodeLimits::for_bytes(bytes.len());
Self::from_vec(bytes, limits)
}
#[inline]
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
#[inline]
#[must_use]
pub fn as_ref(&self) -> CanonicalCborRef<'_> {
CanonicalCborRef::new(self.as_bytes())
}
#[inline]
#[must_use]
pub fn into_bytes(self) -> Vec<u8> {
self.bytes
}
#[cfg(feature = "sha2")]
#[cfg_attr(docsrs, doc(cfg(feature = "sha2")))]
#[must_use]
pub fn sha256(&self) -> [u8; 32] {
CanonicalCborRef::new(&self.bytes).sha256()
}
}
#[cfg(feature = "alloc")]
impl AsRef<[u8]> for CanonicalCbor {
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
#[cfg(feature = "serde")]
mod serde_impls {
use super::{CanonicalCbor, CanonicalCborRef};
use crate::{validate_canonical, DecodeLimits};
use serde::de::{Error as DeError, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
impl Serialize for CanonicalCborRef<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_bytes(self.as_bytes())
}
}
#[cfg(feature = "alloc")]
impl Serialize for CanonicalCbor {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_bytes(self.as_bytes())
}
}
#[cfg(feature = "alloc")]
impl<'de> Deserialize<'de> for CanonicalCbor {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct V;
impl<'de> Visitor<'de> for V {
type Value = CanonicalCbor;
fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "canonical CBOR bytes")
}
fn visit_byte_buf<E: DeError>(
self,
v: alloc::vec::Vec<u8>,
) -> Result<Self::Value, E> {
let limits = DecodeLimits::for_bytes(v.len());
validate_canonical(&v, limits).map_err(E::custom)?;
Ok(CanonicalCbor::new_unchecked(v))
}
fn visit_borrowed_bytes<E: DeError>(self, v: &'de [u8]) -> Result<Self::Value, E> {
let limits = DecodeLimits::for_bytes(v.len());
validate_canonical(v, limits).map_err(E::custom)?;
let out = crate::alloc_util::try_vec_from_slice(v, 0).map_err(E::custom)?;
Ok(CanonicalCbor::new_unchecked(out))
}
}
deserializer.deserialize_bytes(V)
}
}
}