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
138 changes: 135 additions & 3 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::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(u64),
Copy link
Owner

Choose a reason for hiding this comment

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

Why not a minicbor::data::Tag?

Suggested change
Tag(u64),
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<u64>, 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
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.

Ok(Some(
seed.deserialize(U64Deserializer::<DecodeError>::new(tag))?,
))
}
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<u64>,
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
tag: Option<u64>,
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()?.as_u64()),
_ => 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