repositories / smith
smith
There are many coding harnesses - but this one is fast
owned by admin
smith-core/src/cbor.rs
Raw//! 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<usize>),
Array(Option<usize>),
Map(Option<usize>),
}
impl TryFrom<EngineHeader> for Header {
type Error = DecodeError;
fn try_from(header: EngineHeader) -> Result<Self, Self::Error> {
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<Header> 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>(W);
impl<W: Write> ciborium_io::Write for EngineOutput<W> {
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<W: Write>(EngineEncoder<EngineOutput<W>>);
impl<W: Write> From<W> for Encoder<W> {
fn from(output: W) -> Self {
Self(EngineEncoder::from(EngineOutput(output)))
}
}
impl<W: Write> Encoder<W> {
#[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<Option<usize>>) -> 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<Header, DecodeError> {
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::<super::Decoder<'static>>(), 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"))
);
}
}