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
140 changes: 136 additions & 4 deletions minicbor-serde/src/de.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
use serde::de::{self, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, VariantAccess, Visitor};
use serde::de::{
self, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, VariantAccess, Visitor,
value::{BorrowedStrDeserializer, U64Deserializer},
};

use minicbor::data::Type;
use minicbor::data::{Tag, Type};
use minicbor::decode::{Decoder, Error};

use crate::error::DecodeError;
use crate::{
error::DecodeError,
tag::{NO_TAG_IDENTIFIER, TAG_CONTAINER_IDENTIFIER, TAG_IDENTIFIER},
};

const BREAK: u8 = 0xff;

Expand Down Expand Up @@ -269,13 +275,18 @@ impl<'de> de::Deserializer<'de> for &mut Deserializer<'de> {

fn deserialize_enum<V>
( self
, _name: &'static str
, name: &'static str
, _variants: &'static [&'static str]
, visitor: V
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>
{
// Handle the case when user uses our custom tag structures
if name == TAG_CONTAINER_IDENTIFIER {
return visitor.visit_enum(EnumTagAccess::new(self)?);
}

let p = self.decoder.position();
if Type::Map == self.decoder.datatype()? {
let m = self.decoder.map()?;
Expand Down Expand Up @@ -426,3 +437,124 @@ impl<'a, 'de> VariantAccess<'de> for Enum<'a, 'de> {
de::Deserializer::deserialize_map(self.deserializer, v)
}
}

enum State {
Tag(Tag),
Value,
End,
}

struct SeqTagAccess<'a, 'de: 'a> {
deserializer: &'a mut Deserializer<'de>,
state: State,
}

impl<'a, 'de> SeqTagAccess<'a, 'de> {
fn new(tag: Option<Tag>, d: &'a mut Deserializer<'de>) -> Self {
Self {
state: tag.map(State::Tag).unwrap_or(State::Value),
deserializer: d,
}
}
}

impl<'a, 'de> de::SeqAccess<'de> for SeqTagAccess<'a, 'de> {
type Error = DecodeError;

fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>,
{
match self.state {
State::Tag(tag) => {
self.state = State::Value;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the state should change after the tag was successfully deserialised? Probably does not make much of a difference in practice.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup as we'd error out either way. I'd keep it this way as otherwise the code ends up looking a bit too verbose (assign to var, switch state, and then return the value).

Let me know if you feel otherwise.

Ok(Some(
seed.deserialize(U64Deserializer::<DecodeError>::new(tag.as_u64()))?,
))
}
State::Value => {
self.state = State::End;
Ok(Some(seed.deserialize(&mut *self.deserializer)?))
}
State::End => Ok(None),
}
}
}

struct EnumTagAccess<'a, 'de: 'a> {
deserializer: &'a mut Deserializer<'de>,
tag: Option<Tag>,
}

impl<'a, 'de> EnumTagAccess<'a, 'de> {
fn new(d: &'a mut Deserializer<'de>) -> Result<Self, DecodeError> {
let tag = match d.decoder_mut().datatype()? {
Type::Tag => Some(d.decoder_mut().tag()?),
_ => None,
};

Ok(Self {
tag,
deserializer: d,
})
}
}

impl<'a, 'de> de::EnumAccess<'de> for EnumTagAccess<'a, 'de> {
type Error = DecodeError;
type Variant = Self;

fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where
V: DeserializeSeed<'de>,
{
let variant = match self.tag.is_some() {
true => TAG_IDENTIFIER,
false => NO_TAG_IDENTIFIER,
};

Ok((
seed.deserialize(BorrowedStrDeserializer::<Self::Error>::new(variant))?,
self,
))
}
}

impl<'a, 'de> de::VariantAccess<'de> for EnumTagAccess<'a, 'de> {
type Error = DecodeError;

fn unit_variant(self) -> Result<(), Self::Error> {
Err(de::Error::invalid_type(
de::Unexpected::UnitVariant,
&"NoTag or Tag variant",
))
}

fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
seed.deserialize(&mut *self.deserializer)
}

fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_seq(SeqTagAccess::new(self.tag, self.deserializer))
}

fn struct_variant<V>(
self
, _fields: &'static [&'static str]
, _visitor: V
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Err(de::Error::invalid_type(
de::Unexpected::StructVariant,
&"NoTag or Tag variant",
))
}
}
1 change: 1 addition & 0 deletions minicbor-serde/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ extern crate alloc;

mod de;
mod ser;
pub mod tag;
pub mod error;

pub use de::{Deserializer, from_slice};
Expand Down
Loading