use alloc::borrow::Cow;
use alloc::vec::Vec;
use nextjson::de::Mark;
use nextjson::Error as NextjsonError;
use nextjson::{FormatDecoder, FormatEncoder, Number, OptionTag, Token};
use crate::{
config::Config,
error::{Error, Result},
tags::MAX_DEPTH,
writer::EncodeWriter,
};
type NextjsonResult<T> = core::result::Result<T, NextjsonError>;
pub(crate) struct CborEncoder<W: EncodeWriter> {
writer: W,
config: Config,
written: u64,
depth: usize,
counts: [u64; MAX_DEPTH],
wire_error: Option<Error>,
}
impl<W: EncodeWriter> CborEncoder<W> {
pub(crate) fn new(writer: W, config: Config) -> Self {
Self {
writer,
config,
written: 0,
depth: 0,
counts: [0; MAX_DEPTH],
wire_error: None,
}
}
pub(crate) fn finish<T: nextjson::NsonSerialize + ?Sized>(mut self, value: &T) -> Result<u64> {
nextjson::NsonSerialize::nextencode(value, &mut self).map_err(|error| {
self.wire_error
.take()
.unwrap_or_else(|| Error::from_nextjson(error))
})?;
if self.depth != 0 {
return Err(Error::Custom(
"encoder finished inside an unclosed container".into(),
));
}
Ok(self.written)
}
fn fail(&mut self, error: Error) -> NextjsonError {
self.wire_error = Some(error);
NextjsonError::custom("rustbinary cbor wire error")
}
fn emit(&mut self, bytes: &[u8]) -> Result<()> {
let amount =
u64::try_from(bytes.len()).map_err(|_| Error::IntegerOverflow { target: "u64" })?;
let next = self
.written
.checked_add(amount)
.ok_or(Error::SizeLimit { limit: u64::MAX })?;
if let Some(limit) = self.config.limit {
if next > limit {
return Err(Error::SizeLimit { limit });
}
}
self.writer.write_all(bytes)?;
self.written = next;
Ok(())
}
fn head(&mut self, major: u8, argument: u64) -> NextjsonResult<()> {
let prefix = major << 5;
let mut buffer = [0_u8; 9];
let len = if argument < 24 {
buffer[0] = prefix | argument as u8;
1
} else if argument <= u8::MAX as u64 {
buffer[0] = prefix | 24;
buffer[1] = argument as u8;
2
} else if argument <= u16::MAX as u64 {
buffer[0] = prefix | 25;
buffer[1..3].copy_from_slice(&(argument as u16).to_be_bytes());
3
} else if argument <= u32::MAX as u64 {
buffer[0] = prefix | 26;
buffer[1..5].copy_from_slice(&(argument as u32).to_be_bytes());
5
} else {
buffer[0] = prefix | 27;
buffer[1..9].copy_from_slice(&argument.to_be_bytes());
9
};
self.emit(&buffer[..len]).map_err(|error| self.fail(error))
}
fn unsigned(&mut self, value: u128) -> NextjsonResult<()> {
match u64::try_from(value) {
Ok(value) => self.head(0, value),
Err(_) => self.bignum(2, value),
}
}
fn signed(&mut self, value: i128) -> NextjsonResult<()> {
if value >= 0 {
return self.unsigned(value as u128);
}
let argument = (-1 - value) as u128;
match u64::try_from(argument) {
Ok(argument) => self.head(1, argument),
Err(_) => self.bignum(3, argument),
}
}
fn bignum(&mut self, tag: u64, value: u128) -> NextjsonResult<()> {
self.head(6, tag)?;
let bytes = value.to_be_bytes();
let first = bytes
.iter()
.position(|byte| *byte != 0)
.unwrap_or(bytes.len() - 1);
let magnitude = &bytes[first..];
self.head(2, magnitude.len() as u64)?;
self.emit(magnitude).map_err(|error| self.fail(error))
}
fn write_text(&mut self, value: &str) -> NextjsonResult<()> {
self.head(3, value.len() as u64)?;
self.emit(value.as_bytes())
.map_err(|error| self.fail(error))
}
fn enter_container(&mut self) -> NextjsonResult<()> {
if self.depth >= MAX_DEPTH {
return Err(self.fail(Error::Custom("encoder nesting depth limit exceeded".into())));
}
self.depth += 1;
Ok(())
}
fn exit_container(&mut self) -> NextjsonResult<()> {
if self.depth == 0 {
return Err(self.fail(Error::Custom("container end without matching start".into())));
}
self.depth -= 1;
self.counts[self.depth] = 0;
self.emit(&[0xff]).map_err(|error| self.fail(error))
}
fn count_element(&mut self) -> NextjsonResult<()> {
let index = self
.depth
.checked_sub(1)
.ok_or_else(|| self.fail(Error::Custom("element outside any container".into())))?;
let count = self.counts[index]
.checked_add(1)
.ok_or_else(|| self.fail(Error::CollectionLimit { limit: u64::MAX }))?;
if let Some(limit) = self.config.collection_limit {
if count > limit {
return Err(self.fail(Error::CollectionLimit { limit }));
}
}
self.counts[index] = count;
Ok(())
}
}
impl<W: EncodeWriter> FormatEncoder for CborEncoder<W> {
type Error = NextjsonError;
fn begin_array(&mut self) -> NextjsonResult<()> {
self.enter_container()?;
self.emit(&[0x9f]).map_err(|error| self.fail(error))
}
fn separator(&mut self) -> NextjsonResult<()> {
self.count_element()
}
fn end_array(&mut self) -> NextjsonResult<()> {
self.exit_container()
}
fn begin_object(&mut self) -> NextjsonResult<()> {
self.enter_container()?;
self.emit(&[0xbf]).map_err(|error| self.fail(error))
}
fn key(&mut self, key: &str) -> NextjsonResult<()> {
self.count_element()?;
self.write_text(key)
}
fn end_object(&mut self) -> NextjsonResult<()> {
self.exit_container()
}
fn write_null(&mut self) -> NextjsonResult<()> {
self.emit(&[0xf6]).map_err(|error| self.fail(error))
}
fn write_bool(&mut self, value: bool) -> NextjsonResult<()> {
self.emit(&[if value { 0xf5 } else { 0xf4 }])
.map_err(|error| self.fail(error))
}
fn write_str(&mut self, value: &str) -> NextjsonResult<()> {
self.write_text(value)
}
fn write_char(&mut self, value: char) -> NextjsonResult<()> {
let mut buffer = [0_u8; 4];
self.write_text(value.encode_utf8(&mut buffer))
}
fn write_number(&mut self, value: &Number) -> NextjsonResult<()> {
match *value {
Number::U64(value) => self.write_u64(value),
Number::U128(value) => self.write_u128(value),
Number::I64(value) => self.write_i64(value),
Number::I128(value) => self.write_i128(value),
Number::F64(value) => self.write_f64(value),
}
}
fn write_i64(&mut self, value: i64) -> NextjsonResult<()> {
self.signed(value as i128)
}
fn write_u64(&mut self, value: u64) -> NextjsonResult<()> {
self.unsigned(value as u128)
}
fn write_i128(&mut self, value: i128) -> NextjsonResult<()> {
self.signed(value)
}
fn write_u128(&mut self, value: u128) -> NextjsonResult<()> {
self.unsigned(value)
}
fn write_f64(&mut self, value: f64) -> NextjsonResult<()> {
self.emit(&[0xfb]).map_err(|error| self.fail(error))?;
self.emit(&value.to_bits().to_be_bytes())
.map_err(|error| self.fail(error))
}
fn write_f32(&mut self, value: f32) -> NextjsonResult<()> {
self.emit(&[0xfa]).map_err(|error| self.fail(error))?;
self.emit(&value.to_bits().to_be_bytes())
.map_err(|error| self.fail(error))
}
fn write_bytes(&mut self, value: &[u8]) -> NextjsonResult<()> {
self.head(2, value.len() as u64)?;
self.emit(value).map_err(|error| self.fail(error))
}
fn write_none(&mut self) -> NextjsonResult<()> {
self.write_null()
}
fn write_some(&mut self) -> NextjsonResult<()> {
Ok(())
}
fn is_human_readable(&self) -> bool {
false
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum ContainerKind {
Array,
Object,
}
#[derive(Clone, Copy, Debug)]
struct Frame {
kind: ContainerKind,
definite: Option<u64>,
}
#[derive(Clone, Copy, Debug)]
enum HeadArg {
Value(u64),
Float16,
Float32,
Float64,
Indefinite,
}
impl HeadArg {
fn value(self) -> u64 {
match self {
HeadArg::Value(value) => value,
_ => unreachable!("non-value argument where a value is required"),
}
}
}
pub(crate) struct CborDecoder<'de> {
input: &'de [u8],
cursor: usize,
config: Config,
depth: usize,
counts: [u64; MAX_DEPTH],
frames: Vec<Frame>,
lookahead: Option<Token<'de>>,
wire_error: Option<Error>,
expecting: Option<&'static str>,
}
impl<'de> CborDecoder<'de> {
pub(crate) fn new(input: &'de [u8], config: Config) -> Self {
Self {
input,
cursor: 0,
config,
depth: 0,
counts: [0; MAX_DEPTH],
frames: Vec::new(),
lookahead: None,
wire_error: None,
expecting: None,
}
}
pub(crate) fn decode<T: nextjson::NsonDeserialize<'de>>(mut self) -> Result<T> {
let value = T::nextdecode(&mut self).map_err(|error| {
self.wire_error
.take()
.unwrap_or_else(|| Error::from_nextjson(error))
})?;
if self.depth != 0 {
return Err(Error::Custom(
"decoder finished inside an unclosed container".into(),
));
}
if self.config.trailing == crate::config::TrailingBytes::Reject
&& self.cursor != self.input.len()
{
return Err(Error::TrailingBytes {
remaining: self.input.len() - self.cursor,
});
}
Ok(value)
}
fn fail(&mut self, error: Error) -> NextjsonError {
self.wire_error = Some(error);
NextjsonError::custom("rustbinary cbor wire error")
}
fn invalid_type(&self, expected: &'static str, found: &Token<'_>) -> NextjsonError {
let expected = match (self.expecting, expected) {
(Some(expecting), "an object" | "an array") => expecting,
_ => expected,
};
NextjsonError::invalid_type(expected, token_name(found))
}
fn take(&mut self, len: usize) -> Result<&'de [u8]> {
let end = self.cursor.checked_add(len).ok_or(Error::UnexpectedEnd)?;
if let Some(limit) = self.config.limit {
if end as u64 > limit {
return Err(Error::SizeLimit { limit });
}
}
let bytes = self
.input
.get(self.cursor..end)
.ok_or(Error::UnexpectedEnd)?;
self.cursor = end;
Ok(bytes)
}
fn peek_byte(&mut self) -> Result<u8> {
let byte = *self.input.get(self.cursor).ok_or(Error::UnexpectedEnd)?;
if let Some(limit) = self.config.limit {
if (self.cursor as u64).saturating_add(1) > limit {
return Err(Error::SizeLimit { limit });
}
}
Ok(byte)
}
fn read_head(&mut self) -> NextjsonResult<(u8, HeadArg)> {
let initial = self.take(1).map_err(|error| self.fail(error))?[0];
let major = initial >> 5;
let ai = initial & 0x1f;
let argument = if major == 7 {
match ai {
0..=23 => HeadArg::Value(ai as u64),
24 => HeadArg::Value(24),
25 => HeadArg::Float16,
26 => HeadArg::Float32,
27 => HeadArg::Float64,
28..=30 => {
return Err(self.fail(Error::Custom(
"reserved CBOR additional information value".into(),
)))
}
31 => HeadArg::Indefinite,
_ => unreachable!("additional information is five bits"),
}
} else {
match ai {
0..=23 => HeadArg::Value(ai as u64),
24 => HeadArg::Value(self.take(1).map_err(|error| self.fail(error))?[0] as u64),
25 => {
let bytes: [u8; 2] = self
.take(2)
.map_err(|error| self.fail(error))?
.try_into()
.expect("two bytes");
HeadArg::Value(u16::from_be_bytes(bytes) as u64)
}
26 => {
let bytes: [u8; 4] = self
.take(4)
.map_err(|error| self.fail(error))?
.try_into()
.expect("four bytes");
HeadArg::Value(u32::from_be_bytes(bytes) as u64)
}
27 => {
let bytes: [u8; 8] = self
.take(8)
.map_err(|error| self.fail(error))?
.try_into()
.expect("eight bytes");
HeadArg::Value(u64::from_be_bytes(bytes))
}
28..=30 => {
return Err(self.fail(Error::Custom(
"reserved CBOR additional information value".into(),
)))
}
31 => HeadArg::Indefinite,
_ => unreachable!("additional information is five bits"),
}
};
Ok((major, argument))
}
fn dec_remaining(&mut self) -> NextjsonResult<()> {
let underflow = match self.frames.last_mut() {
Some(frame) => match &mut frame.definite {
Some(remaining) => match remaining.checked_sub(1) {
Some(next) => {
*remaining = next;
false
}
None => true,
},
None => false,
},
None => false,
};
if underflow {
return Err(self.fail(Error::Custom("too many container elements".into())));
}
Ok(())
}
fn enter_container(
&mut self,
kind: ContainerKind,
definite: Option<u64>,
) -> NextjsonResult<()> {
if self.depth >= MAX_DEPTH {
return Err(self.fail(Error::Custom("decoder nesting depth limit exceeded".into())));
}
if let Some(count) = definite {
if let Some(limit) = self.config.collection_limit {
if count > limit {
return Err(self.fail(Error::CollectionLimit { limit }));
}
}
}
self.frames.push(Frame { kind, definite });
self.depth += 1;
Ok(())
}
fn pop_frame(&mut self, expected: ContainerKind) -> NextjsonResult<()> {
let frame = self.frames.last().copied().ok_or_else(|| {
self.fail(Error::Custom("container end without matching start".into()))
})?;
if frame.kind != expected {
return Err(self.fail(Error::Custom(
"container end does not match its start".into(),
)));
}
self.frames.pop();
self.depth -= 1;
self.counts[self.depth] = 0;
Ok(())
}
fn count_element(&mut self) -> NextjsonResult<()> {
let index = self
.depth
.checked_sub(1)
.ok_or_else(|| self.fail(Error::Custom("separator outside any container".into())))?;
let count = self.counts[index]
.checked_add(1)
.ok_or_else(|| self.fail(Error::CollectionLimit { limit: u64::MAX }))?;
if let Some(limit) = self.config.collection_limit {
if count > limit {
return Err(self.fail(Error::CollectionLimit { limit }));
}
}
self.counts[index] = count;
Ok(())
}
fn has_more(&mut self) -> NextjsonResult<bool> {
if self.lookahead.is_some() {
return Ok(true);
}
let frame = match self.frames.last().copied() {
Some(frame) => frame,
None => return Err(self.fail(Error::Custom("separator outside any container".into()))),
};
match frame.definite {
Some(remaining) => Ok(remaining > 0),
None => Ok(self.peek_byte().map_err(|error| self.fail(error))? != 0xff),
}
}
fn read_token(&mut self) -> NextjsonResult<Token<'de>> {
loop {
let (major, argument) = self.read_head()?;
match major {
0 => {
self.dec_remaining()?;
return Ok(Token::Number(Number::U64(argument.value())));
}
1 => {
self.dec_remaining()?;
let negative = argument.value();
if negative <= i64::MAX as u64 {
return Ok(Token::Number(Number::I64(-1 - negative as i64)));
}
return Ok(Token::Number(Number::I128(-1 - negative as i128)));
}
2 => {
return Err(self.fail(Error::Custom(
"byte string (major type 2) is outside the value model; use FormatDecoder::bytes"
.into(),
)));
}
3 => {
let token = self.read_text(argument)?;
self.dec_remaining()?;
return Ok(token);
}
4 => {
self.dec_remaining()?;
let definite = match argument {
HeadArg::Value(count) => Some(count),
HeadArg::Indefinite => None,
_ => return Err(self.fail(Error::Custom("invalid array length".into()))),
};
self.enter_container(ContainerKind::Array, definite)?;
return Ok(Token::BeginArray);
}
5 => {
self.dec_remaining()?;
let definite = match argument {
HeadArg::Value(count) => Some(count),
HeadArg::Indefinite => None,
_ => return Err(self.fail(Error::Custom("invalid object length".into()))),
};
self.enter_container(ContainerKind::Object, definite)?;
return Ok(Token::BeginObject);
}
6 => {
let tag = argument.value();
match tag {
2 => {
let token = self.read_bignum(false)?;
self.dec_remaining()?;
return Ok(token);
}
3 => {
let token = self.read_bignum(true)?;
self.dec_remaining()?;
return Ok(token);
}
_ => continue,
}
}
7 => match argument {
HeadArg::Value(20) => {
self.dec_remaining()?;
return Ok(Token::Bool(false));
}
HeadArg::Value(21) => {
self.dec_remaining()?;
return Ok(Token::Bool(true));
}
HeadArg::Value(22) => {
self.dec_remaining()?;
return Ok(Token::Null);
}
HeadArg::Value(23) => {
return Err(self.fail(Error::Custom(
"undefined (0xf7) is outside the value model".into(),
)))
}
HeadArg::Value(24) => {
let _ = self.take(1).map_err(|error| self.fail(error))?;
return Err(
self.fail(Error::Custom("unsupported CBOR simple value".into()))
);
}
HeadArg::Float16 => {
self.dec_remaining()?;
let bytes: [u8; 2] = self
.take(2)
.map_err(|error| self.fail(error))?
.try_into()
.expect("two bytes");
return Ok(Token::Number(Number::F64(half_to_f64(u16::from_be_bytes(
bytes,
)))));
}
HeadArg::Float32 => {
self.dec_remaining()?;
let bytes: [u8; 4] = self
.take(4)
.map_err(|error| self.fail(error))?
.try_into()
.expect("four bytes");
let value = f32::from_be_bytes(bytes);
return Ok(Token::Number(Number::F64(value as f64)));
}
HeadArg::Float64 => {
self.dec_remaining()?;
let bytes: [u8; 8] = self
.take(8)
.map_err(|error| self.fail(error))?
.try_into()
.expect("eight bytes");
return Ok(Token::Number(Number::F64(f64::from_be_bytes(bytes))));
}
HeadArg::Value(_) => {
return Err(self.fail(Error::Custom("unsupported CBOR simple value".into())))
}
HeadArg::Indefinite => {
let kind = match self.frames.last().copied() {
Some(frame) => frame.kind,
None => {
return Err(self.fail(Error::Custom(
"indefinite break outside any container".into(),
)))
}
};
return Ok(match kind {
ContainerKind::Array => Token::EndArray,
ContainerKind::Object => Token::EndObject,
});
}
},
_ => unreachable!("major type is three bits"),
}
}
}
fn read_text(&mut self, argument: HeadArg) -> NextjsonResult<Token<'de>> {
match argument {
HeadArg::Value(len) => {
let bytes = self.take(len as usize).map_err(|error| self.fail(error))?;
let text = core::str::from_utf8(bytes).map_err(|_| {
self.fail(Error::Custom("CBOR text string is not valid UTF-8".into()))
})?;
Ok(Token::Str(Cow::Borrowed(text)))
}
HeadArg::Indefinite => {
let mut out = Vec::new();
loop {
let byte = self.peek_byte().map_err(|error| self.fail(error))?;
if byte == 0xff {
self.cursor += 1;
break;
}
let (major, argument) = self.read_head()?;
if major != 3 {
return Err(self.fail(Error::Custom(
"indefinite text string contains a non-text chunk".into(),
)));
}
let len = match argument {
HeadArg::Value(len) => len,
_ => {
return Err(
self.fail(Error::Custom("invalid text string length".into()))
)
}
};
out.extend_from_slice(
self.take(len as usize).map_err(|error| self.fail(error))?,
);
}
let text = core::str::from_utf8(&out).map_err(|_| {
self.fail(Error::Custom("CBOR text string is not valid UTF-8".into()))
})?;
Ok(Token::Str(Cow::Owned(text.to_owned())))
}
_ => Err(self.fail(Error::Custom("invalid text string length".into()))),
}
}
fn read_bignum(&mut self, negative: bool) -> NextjsonResult<Token<'de>> {
let (major, argument) = self.read_head()?;
if major != 2 {
return Err(self.fail(Error::Custom("bignum payload must be a byte string".into())));
}
let len = match argument {
HeadArg::Value(len) => len,
HeadArg::Indefinite => {
return Err(self.fail(Error::Custom(
"indefinite bignum payload is not supported".into(),
)))
}
_ => {
return Err(self.fail(Error::Custom("bignum payload must be a byte string".into())))
}
};
let bytes = self.take(len as usize).map_err(|error| self.fail(error))?;
if bytes.len() > 16 {
return Err(self.fail(Error::Custom(
"bignum wider than 128 bits is not supported".into(),
)));
}
let mut magnitude = [0_u8; 16];
magnitude[16 - bytes.len()..].copy_from_slice(bytes);
let value = u128::from_be_bytes(magnitude);
if negative {
Ok(Token::Number(Number::I128(-1 - value as i128)))
} else {
Ok(Token::Number(Number::U128(value)))
}
}
fn peek_token_inner(&mut self) -> NextjsonResult<Token<'de>> {
if self.lookahead.is_none() {
self.lookahead = Some(self.read_token()?);
}
Ok(self.lookahead.clone().expect("lookahead initialized"))
}
fn take_token(&mut self) -> NextjsonResult<Token<'de>> {
match self.lookahead.take() {
Some(token) => Ok(token),
None => self.read_token(),
}
}
fn skip_value_inner(&mut self) -> NextjsonResult<()> {
let saved_depth = self.depth;
self.take_token()?;
while self.depth > saved_depth {
let frame = match self.frames.last().copied() {
Some(frame) => frame,
None => return Err(self.fail(Error::Custom("unbalanced container in skip".into()))),
};
let finished = match frame.definite {
Some(0) => true,
Some(_) => false,
None => self.peek_byte().map_err(|error| self.fail(error))? == 0xff,
};
if finished {
if frame.definite.is_none() {
self.cursor += 1;
}
self.pop_frame(frame.kind)?;
continue;
}
self.take_token()?;
}
Ok(())
}
}
impl<'de> FormatDecoder<'de> for CborDecoder<'de> {
type Error = NextjsonError;
fn begin_object(&mut self) -> NextjsonResult<()> {
match self.take_token()? {
Token::BeginObject => Ok(()),
other => Err(self.invalid_type("an object", &other)),
}
}
fn end_object(&mut self) -> NextjsonResult<()> {
self.end_container(ContainerKind::Object)
}
fn object_key(&mut self) -> NextjsonResult<Option<Cow<'de, str>>> {
if let Some(token) = self.lookahead.take() {
return match token {
Token::Str(key) => Ok(Some(key)),
Token::EndObject => Ok(None),
other => Err(self.invalid_type("an object key string", &other)),
};
}
let frame = match self.frames.last().copied() {
Some(frame) => frame,
None => return Err(self.fail(Error::Custom("object key outside any object".into()))),
};
if frame.kind != ContainerKind::Object {
return Err(self.fail(Error::Custom(
"object key outside an object container".into(),
)));
}
match frame.definite {
Some(0) => return Ok(None),
Some(_) => {}
None => {
if self.peek_byte().map_err(|error| self.fail(error))? == 0xff {
return Ok(None);
}
}
}
let (major, argument) = self.read_head()?;
if major != 3 {
let found = match major {
0 | 1 | 7 => Token::Number(Number::U64(0)),
4 => Token::BeginArray,
5 => Token::BeginObject,
_ => Token::Null,
};
return Err(self.invalid_type("an object key string", &found));
}
match self.read_text(argument)? {
Token::Str(key) => Ok(Some(key)),
_ => unreachable!("read_text always returns a string token"),
}
}
fn object_entry_sep(&mut self) -> NextjsonResult<bool> {
self.count_element()?;
self.has_more()
}
fn begin_array(&mut self) -> NextjsonResult<()> {
match self.take_token()? {
Token::BeginArray => Ok(()),
other => Err(self.invalid_type("an array", &other)),
}
}
fn end_array(&mut self) -> NextjsonResult<()> {
self.end_container(ContainerKind::Array)
}
fn array_has_more(&mut self) -> NextjsonResult<bool> {
self.has_more()
}
fn array_entry_sep(&mut self) -> NextjsonResult<bool> {
self.count_element()?;
self.has_more()
}
fn unit(&mut self) -> NextjsonResult<()> {
match self.take_token()? {
Token::Null => Ok(()),
other => Err(self.invalid_type("null", &other)),
}
}
fn bool(&mut self) -> NextjsonResult<bool> {
match self.take_token()? {
Token::Bool(value) => Ok(value),
other => Err(self.invalid_type("a boolean", &other)),
}
}
fn number(&mut self) -> NextjsonResult<Number> {
match self.take_token()? {
Token::Number(value) => Ok(value),
other => Err(self.invalid_type("a number", &other)),
}
}
fn string(&mut self) -> NextjsonResult<Cow<'de, str>> {
match self.take_token()? {
Token::Str(value) => Ok(value),
other => Err(self.invalid_type("a string", &other)),
}
}
fn char(&mut self) -> NextjsonResult<char> {
match self.take_token()? {
Token::Str(value) => {
let mut chars = value.chars();
match (chars.next(), chars.next()) {
(Some(ch), None) => Ok(ch),
_ => Err(self.fail(Error::InvalidChar)),
}
}
other => Err(self.invalid_type("a character", &other)),
}
}
fn bytes(&mut self) -> NextjsonResult<Cow<'de, [u8]>> {
let byte = self.peek_byte().map_err(|error| self.fail(error))?;
let major = byte >> 5;
match major {
2 => {
let (major2, argument) = self.read_head()?;
debug_assert_eq!(major2, 2);
match argument {
HeadArg::Value(len) => {
let bytes = self.take(len as usize).map_err(|error| self.fail(error))?;
Ok(Cow::Borrowed(bytes))
}
HeadArg::Indefinite => {
let mut out = Vec::new();
loop {
let next = self.peek_byte().map_err(|error| self.fail(error))?;
if next == 0xff {
self.cursor += 1;
break;
}
let (maj, arg) = self.read_head()?;
if maj != 2 {
return Err(self.fail(Error::Custom(
"indefinite byte string contains a non-byte chunk".into(),
)));
}
let len = match arg {
HeadArg::Value(len) => len,
_ => {
return Err(self
.fail(Error::Custom("invalid byte string length".into())))
}
};
out.extend_from_slice(
self.take(len as usize).map_err(|error| self.fail(error))?,
);
}
Ok(Cow::Owned(out))
}
_ => unreachable!("byte string head cannot be a float"),
}
}
3 => match self.string()? {
Cow::Borrowed(text) => Ok(Cow::Borrowed(text.as_bytes())),
Cow::Owned(text) => Ok(Cow::Owned(text.into_bytes())),
},
4 => {
self.begin_array()?;
let mut out = Vec::new();
while self.array_has_more()? {
out.push(self.u8()?);
if !self.array_entry_sep()? {
break;
}
}
self.end_array()?;
Ok(Cow::Owned(out))
}
_ => Err(self.fail(Error::Custom(
"expected a byte string or an array of bytes".into(),
))),
}
}
fn option_tag(&mut self) -> NextjsonResult<OptionTag> {
if self.lookahead.is_none() && self.peek_byte().map_err(|error| self.fail(error))? == 0xf6 {
self.cursor += 1;
return Ok(OptionTag::None);
}
if matches!(self.lookahead, Some(Token::Null)) {
self.lookahead = None;
return Ok(OptionTag::None);
}
Ok(OptionTag::Some)
}
fn skip_value(&mut self) -> NextjsonResult<()> {
self.skip_value_inner()
}
fn peek_token(&mut self) -> NextjsonResult<Token<'de>> {
self.peek_token_inner()
}
fn next_token(&mut self) -> NextjsonResult<Token<'de>> {
self.take_token()
}
fn save(&self) -> Mark {
Mark::new(self.cursor, self.depth as u32)
}
fn restore(&mut self, mark: Mark) {
let depth = (mark.depth() as usize).min(self.counts.len());
self.cursor = mark.pos();
self.depth = depth;
self.frames.truncate(depth);
for slot in &mut self.counts[depth..] {
*slot = 0;
}
self.lookahead = None;
self.wire_error = None;
}
fn set_expecting(&mut self, expecting: &'static str) -> Option<&'static str> {
self.expecting.replace(expecting)
}
fn is_human_readable(&self) -> bool {
false
}
}
impl<'de> CborDecoder<'de> {
fn end_container(&mut self, kind: ContainerKind) -> NextjsonResult<()> {
match self.lookahead.take() {
Some(Token::EndArray) | Some(Token::EndObject) => {}
Some(Token::BeginArray) | Some(Token::BeginObject) => {}
Some(_) => {
return Err(self.fail(Error::Custom("container ended with unread elements".into())))
}
None => {
let frame = match self.frames.last().copied() {
Some(frame) => frame,
None => {
return Err(
self.fail(Error::Custom("container end without matching start".into()))
)
}
};
if frame.definite.is_none() {
let byte = self.peek_byte().map_err(|error| self.fail(error))?;
if byte != 0xff {
return Err(
self.fail(Error::Custom("container ended with unread elements".into()))
);
}
self.cursor += 1;
}
}
}
let frame = match self.frames.last().copied() {
Some(frame) => frame,
None => {
return Err(self.fail(Error::Custom("container end without matching start".into())))
}
};
if let Some(remaining) = frame.definite {
if remaining != 0 {
return Err(self.fail(Error::Custom("container ended with unread elements".into())));
}
}
self.pop_frame(kind)
}
}
fn token_name(token: &Token<'_>) -> &'static str {
match token {
Token::Null => "null",
Token::Bool(_) => "bool",
Token::Number(_) => "number",
Token::Str(_) => "string",
Token::BeginObject => "object",
Token::EndObject => "end of object",
Token::BeginArray => "array",
Token::EndArray => "end of array",
}
}
fn half_to_f64(half: u16) -> f64 {
let sign = if half & 0x8000 != 0 { -1.0 } else { 1.0 };
let exponent = ((half >> 10) & 0x1f) as i32;
let fraction = (half & 0x03ff) as u32;
match exponent {
0 => {
if fraction == 0 {
sign * 0.0
} else {
sign * (fraction as f64) * 2f64.powi(-24)
}
}
0x1f => {
if fraction == 0 {
sign * f64::INFINITY
} else {
f64::NAN
}
}
_ => sign * (fraction as f64 + 1024.0) * 2f64.powi(exponent - 25),
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::collections::BTreeMap;
use alloc::string::{String, ToString};
use alloc::vec;
use nextjson::NsonDeserialize;
fn encode<T: nextjson::NsonSerialize + ?Sized>(value: &T) -> Vec<u8> {
let mut out = Vec::new();
CborEncoder::new(&mut out, Config::standard())
.finish(value)
.expect("encode");
out
}
fn decode<'de, T: nextjson::NsonDeserialize<'de>>(bytes: &'de [u8]) -> T {
CborDecoder::new(bytes, Config::standard())
.decode()
.expect("decode")
}
fn decode_err(bytes: &[u8]) -> Error {
CborDecoder::new(bytes, Config::standard())
.decode::<nextjson::Value>()
.expect_err("expected decode failure")
}
#[test]
fn encodes_rfc_8949_vectors() {
assert_eq!(encode(&0u8), [0x00]);
assert_eq!(encode(&23u8), [0x17]);
assert_eq!(encode(&24u8), [0x18, 0x18]);
assert_eq!(encode(&255u8), [0x18, 0xff]);
assert_eq!(encode(&256u16), [0x19, 0x01, 0x00]);
assert_eq!(encode(&65536u32), [0x1a, 0x00, 0x01, 0x00, 0x00]);
assert_eq!(
encode(&u64::MAX),
[0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
);
assert_eq!(encode(&-1i64), [0x20]);
assert_eq!(encode(&-24i64), [0x37]);
assert_eq!(encode(&-25i64), [0x38, 0x18]);
assert_eq!(encode(&-256i64), [0x38, 0xff]);
assert_eq!(encode(&-257i64), [0x39, 0x01, 0x00]);
assert_eq!(encode(&true), [0xf5]);
assert_eq!(encode(&false), [0xf4]);
assert_eq!(encode(&Option::<u8>::None), [0xf6]);
assert_eq!(encode(&Option::Some(5u8)), [0x05]);
assert_eq!(encode("a"), [0x61, b'a']);
assert_eq!(encode("IETF"), [0x64, b'I', b'E', b'T', b'F']);
assert_eq!(encode(&vec![1u8, 2, 3]), [0x9f, 0x01, 0x02, 0x03, 0xff]);
assert_eq!(
encode(&1.0f64),
[0xfb, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
);
assert_eq!(encode(&1.0f32), [0xfa, 0x3f, 0x80, 0x00, 0x00]);
let big = encode(&u128::MAX);
assert_eq!(big[0], 0xc2);
assert_eq!(big[1], 0x50);
assert_eq!(&big[2..], &[0xff; 16]);
let bytes = encode(&nextjson::Bytes(b"xyz"));
assert_eq!(bytes, [0x43, b'x', b'y', b'z']);
}
#[test]
fn decodes_definite_and_indefinite_containers() {
assert_eq!(decode::<Vec<u8>>(&[0x83, 0x01, 0x02, 0x03]), vec![1, 2, 3]);
assert_eq!(
decode::<Vec<u8>>(&[0x9f, 0x01, 0x02, 0x03, 0xff]),
vec![1, 2, 3]
);
let map: BTreeMap<String, u8> = decode(&[0xa2, 0x61, b'a', 0x01, 0x61, b'b', 0x02]);
assert_eq!(
map,
BTreeMap::from([("a".to_string(), 1), ("b".to_string(), 2)])
);
let map: BTreeMap<String, u8> = decode(&[0xbf, 0x61, b'a', 0x01, 0x61, b'b', 0x02, 0xff]);
assert_eq!(
map,
BTreeMap::from([("a".to_string(), 1), ("b".to_string(), 2)])
);
assert_eq!(
decode::<String>(&[0x7f, 0x62, b'a', b'b', 0x61, b'c', 0xff]),
"abc"
);
let nested: Vec<Vec<u8>> = decode(&[0x9f, 0x82, 0x01, 0x02, 0x81, 0x03, 0xff]);
assert_eq!(nested, vec![vec![1, 2], vec![3]]);
}
#[test]
fn roundtrips_values_across_formats() {
let data = (
7u64,
"hello",
vec![1i32, -2, 3],
Some("x".to_string()),
Option::<u8>::None,
-42i128,
true,
);
let encoded = encode(&data);
let decoded: (
u64,
String,
Vec<i32>,
Option<String>,
Option<u8>,
i128,
bool,
) = decode(&encoded);
assert_eq!(
decoded,
(
7,
"hello".to_string(),
vec![1, -2, 3],
Some("x".to_string()),
None,
-42,
true
)
);
}
#[test]
fn decodes_half_precision_and_ignores_annotating_tags() {
assert_eq!(decode::<f64>(&[0xf9, 0x3c, 0x00]), 1.0);
assert_eq!(decode::<f64>(&[0xf9, 0xc0, 0x00]), -2.0);
assert_eq!(decode::<f64>(&[0xf9, 0x7b, 0xff]), 65504.0);
assert_eq!(decode::<f64>(&[0xf9, 0x00, 0x01]), 5.960464477539063e-8);
assert_eq!(
decode::<u64>(&[0xc1, 0x1a, 0x51, 0x4b, 0xb6, 0x70]),
1363916400
);
assert_eq!(
decode::<String>(&[
0xc0, 0x74, b'2', b'0', b'1', b'3', b'-', b'0', b'3', b'-', b'2', b'1', b'T', b'2',
b'0', b':', b'0', b'4', b':', b'0', b'0', b'Z'
]),
"2013-03-21T20:04:00Z"
);
}
#[test]
fn bignums_roundtrip_beyond_64_bits() {
for value in [
u128::MAX,
u128::from(u64::MAX) + 1,
0x1234_5678_9abc_def0_1122_3344_5566_7788,
] {
let encoded = encode(&value);
assert_eq!(decode::<u128>(&encoded), value);
}
for value in [
i128::MIN,
i128::from(i64::MIN) - 1,
-0x1234_5678_9abc_def0_1122_3344_5566_7789i128,
] {
let encoded = encode(&value);
assert_eq!(decode::<i128>(&encoded), value);
}
let encoded = encode(&0x8000_0000_0000_0000u128);
assert_eq!(decode::<u128>(&encoded), 0x8000_0000_0000_0000);
}
#[test]
fn bytes_reads_native_and_array_spellings() {
let encoded = encode(&nextjson::Bytes(b"abc"));
let out: nextjson::Bytes<'_> = decode(&encoded);
assert_eq!(out.as_bytes(), b"abc");
assert_eq!(decode::<Vec<u8>>(&[0x83, 0x01, 0x02, 0x03]), vec![1, 2, 3]);
}
#[test]
fn cross_checks_against_nextjson_relay() {
use nextjson::formats::{Cbor, Format};
let ours = encode(&("value", 42u64, vec![1u8, 2, 3]));
let decoded: (String, u64, Vec<u8>) = Cbor.decode(&ours).expect("nextjson decodes ours");
assert_eq!(decoded, ("value".to_string(), 42, vec![1, 2, 3]));
let theirs = Cbor
.encode(&("value", 42u64, vec![1u8, 2, 3]))
.expect("nextjson encodes");
let decoded: (String, u64, Vec<u8>) = decode(&theirs);
assert_eq!(decoded, ("value".to_string(), 42, vec![1, 2, 3]));
}
#[test]
fn rejects_malformed_and_truncated_input() {
assert!(matches!(
decode_err(&[0x83, 0x01, 0x02]),
Error::UnexpectedEnd
));
assert!(matches!(decode_err(&[0x62, 0xff, 0xfe]), Error::Custom(_)));
assert!(matches!(decode_err(&[0xff]), Error::Custom(_)));
assert!(matches!(decode_err(&[0x1e]), Error::Custom(_)));
assert!(matches!(decode_err(&[0x41, 0x01]), Error::Custom(_)));
assert!(matches!(decode_err(&[0xf7]), Error::Custom(_)));
assert!(matches!(decode_err(&[0xf8, 0x20]), Error::Custom(_)));
assert!(matches!(decode_err(&[0x82, 0x01]), Error::UnexpectedEnd));
let mut wide = vec![0xc2, 0x59, 0x00, 0x11];
wide.extend_from_slice(&[0u8; 17]);
assert!(matches!(decode_err(&wide), Error::Custom(_)));
}
#[test]
fn enforces_byte_collection_and_depth_limits() {
let err = CborDecoder::new(
&[0x1b, 0, 0, 0, 0, 0, 0, 0, 0],
Config::standard().with_limit(4),
)
.decode::<u64>()
.expect_err("byte limit");
assert!(matches!(err, Error::SizeLimit { .. }));
let err = CborDecoder::new(&[0x98, 0x64], Config::standard().with_collection_limit(3))
.decode::<Vec<u8>>()
.expect_err("collection limit");
assert!(matches!(err, Error::CollectionLimit { limit: 3 }));
let mut deep = Vec::new();
#[allow(clippy::same_item_push)]
for _ in 0..(crate::tags::MAX_DEPTH + 2) {
deep.push(0x81);
}
deep.push(0x00);
#[allow(clippy::same_item_push)]
for _ in 0..(crate::tags::MAX_DEPTH + 2) {
deep.push(0xff);
}
let err = CborDecoder::new(&deep, Config::standard())
.decode::<Vec<u8>>()
.expect_err("depth limit");
assert!(matches!(err, Error::Custom(_)));
let err = CborEncoder::new(&mut Vec::new(), Config::standard().with_limit(2))
.finish(&vec![1u8, 2, 3])
.expect_err("encode byte limit");
assert!(matches!(err, Error::SizeLimit { limit: 2 }));
}
#[test]
fn restore_supports_untagged_backtracking() {
let bytes = encode(&("abc", 9u64));
let mut decoder = CborDecoder::new(&bytes, Config::standard());
decoder.begin_array().expect("array");
let mark = decoder.save();
assert!(u64::nextdecode(&mut decoder).is_err());
decoder.restore(mark);
let first: String = String::nextdecode(&mut decoder).expect("retry");
assert_eq!(first, "abc");
assert!(decoder.array_entry_sep().expect("sep"));
let second: u64 = u64::nextdecode(&mut decoder).expect("second value");
assert_eq!(second, 9);
assert!(!decoder.array_entry_sep().expect("last sep"));
decoder.end_array().expect("end");
}
}