//! Smith-owned CBOR operations used by JSON content codecs (`SMH-SPEC-SPEC0001`). //! Engine types stay private to this facade. use ciborium_ll::{Decoder as EngineDecoder, Encoder as EngineEncoder, Header as EngineHeader}; #[derive(Clone, Copy, Debug, PartialEq)] pub enum Header { Positive(u64), Negative(u64), Float(f64), Simple(u8), Text(Option), Array(Option), Map(Option), } impl TryFrom for Header { type Error = DecodeError; fn try_from(header: EngineHeader) -> Result { Ok(match header { EngineHeader::Positive(value) => Self::Positive(value), EngineHeader::Negative(value) => Self::Negative(value), EngineHeader::Float(value) => Self::Float(value), EngineHeader::Simple(value) => Self::Simple(value), EngineHeader::Text(length) => Self::Text(length), EngineHeader::Array(length) => Self::Array(length), EngineHeader::Map(length) => Self::Map(length), EngineHeader::Bytes(_) | EngineHeader::Tag(_) | EngineHeader::Break => { return Err(DecodeError); } }) } } impl From
for EngineHeader { fn from(header: Header) -> Self { match header { Header::Positive(value) => Self::Positive(value), Header::Negative(value) => Self::Negative(value), Header::Float(value) => Self::Float(value), Header::Simple(value) => Self::Simple(value), Header::Text(length) => Self::Text(length), Header::Array(length) => Self::Array(length), Header::Map(length) => Self::Map(length), } } } pub trait Write { type Error; fn write_all(&mut self, bytes: &[u8]) -> Result<(), Self::Error>; fn flush(&mut self) -> Result<(), Self::Error>; } struct EngineOutput(W); impl ciborium_io::Write for EngineOutput { type Error = W::Error; fn write_all(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { self.0.write_all(bytes) } fn flush(&mut self) -> Result<(), Self::Error> { self.0.flush() } } pub struct Encoder(EngineEncoder>); impl From for Encoder { fn from(output: W) -> Self { Self(EngineEncoder::from(EngineOutput(output))) } } impl Encoder { #[expect( clippy::large_types_passed_by_value, reason = "the encoder consumes this dependency-shaped fixed-width CBOR tag" )] pub fn push(&mut self, header: Header) -> Result<(), W::Error> { self.0.push(header.into()) } pub fn text(&mut self, value: &str, segment: impl Into>) -> Result<(), W::Error> { self.0.text(value, segment) } } #[derive(Clone, Copy, Debug)] pub struct DecodeError; pub struct Decoder<'a>(EngineDecoder<&'a [u8]>); impl<'a> From<&'a [u8]> for Decoder<'a> { fn from(bytes: &'a [u8]) -> Self { Self(EngineDecoder::from(bytes)) } } impl Decoder<'_> { pub fn pull(&mut self) -> Result { self.0 .pull() .map_err(|_| DecodeError) .and_then(Header::try_from) } pub fn offset(&mut self) -> usize { self.0.offset() } } #[cfg(test)] mod tests { #[test] fn decoder_size_stays_compact() { #[cfg(target_arch = "x86_64")] assert_eq!(std::mem::size_of::>(), 40); } #[test] fn engine_types_do_not_escape_public_facade() { let source = include_str!("cbor.rs"); assert!( !source .lines() .any(|line| line.trim_start().starts_with("pub use ciborium")) ); } }