use half::f16;
use std::borrow::Cow;
use winnow::{Parser, error::ParserError as _};
use crate::{
SyntacticValue, Value,
error::SeaboredDeError,
ib::{self, AdditionalInfoAction, InitialByte},
io::Read,
mt::MajorType,
types::{CborFloat, CborInteger, CborIntegerValue, CborSequence},
};
pub trait CborDeserialize<'a> {
fn cbor_deserialize_from<R: Read<'a>>(reader: &mut R) -> Result<Self, SeaboredDeError<'a>>
where
Self: Sized + 'a;
}
impl<'a, T1, T2> CborDeserialize<'a> for (T1, T2)
where
T1: CborDeserialize<'a>,
T2: CborDeserialize<'a>,
{
#[inline(always)]
fn cbor_deserialize_from<R: Read<'a>>(reader: &mut R) -> Result<Self, SeaboredDeError<'a>>
where
Self: Sized + 'a,
{
T1::cbor_deserialize_from(reader)
.and_then(|t1| T2::cbor_deserialize_from(reader).map(|t2| (t1, t2)))
}
}
impl<'a> CborDeserialize<'a> for Value<'a> {
#[cfg_attr(feature = "inline-nontrivial", inline)]
fn cbor_deserialize_from<R: Read<'a>>(reader: &mut R) -> Result<Self, SeaboredDeError<'a>>
where
Self: Sized + 'a,
{
let ib = InitialByte::cbor_deserialize_from(reader)?;
let (mt, ai) = ib.mt_ai();
let value_or_len = match ai.action()? {
AdditionalInfoAction::DoNothing => CborIntegerValue::from(ai.0),
AdditionalInfoAction::Uint8 => CborIntegerValue::from(reader.read_byte()?),
AdditionalInfoAction::Uint16 => CborIntegerValue::from(reader.read_be_u16()?),
AdditionalInfoAction::Uint32 => CborIntegerValue::from(reader.read_be_u32()?),
AdditionalInfoAction::Uint64 => CborIntegerValue::from(reader.read_be_u64()?),
AdditionalInfoAction::IndefiniteLenSeq => {
return match mt {
MajorType::Bytes | MajorType::String | MajorType::Array => {
let mut seq = CborSequence::new_indefinite(mt);
while reader.peek_byte()? != ib::consts::IB_BREAK {
seq.push(Value::cbor_deserialize_from(reader)?)
}
reader.advance(1)?; Ok(Value::Sequence(seq))
}
MajorType::Map => {
let mut seq = CborSequence::new_indefinite(mt);
while reader.peek_byte()? != ib::consts::IB_BREAK {
seq.push(<(Value, Value)>::cbor_deserialize_from(reader)?)
}
reader.advance(1)?; Ok(Value::Map(seq))
}
_ => {
return Err(SeaboredDeError::IncorrectMajorType {
actual: mt,
expected: &[
MajorType::Bytes,
MajorType::String,
MajorType::Array,
MajorType::Map,
],
});
}
};
}
};
Ok(match mt {
MajorType::Uint | MajorType::NegativeUint => Value::Integer(CborInteger {
value: value_or_len,
negative: mt == MajorType::NegativeUint,
}),
MajorType::SimpleValueOrFloat => match ib.0 {
ib::consts::IB_FALSE => Value::Bool(false),
ib::consts::IB_TRUE => Value::Bool(true),
ib::consts::IB_NULL => Value::Null,
ib::consts::IB_UNDEFINED => Value::Undefined,
ib::consts::IB_SIMPLE_VALUE_NEXT_BYTE => {
Value::SimpleValue(value_or_len.try_into()?)
}
ib::consts::IB_FLOAT_16 => {
Value::Float(f16::from_bits(value_or_len.try_into()?).into())
}
ib::consts::IB_FLOAT_32 => {
Value::Float(f32::from_bits(value_or_len.try_into()?).into())
}
ib::consts::IB_FLOAT_64 => Value::Float(f64::from_bits(value_or_len.into()).into()),
ib::consts::IB_SIMPLE_VALUE..ib::consts::IB_FALSE => {
Value::SimpleValue(ib.0 - ib::consts::IB_SIMPLE_VALUE)
}
_ => return Err(SeaboredDeError::UnsupportedSimpleValue(ib.0)),
},
MajorType::Bytes => Value::Bytes(reader.read_slice(value_or_len.try_into()?)?),
MajorType::String => {
Value::String(match reader.read_slice(value_or_len.try_into()?)? {
Cow::Borrowed(s) => Cow::Borrowed(simdutf8::basic::from_utf8(s)?),
Cow::Owned(s) => Cow::Owned({
simdutf8::basic::from_utf8(&s)?;
unsafe { String::from_utf8_unchecked(s) }
}),
})
}
MajorType::Array => Value::Sequence({
let len = value_or_len.try_into()?;
let mut seq = CborSequence::new_finite(MajorType::Array, len);
for _ in 0..len {
seq.push(Value::cbor_deserialize_from(reader)?)
}
seq
}),
MajorType::Map => Value::Map({
let len = value_or_len.try_into()?;
let mut seq = CborSequence::new_finite(MajorType::Map, len);
for _ in 0..len {
seq.push(<(Value, Value)>::cbor_deserialize_from(reader)?)
}
seq
}),
MajorType::Tagged => Value::Tagged((
value_or_len,
Box::new(Value::cbor_deserialize_from(reader)?),
)),
})
}
}
type Stream<'i> = &'i [u8];
type StreamErr<'i> = winnow::error::ErrMode<winnow::error::ContextError<Stream<'i>>>;
#[inline(always)]
fn read_ib<'i>(input: &mut Stream<'i>) -> Result<InitialByte, SeaboredDeError<'i>> {
winnow::binary::be_u8::<_, StreamErr<'i>>
.map(InitialByte)
.parse_next(input)
.map_err(Into::into)
}
#[inline(always)]
fn cut_err<'i, T>(input: &mut Stream<'i>) -> Result<T, SeaboredDeError<'i>> {
Err(winnow::error::ErrMode::Cut(winnow::error::ContextError::from_input(input)).into())
}
#[inline(always)]
fn take_bytes<'i>(
input: &mut Stream<'i>,
len: usize,
) -> winnow::ModalResult<SyntacticValue<'i>, winnow::error::ContextError<&'i [u8]>> {
winnow::token::take(len)
.map(|bytes: &[u8]| Value::Bytes(Cow::Borrowed(bytes)).into())
.parse_next(input)
}
#[inline(always)]
fn take_string<'i>(
input: &mut Stream<'i>,
len: usize,
) -> winnow::ModalResult<SyntacticValue<'i>, winnow::error::ContextError<&'i [u8]>> {
winnow::token::take(len)
.try_map::<_, _, simdutf8::basic::Utf8Error>(|bytes: &[u8]| {
Ok(Value::String(Cow::Borrowed(simdutf8::basic::from_utf8(bytes)?)).into())
})
.parse_next(input)
}
#[inline(always)]
fn take_array<'i>(
input: &mut Stream<'i>,
len: usize,
) -> Result<SyntacticValue<'i>, SeaboredDeError<'i>> {
let mut seq = CborSequence::new_finite(MajorType::Array, len);
for _ in 0..len {
let SyntacticValue::Value(value) = parse_value_inner(input)? else {
return cut_err(input);
};
seq.push(value);
}
Ok(Value::Sequence(seq).into())
}
#[inline(always)]
fn take_map<'i>(
input: &mut Stream<'i>,
len: usize,
) -> Result<SyntacticValue<'i>, SeaboredDeError<'i>> {
let mut seq = CborSequence::new_finite(MajorType::Map, len);
for _ in 0..len {
let (SyntacticValue::Value(key), SyntacticValue::Value(value)) =
parse_value_inner(input)
.and_then(|key| parse_value_inner(input).map(|value| (key, value)))?
else {
return cut_err(input);
};
seq.push((key, value));
}
Ok(Value::Map(seq).into())
}
#[inline(always)]
fn take_sequence<'i>(
input: &mut Stream<'i>,
mt: MajorType,
) -> Result<SyntacticValue<'i>, SeaboredDeError<'i>> {
let mut seq = CborSequence::new_indefinite(mt);
loop {
let value = parse_value_inner(input)?;
match value {
SyntacticValue::Value(value) => {
if mt != MajorType::Array && mt != value.mt() {
return cut_err(input);
}
seq.push(value);
}
SyntacticValue::Break => {
break;
}
}
}
Ok(Value::Sequence(seq).into())
}
#[inline(always)]
fn take_sequence_map<'i>(
input: &mut Stream<'i>,
) -> Result<SyntacticValue<'i>, SeaboredDeError<'i>> {
let mut map = CborSequence::new_indefinite(MajorType::Map);
loop {
let key = parse_value_inner(input)?;
match key {
SyntacticValue::Value(key) => {
let value = parse_value_inner(input)?;
match value {
SyntacticValue::Value(value) => {
map.push((key, value));
}
SyntacticValue::Break => {
return cut_err(input);
}
}
}
SyntacticValue::Break => {
break;
}
}
}
Ok(Value::Map(map).into())
}
#[inline(always)]
pub fn parse_value<'i>(input: &mut Stream<'i>) -> Result<Value<'i>, SeaboredDeError<'i>> {
let syn_value = parse_value_inner(input)?;
if !input.is_empty() {
return Err(
winnow::error::ErrMode::Cut(winnow::error::ContextError::from_input(input)).into(),
);
}
let SyntacticValue::Value(value) = syn_value else {
return Err(SeaboredDeError::Incomplete(winnow::error::Needed::Unknown));
};
Ok(value)
}
#[inline(always)]
pub fn parse_value_streaming<'i>(input: &mut Stream<'i>) -> Result<Value<'i>, SeaboredDeError<'i>> {
let SyntacticValue::Value(value) = parse_value_inner(input)? else {
return Err(SeaboredDeError::Incomplete(winnow::error::Needed::Unknown));
};
Ok(value)
}
#[inline(always)]
fn parse_value_inner<'i>(
input: &mut Stream<'i>,
) -> Result<SyntacticValue<'i>, SeaboredDeError<'i>> {
let ib = read_ib(input)?;
if ib.0 == ib::consts::IB_BREAK {
return Ok(SyntacticValue::Break);
}
let (mt, ai) = ib.mt_ai();
let ai_action = ai
.action()
.map_err(|_| cut_err::<AdditionalInfoAction>(input).unwrap_err())?;
let value_or_len = match ai_action {
AdditionalInfoAction::DoNothing => CborIntegerValue::from(ai.0),
AdditionalInfoAction::Uint8 => winnow::binary::be_u8::<_, StreamErr<'i>>
.map(CborIntegerValue::from)
.parse_next(input)?,
AdditionalInfoAction::Uint16 => winnow::binary::be_u16::<_, StreamErr<'i>>
.map(CborIntegerValue::from)
.parse_next(input)?,
AdditionalInfoAction::Uint32 => winnow::binary::be_u32::<_, StreamErr<'i>>
.map(CborIntegerValue::from)
.parse_next(input)?,
AdditionalInfoAction::Uint64 => winnow::binary::be_u64::<_, StreamErr<'i>>
.map(CborIntegerValue::from)
.parse_next(input)?,
AdditionalInfoAction::IndefiniteLenSeq => {
return match mt {
MajorType::String | MajorType::Bytes | MajorType::Array => {
Ok(take_sequence(input, mt)?)
}
MajorType::Map => Ok(take_sequence_map(input)?),
_ => cut_err(input),
};
}
};
Ok(match mt {
MajorType::Uint | MajorType::NegativeUint => Value::Integer(CborInteger {
value: value_or_len,
negative: mt == MajorType::NegativeUint,
}),
MajorType::SimpleValueOrFloat => match ib.0 {
value @ ib::consts::IB_SIMPLE_VALUE..ib::consts::IB_FALSE => {
Value::SimpleValue(value - ib::consts::IB_SIMPLE_VALUE)
}
ib::consts::IB_FALSE => Value::Bool(false),
ib::consts::IB_TRUE => Value::Bool(true),
ib::consts::IB_NULL => Value::Null,
ib::consts::IB_UNDEFINED => Value::Undefined,
ib::consts::IB_SIMPLE_VALUE_NEXT_BYTE => Value::SimpleValue(value_or_len.try_into()?),
ib::consts::IB_FLOAT_16 => {
Value::Float(CborFloat::from(f16::from_bits(value_or_len.try_into()?))).into()
}
ib::consts::IB_FLOAT_32 => {
Value::Float(CborFloat::from(f32::from_bits(value_or_len.try_into()?))).into()
}
ib::consts::IB_FLOAT_64 => {
Value::Float(CborFloat::from(f64::from_bits(value_or_len.into()))).into()
}
_ => return cut_err(input),
},
MajorType::Bytes => {
let SyntacticValue::Value(v) = take_bytes(input, value_or_len.try_into()?)? else {
return cut_err(input);
};
v
}
MajorType::String => {
let SyntacticValue::Value(v) = take_string(input, value_or_len.try_into()?)? else {
return cut_err(input);
};
v
}
MajorType::Array => {
let SyntacticValue::Value(v) = take_array(input, value_or_len.try_into()?)? else {
return cut_err(input);
};
v
}
MajorType::Map => {
let SyntacticValue::Value(v) = take_map(input, value_or_len.try_into()?)? else {
return cut_err(input);
};
v
}
MajorType::Tagged => {
let SyntacticValue::Value(v) = parse_value_inner(input)? else {
return cut_err(input);
};
Value::Tagged((value_or_len, Box::new(v)))
}
}
.into())
}