Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions ciborium/src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ pub use error::Error;

use alloc::{string::String, vec::Vec};

use crate::{simple_type::SimpleTypeAccess, tag::TagAccess};
use ciborium_io::Read;
use ciborium_ll::*;
use serde::de::{self, value::BytesDeserializer, Deserializer as _};

use crate::tag::TagAccess;

trait Expected<E: de::Error> {
fn expected(self, kind: &'static str) -> E;
}
Expand Down Expand Up @@ -213,8 +212,22 @@ where
Header::Simple(simple::FALSE) => self.deserialize_bool(visitor),
Header::Simple(simple::TRUE) => self.deserialize_bool(visitor),
Header::Simple(simple::NULL) => self.deserialize_option(visitor),
Header::Simple(simple::UNDEFINED) => self.deserialize_option(visitor),
h @ Header::Simple(..) => Err(h.expected("known simple value")),
Header::Simple(v @ simple::UNDEFINED) => {
let _: Header = self.decoder.pull()?;
visitor.visit_enum(SimpleTypeAccess::new(self, v))
}
// Those have to be registered via Standard Actions or are reserved so we should error whenever we
// encounter one. This crate should be updated once new entries in this range are added
// in the IANA registry
h @ Header::Simple(0..=31) => Err(h.expected("known simple value")),
// However we should support arbitrary simple types
Header::Simple(v) => {
let _: Header = self.decoder.pull()?;
self.recurse(|me| {
let access = SimpleTypeAccess::new(me, v);
visitor.visit_enum(access)
})
}

h @ Header::Break => Err(h.expected("non-break")),
}
Expand Down Expand Up @@ -604,6 +617,19 @@ where
let access = TagAccess::new(me, tag);
visitor.visit_enum(access)
});
} else if name == "@@ST@@" {
return match self.decoder.pull()? {
Header::Simple(v @ simple::UNDEFINED) => {
self.decoder.push(Header::Positive(v as u64));
visitor.visit_enum(SimpleTypeAccess::new(self, v))
}
h @ Header::Simple(0..=31) => Err(h.expected("known simple value")),
Header::Simple(v) => {
self.decoder.push(Header::Positive(v as u64));
visitor.visit_enum(SimpleTypeAccess::new(self, v))
}
h => Err(h.expected("known simple value")),
};
}

loop {
Expand Down
1 change: 1 addition & 0 deletions ciborium/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ extern crate alloc;

pub mod de;
pub mod ser;
pub mod simple_type;
pub mod tag;
pub mod value;

Expand Down
26 changes: 23 additions & 3 deletions ciborium/src/ser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,21 @@ where
#[inline]
fn serialize_newtype_struct<U: ?Sized + ser::Serialize>(
self,
_name: &'static str,
name: &'static str,
value: &U,
) -> Result<(), Self::Error> {
value.serialize(self)
if name == "@@SIMPLETYPE@@" {
use serde::ser::Error as _;

let v = crate::Value::serialized(value).map_err(Error::custom)?;
let v = v
.as_integer()
.ok_or_else(|| Error::custom("Internal error handling simple types"))?;
let v = u8::try_from(v).map_err(Error::custom)?;
Ok(self.0.push(Header::Simple(v))?)
} else {
value.serialize(self)
}
}

#[inline]
Expand All @@ -214,7 +225,16 @@ where
variant: &'static str,
value: &U,
) -> Result<(), Self::Error> {
if name != "@@TAG@@" || variant != "@@UNTAGGED@@" {
if name == "@@ST@@" && variant == "@@SIMPLETYPE@@" {
use serde::ser::Error as _;

let v = crate::Value::serialized(value).map_err(Error::custom)?;
let v = v
.as_integer()
.ok_or_else(|| Error::custom("Internal error handling simple types"))?;
let v = u8::try_from(v).map_err(Error::custom)?;
return Ok(self.0.push(Header::Simple(v))?);
} else if name != "@@TAG@@" || variant != "@@UNTAGGED@@" {
self.0.push(Header::Map(Some(1)))?;
self.serialize_str(variant)?;
}
Expand Down
141 changes: 141 additions & 0 deletions ciborium/src/simple_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
//! Contains helper types for dealing with CBOR simple types

use serde::{de, de::Error as _, forward_to_deserialize_any, ser, Deserialize, Serialize};

#[derive(Debug, Deserialize, Serialize)]
#[serde(rename = "@@ST@@")]
enum Internal {
/// The integer can either be 23, or (32..=255)
#[serde(rename = "@@SIMPLETYPE@@")]
SimpleType(u8),
}

/// A CBOR simple value
/// See https://datatracker.ietf.org/doc/html/rfc8949#section-3.3
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SimpleType(pub u8);

impl<'de> Deserialize<'de> for SimpleType {
#[inline]
fn deserialize<D: de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
match Internal::deserialize(deserializer)? {
Internal::SimpleType(t) => Ok(SimpleType(t)),
}
}
}

impl Serialize for SimpleType {
#[inline]
fn serialize<S: ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
Internal::SimpleType(self.0).serialize(serializer)
}
}

pub(crate) struct SimpleTypeAccess<D> {
parent: Option<D>,
state: usize,
typ: u8,
}

impl<D> SimpleTypeAccess<D> {
pub fn new(parent: D, typ: u8) -> Self {
Self {
parent: Some(parent),
state: 0,
typ,
}
}
}

impl<'de, D: de::Deserializer<'de>> de::Deserializer<'de> for &mut SimpleTypeAccess<D> {
type Error = D::Error;

#[inline]
fn deserialize_any<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
self.state += 1;
match self.state {
1 => visitor.visit_str("@@SIMPLETYPE@@"),
_ => visitor.visit_u8(self.typ),
}
}

forward_to_deserialize_any! {
i8 i16 i32 i64 i128
u8 u16 u32 u64 u128
bool f32 f64
char str string
bytes byte_buf
seq map
struct tuple tuple_struct
identifier ignored_any
option unit unit_struct newtype_struct enum
}
}

impl<'de, D: de::Deserializer<'de>> de::EnumAccess<'de> for SimpleTypeAccess<D> {
type Error = D::Error;
type Variant = Self;

#[inline]
fn variant_seed<V: de::DeserializeSeed<'de>>(
mut self,
seed: V,
) -> Result<(V::Value, Self::Variant), Self::Error> {
let variant = seed.deserialize(&mut self)?;
Ok((variant, self))
}
}

impl<'de, D: de::Deserializer<'de>> de::VariantAccess<'de> for SimpleTypeAccess<D> {
type Error = D::Error;

#[inline]
fn unit_variant(self) -> Result<(), Self::Error> {
Err(Self::Error::custom("expected simple type"))
}

#[inline]
fn newtype_variant_seed<U: de::DeserializeSeed<'de>>(
mut self,
seed: U,
) -> Result<U::Value, Self::Error> {
seed.deserialize(self.parent.take().unwrap())
}

#[inline]
fn tuple_variant<V: de::Visitor<'de>>(
self,
_len: usize,
visitor: V,
) -> Result<V::Value, Self::Error> {
visitor.visit_seq(self)
}

#[inline]
fn struct_variant<V: de::Visitor<'de>>(
self,
_fields: &'static [&'static str],
_visitor: V,
) -> Result<V::Value, Self::Error> {
Err(Self::Error::custom("expected simple_type"))
}
}

impl<'de, D: de::Deserializer<'de>> de::SeqAccess<'de> for SimpleTypeAccess<D> {
type Error = D::Error;

#[inline]
fn next_element_seed<T: de::DeserializeSeed<'de>>(
&mut self,
seed: T,
) -> Result<Option<T::Value>, Self::Error> {
if self.state < 2 {
return Ok(Some(seed.deserialize(self)?));
}

Ok(match self.parent.take() {
Some(x) => Some(seed.deserialize(x)?),
None => None,
})
}
}
56 changes: 50 additions & 6 deletions ciborium/src/value/de.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// SPDX-License-Identifier: Apache-2.0

use crate::tag::TagAccess;
use crate::{simple_type::SimpleTypeAccess, tag::TagAccess};

use super::{Error, Integer, Value};

use alloc::{boxed::Box, string::String, vec::Vec};
use core::iter::Peekable;

use ciborium_ll::tag;
use ciborium_ll::{simple, tag};
use serde::de::{self, Deserializer as _};

impl<'a> From<Integer> for de::Unexpected<'a> {
Expand Down Expand Up @@ -36,6 +36,7 @@ impl<'a> From<&'a Value> for de::Unexpected<'a> {
Value::Map(..) => Self::Map,
Value::Null => Self::Other("null"),
Value::Tag(..) => Self::Other("tag"),
Value::Simple(..) => Self::Other("simple"),
}
}
}
Expand Down Expand Up @@ -141,9 +142,9 @@ impl<'de> serde::de::Visitor<'de> for Visitor {
fn visit_enum<A: de::EnumAccess<'de>>(self, acc: A) -> Result<Self::Value, A::Error> {
use serde::de::VariantAccess;

struct Inner;
struct TagInner;

impl<'de> serde::de::Visitor<'de> for Inner {
impl<'de> serde::de::Visitor<'de> for TagInner {
type Value = Value;

fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
Expand All @@ -162,9 +163,30 @@ impl<'de> serde::de::Visitor<'de> for Visitor {
}
}

struct SimpleTypeInner;

impl<'de> serde::de::Visitor<'de> for SimpleTypeInner {
type Value = Value;

fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(formatter, "a valid CBOR item")
}

#[inline]
fn visit_seq<A: de::SeqAccess<'de>>(self, mut acc: A) -> Result<Self::Value, A::Error> {
let st = acc
.next_element::<u8>()?
.ok_or_else(|| de::Error::custom("expected simple type"))?;
Ok(Value::Simple(st))
}
}

let (name, data): (String, _) = acc.variant()?;
assert_eq!("@@TAGGED@@", name);
data.tuple_variant(2, Inner)
match name.as_str() {
"@@TAGGED@@" => data.tuple_variant(2, TagInner),
"@@SIMPLETYPE@@" => data.tuple_variant(1, SimpleTypeInner),
_ => panic!("Implementation error"),
}
}
}

Expand Down Expand Up @@ -218,6 +240,7 @@ impl<'a> Deserializer<&'a Value> {
.map(|x| x ^ !0)
.map_err(|_| err())
.and_then(|x| x.try_into().map_err(|_| err()))?,
Value::Simple(x) => i128::from(*x).try_into().map_err(|_| err())?,
_ => return Err(de::Error::invalid_type(self.0.into(), &"(big)int")),
})
}
Expand All @@ -228,13 +251,22 @@ impl<'a, 'de> de::Deserializer<'de> for Deserializer<&'a Value> {

#[inline]
fn deserialize_any<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
use serde::ser::Error as _;
match self.0 {
Value::Bytes(x) => visitor.visit_bytes(x),
Value::Text(x) => visitor.visit_str(x),
Value::Array(x) => visitor.visit_seq(Deserializer(x.iter())),
Value::Map(x) => visitor.visit_map(Deserializer(x.iter().peekable())),
Value::Bool(x) => visitor.visit_bool(*x),
Value::Null => visitor.visit_none(),
Value::Simple(v @ simple::UNDEFINED) => {
visitor.visit_enum(SimpleTypeAccess::new(self, *v))
}
Value::Simple(0..=31) => Err(Self::Error::custom("Unsupported simple type")),
Value::Simple(v) => {
let access = SimpleTypeAccess::new(self, *v);
visitor.visit_enum(access)
}

Value::Tag(t, v) => {
let parent: Deserializer<&Value> = Deserializer(v);
Expand Down Expand Up @@ -493,6 +525,18 @@ impl<'a, 'de> de::Deserializer<'de> for Deserializer<&'a Value> {
let parent: Deserializer<&Value> = Deserializer(val);
let access = TagAccess::new(parent, tag);
return visitor.visit_enum(access);
} else if name == "@@ST@@" {
use serde::ser::Error as _;
return match self.0 {
Value::Simple(v @ simple::UNDEFINED) => {
visitor.visit_enum(SimpleTypeAccess::new(Deserializer(self.0), *v))
}
Value::Simple(0..=31) => return Err(Error::custom("Unsupported simple type")),
Value::Simple(v) => {
visitor.visit_enum(SimpleTypeAccess::new(Deserializer(self.0), *v))
}
_ => Err(Error::custom("Implementation error for simple type")),
};
}

match self.0 {
Expand Down
Loading
Loading