Skip to content
Draft
112 changes: 90 additions & 22 deletions src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
error::{Result, SpannedResult},
extensions::Extensions,
options::Options,
parse::{NewtypeMode, ParsedByteStr, ParsedStr, Parser, StructType, TupleMode},
parse::{NewtypeMode, ParsedByteStr, ParsedStr, Parser, ParserCursor, StructType, TupleMode},
};

#[cfg(feature = "std")]
Expand Down Expand Up @@ -173,7 +173,12 @@ impl<'de> Deserializer<'de> {
/// struct and deserializes it accordingly.
///
/// This method assumes there is no identifier left.
fn handle_any_struct<V>(&mut self, visitor: V, ident: Option<&str>) -> Result<V::Value>
fn handle_any_struct<V>(
&mut self,
visitor: V,
ident: Option<&str>,
cursor: ParserCursor,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
Expand All @@ -185,33 +190,42 @@ impl<'de> Deserializer<'de> {
let old_serde_content_newtype = self.serde_content_newtype;
self.serde_content_newtype = false;

match (
self.parser.check_struct_type(
NewtypeMode::NoParensMeanUnit,
if old_serde_content_newtype {
TupleMode::DifferentiateNewtype // separate match on NewtypeOrTuple below
} else {
TupleMode::ImpreciseTupleOrNewtype // Tuple and NewtypeOrTuple match equally
},
)?,
ident,
) {
let struct_type = self.parser.check_struct_type(
NewtypeMode::NoParensMeanUnit,
if old_serde_content_newtype {
TupleMode::DifferentiateNewtype // separate match on NewtypeOrTuple below
} else {
TupleMode::ImpreciseTupleOrNewtype // Tuple and NewtypeOrTuple match equally
},
)?;

match (struct_type, ident) {
(StructType::Unit, Some(ident)) if is_serde_content => {
// serde's Content type needs the ident for unit variants
visitor.visit_str(ident)
}
(StructType::Unit, _) => visitor.visit_unit(),
(StructType::Unit, Some(ident)) => {
self.parser.cursor = cursor;
let enum_access = Enum::new(self, EnumKind::Unit);
visitor.visit_enum(enum_access)
}
(StructType::Unit, None) => visitor.visit_unit(),
(_, Some(ident)) if is_serde_content => {
// serde's Content type uses a singleton map encoding for enums
visitor.visit_map(SerdeEnumContent {
de: self,
ident: Some(ident),
})
}
(StructType::Named, _) => {
(StructType::Named, None) => {
// giving no name results in worse errors but is necessary here
self.handle_struct_after_name("", visitor)
}
(StructType::Named, Some(ident)) => {
self.parser.cursor = cursor;
let enum_access = Enum::new(self, EnumKind::Struct);
visitor.visit_enum(enum_access)
}
(StructType::NewtypeTuple, _) if old_serde_content_newtype => {
// deserialize a newtype struct or variant
self.parser.consume_char('(');
Expand All @@ -222,12 +236,28 @@ impl<'de> Deserializer<'de> {

result
}
(StructType::AnyTuple | StructType::NonNewtypeTuple, Some(indent)) => {
self.parser.cursor = cursor;
let enum_access = Enum::new(self, EnumKind::Tuple);
visitor.visit_enum(enum_access)
}
(StructType::EmptyTuple, Some(indent)) => {
self.parser.cursor = cursor;
// should we use unit ?
let enum_access = Enum::new(self, EnumKind::Tuple);
visitor.visit_enum(enum_access)
}
(StructType::NewtypeTuple, Some(indent)) => {
self.parser.cursor = cursor;
let enum_access = Enum::new(self, EnumKind::NewType);
visitor.visit_enum(enum_access)
}
(
StructType::AnyTuple
| StructType::EmptyTuple
| StructType::NewtypeTuple
| StructType::NonNewtypeTuple,
_,
None,
) => {
// first argument is technically incorrect, but ignored anyway
self.deserialize_tuple(0, visitor)
Expand Down Expand Up @@ -341,15 +371,17 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
return visitor.visit_f64(core::f64::NAN);
}

let parser_save = self.parser.cursor.clone();

// `skip_identifier` does not change state if it fails
if let Some(ident) = self.parser.skip_identifier() {
self.parser.skip_ws()?;

return self.handle_any_struct(visitor, Some(ident));
return self.handle_any_struct(visitor, Some(ident), parser_save);
}

match self.parser.peek_char_or_eof()? {
'(' => self.handle_any_struct(visitor, None),
'(' => self.handle_any_struct(visitor, None, parser_save),
'[' => self.deserialize_seq(visitor),
'{' => self.deserialize_map(visitor),
'0'..='9' | '+' | '-' | '.' => self.parser.any_number()?.visit(visitor),
Expand Down Expand Up @@ -744,7 +776,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
{
self.newtype_variant = false;

match guard_recursion! { self => visitor.visit_enum(Enum::new(self)) } {
match guard_recursion! { self => visitor.visit_enum(Enum::new(self, EnumKind::Unknown)) } {
Ok(value) => Ok(value),
Err(Error::NoSuchEnumVariant {
expected,
Expand Down Expand Up @@ -904,13 +936,22 @@ impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> {
}
}

enum EnumKind {
Unknown,
Unit,
NewType,
Tuple,
Struct,
}

struct Enum<'a, 'de: 'a> {
de: &'a mut Deserializer<'de>,
kind: EnumKind,
}

impl<'a, 'de> Enum<'a, 'de> {
fn new(de: &'a mut Deserializer<'de>) -> Self {
Enum { de }
fn new(de: &'a mut Deserializer<'de>, kind: EnumKind) -> Self {
Enum { de, kind }
}
}

Expand All @@ -934,13 +975,26 @@ impl<'de, 'a> de::VariantAccess<'de> for Enum<'a, 'de> {
type Error = Error;

fn unit_variant(self) -> Result<()> {
Ok(())
// todo: consume () if exist ?
match self.kind {
EnumKind::Unknown | EnumKind::Unit => Ok(()),
EnumKind::NewType => Err(Error::ExpectedNamedNewType),
EnumKind::Tuple => Err(Error::ExpectedNamedTuple),
EnumKind::Struct => Err(Error::ExpectedNamedStruct),
}
}

fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
where
T: DeserializeSeed<'de>,
{
match self.kind {
EnumKind::Unknown | EnumKind::NewType => {}
EnumKind::Unit => return Err(Error::ExpectedNamedUnit),
EnumKind::Tuple => return Err(Error::ExpectedNamedTuple),
EnumKind::Struct => return Err(Error::ExpectedNamedStruct),
}

let newtype_variant = self.de.last_identifier;

self.de.parser.skip_ws()?;
Expand Down Expand Up @@ -978,6 +1032,13 @@ impl<'de, 'a> de::VariantAccess<'de> for Enum<'a, 'de> {
where
V: Visitor<'de>,
{
match self.kind {
EnumKind::Unknown | EnumKind::Tuple => {}
EnumKind::Unit => return Err(Error::ExpectedNamedUnit),
EnumKind::NewType => return Err(Error::ExpectedNamedNewType),
EnumKind::Struct => return Err(Error::ExpectedNamedStruct),
}

self.de.parser.skip_ws()?;

self.de.deserialize_tuple(len, visitor)
Expand All @@ -987,6 +1048,13 @@ impl<'de, 'a> de::VariantAccess<'de> for Enum<'a, 'de> {
where
V: Visitor<'de>,
{
match self.kind {
EnumKind::Unknown | EnumKind::Struct => {}
EnumKind::Unit => return Err(Error::ExpectedNamedUnit),
EnumKind::Tuple => return Err(Error::ExpectedNamedTuple),
EnumKind::NewType => return Err(Error::ExpectedNamedNewType),
}

let struct_variant = self.de.last_identifier;

self.de.parser.skip_ws()?;
Expand Down
83 changes: 77 additions & 6 deletions src/de/value.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use alloc::{borrow::ToOwned, boxed::Box, string::String, vec::Vec};
use core::fmt;
use std::borrow::Cow;

use serde::{
de::{Error, MapAccess, SeqAccess, Visitor},
Expand Down Expand Up @@ -214,14 +215,14 @@ impl<'de> Visitor<'de> for ValueVisitor {
vec.push(x);
}

Ok(Value::Seq(vec))
Ok(Value::List(vec))
}

fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut res: Map = Map::new();
let mut res: Map<Value> = Map::new();

#[cfg(feature = "indexmap")]
if let Some(cap) = map.size_hint() {
Expand All @@ -234,6 +235,76 @@ impl<'de> Visitor<'de> for ValueVisitor {

Ok(Value::Map(res))
}

fn visit_enum<A>(self, mut data: A) -> Result<Self::Value, A::Error>
where
A: serde::de::EnumAccess<'de>,
{
// Get the variant name and the VariantAccess
let (variant, variant_access) = data.variant::<Ident>()?;


// Try to extract the value for the variant
use serde::de::VariantAccess;

let value = if let Ok(v) = variant_access.unit_variant() {
Value::NamedUnit {
name: variant.0.into(),
}
} else if let Ok(v) = variant_access.newtype_variant() {
Value::NamedNewtype {
name: variant.0.into(),
inner: Box::new(v),
}
} else if let Ok(v) = variant_access.tuple_variant(0, ValueVisitor) {
if let Value::Tuple(values) = v {
Value::NamedTuple(variant.0.into(), values)
} else {
return Err(A::Error::custom("Expected Value::Tuple"));
}
} else if let Ok(v) = variant_access.struct_variant(&[], ValueVisitor) {
if let Value::Map(values) = v {
let mut values_new: Map<Cow<'static, str>> = Map::new();

for e in values {
if let Value::String(k) = e.0 {
values_new.insert(<std::string::String as Into<Cow<str>>>::into(k), e.1);
} else {
return Err(A::Error::custom("Expected Value::String for the key"));
}
}

Value::NamedMap(variant.0.into(), values_new)
} else {
return Err(A::Error::custom("Expected Value::Map"));
}
} else {
// fallback: treat as unit
Value::Unit
};

Ok(value)
}
}

// todo: use id::Deserializer ?
struct Ident(String);

impl<'de> Deserialize<'de> for Ident {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer
.deserialize_identifier(ValueVisitor)
.and_then(|e| {
if let Value::String(ident) = e {
Ok(Ident(ident))
} else {
unreachable!()
}
})
}
}

#[cfg(test)]
Expand Down Expand Up @@ -265,7 +336,7 @@ mod tests {
fn test_tuples_basic() {
assert_eq!(
eval("(3, 4.0, 5.0)"),
Value::Seq(vec![
Value::List(vec![
Value::Number(Number::U8(3)),
Value::Number(Number::F32(4.0.into())),
Value::Number(Number::F32(5.0.into())),
Expand All @@ -277,7 +348,7 @@ mod tests {
fn test_tuples_ident() {
assert_eq!(
eval("(true, 3, 4, 5.0)"),
Value::Seq(vec![
Value::List(vec![
Value::Bool(true),
Value::Number(Number::U8(3)),
Value::Number(Number::U8(4)),
Expand Down Expand Up @@ -306,7 +377,7 @@ mod tests {
fn test_floats() {
assert_eq!(
eval("(inf, -inf, NaN)"),
Value::Seq(vec![
Value::List(vec![
Value::Number(Number::new(core::f32::INFINITY)),
Value::Number(Number::new(core::f32::NEG_INFINITY)),
Value::Number(Number::new(core::f32::NAN)),
Expand All @@ -333,7 +404,7 @@ mod tests {
),
])"
),
Value::Option(Some(Box::new(Value::Seq(vec![
Value::Option(Some(Box::new(Value::List(vec![
Value::Map(
vec![
(
Expand Down
9 changes: 9 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ pub enum Error {
ExpectedRawValue,
ExceededRecursionLimit,
ExpectedStructName(String),

ExpectedNamedUnit,
ExpectedNamedNewType,
ExpectedNamedTuple,
ExpectedNamedStruct,
}

impl fmt::Display for SpannedError {
Expand Down Expand Up @@ -293,6 +298,10 @@ impl fmt::Display for Error {
"Expected the explicit struct name {}, but none was found",
Identifier(name)
),
Error::ExpectedNamedUnit => write!(f, "ExpectedNamedUnit"),
Error::ExpectedNamedNewType => write!(f, "ExpectedNamedNewType"),
Error::ExpectedNamedTuple => write!(f, "ExpectedNamedTuple"),
Error::ExpectedNamedStruct => write!(f, "ExpectedNamedStruct"),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(warnings)]
#![deny(clippy::correctness)]
#![deny(clippy::suspicious)]
#![deny(clippy::complexity)]
Expand Down
2 changes: 1 addition & 1 deletion src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub struct Parser<'a> {
/// Bits set according to the [`Extensions`] enum.
pub exts: Extensions,
src: &'a str,
cursor: ParserCursor,
pub cursor: ParserCursor,
prev_cursor: ParserCursor,
}

Expand Down
Loading