use serde::{Deserialize, Serialize};
use crate::{Event, Parser};
#[derive(Clone, Debug, PartialEq)]
pub struct Tagged<T> {
pub tag: Option<u64>,
pub value: T,
}
impl<T> Tagged<T> {
pub const fn new(tag: Option<u64>, value: T) -> Self {
Self { tag, value }
}
pub const fn with_tag(tag: u64, value: T) -> Self {
Self::new(Some(tag), value)
}
}
impl<T: Serialize> Serialize for Tagged<T> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::Error as _;
let Some(tag) = self.tag else {
return self.value.serialize(serializer);
};
let mut bytes = crate::to_vec(&self.value).map_err(S::Error::custom)?;
let mut header = [0; 9];
let header_len = encode_tag_header(tag, &mut header);
let payload_len = bytes.len();
bytes.resize(payload_len + header_len, 0);
bytes.copy_within(..payload_len, header_len);
bytes[..header_len].copy_from_slice(&header[..header_len]);
serializer
.serialize_newtype_struct(crate::value::VALUE_MARKER, &serde_bytes::Bytes::new(&bytes))
}
}
impl<'de, T: serde::de::DeserializeOwned> Deserialize<'de> for Tagged<T> {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_newtype_struct(
crate::value::VALUE_MARKER,
TaggedVisitor(core::marker::PhantomData),
)
}
}
struct TaggedVisitor<T>(core::marker::PhantomData<T>);
impl<'de, T: serde::de::DeserializeOwned> serde::de::Visitor<'de> for TaggedVisitor<T> {
type Value = Tagged<T>;
fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter.write_str("an encoded CBOR value with an optional semantic tag")
}
fn visit_newtype_struct<D: serde::Deserializer<'de>>(
self,
deserializer: D,
) -> Result<Self::Value, D::Error> {
deserializer.deserialize_bytes(self)
}
fn visit_borrowed_bytes<E: serde::de::Error>(self, bytes: &'de [u8]) -> Result<Self::Value, E> {
decode_tagged(bytes)
}
fn visit_bytes<E: serde::de::Error>(self, bytes: &[u8]) -> Result<Self::Value, E> {
decode_tagged(bytes)
}
fn visit_byte_buf<E: serde::de::Error>(
self,
bytes: alloc::vec::Vec<u8>,
) -> Result<Self::Value, E> {
decode_tagged(&bytes)
}
}
fn decode_tagged<T: serde::de::DeserializeOwned, E: serde::de::Error>(
bytes: &[u8],
) -> Result<Tagged<T>, E> {
let mut parser = Parser::new(bytes);
let tag = match parser.next().transpose().map_err(E::custom)? {
Some(Event::Tag(tag)) => Some(tag),
_ => None,
};
let payload = tag.map_or(bytes, |_| parser.remaining());
crate::from_slice(payload)
.map(|value| Tagged { tag, value })
.map_err(E::custom)
}
fn encode_tag_header(tag: u64, output: &mut [u8; 9]) -> usize {
if tag < 24 {
output[0] = 0xc0 | tag as u8;
1
} else if tag <= u8::MAX as u64 {
output[0] = 0xd8;
output[1] = tag as u8;
2
} else if tag <= u16::MAX as u64 {
output[0] = 0xd9;
output[1..3].copy_from_slice(&(tag as u16).to_be_bytes());
3
} else if tag <= u32::MAX as u64 {
output[0] = 0xda;
output[1..5].copy_from_slice(&(tag as u32).to_be_bytes());
5
} else {
output[0] = 0xdb;
output[1..].copy_from_slice(&tag.to_be_bytes());
9
}
}