Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:

include:
# Test MSRV
- rust: 1.36.0
- rust: 1.40.0
TARGET: x86_64-unknown-linux-gnu

# Test nightly but don't fail
Expand Down
53 changes: 53 additions & 0 deletions src/de/enum_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,56 @@ impl<'de, 'a> de::VariantAccess<'de> for UnitVariantAccess<'a, 'de> {
Err(Error::InvalidType)
}
}

pub(crate) struct VariantAccess<'a, 'b> {
de: &'a mut Deserializer<'b>,
}

impl<'a, 'b> VariantAccess<'a, 'b> {
pub(crate) fn new(de: &'a mut Deserializer<'b>) -> Self {
VariantAccess { de }
}
}

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

fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self)>
where
V: de::DeserializeSeed<'de>,
{
let variant = seed.deserialize(&mut *self.de)?;
self.de.parse_object_colon()?;
Ok((variant, self))
}
}

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

fn unit_variant(self) -> Result<()> {
de::Deserialize::deserialize(self.de)
}

fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
where
T: de::DeserializeSeed<'de>,
{
seed.deserialize(self.de)
}

fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
{
de::Deserializer::deserialize_seq(self.de, visitor)
}

fn struct_variant<V>(self, fields: &'static [&'static str], visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
{
de::Deserializer::deserialize_struct(self.de, "", fields, visitor)
}
}
80 changes: 68 additions & 12 deletions src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use core::{fmt, str};

use serde::de::{self, Visitor};

use self::enum_::UnitVariantAccess;
use self::enum_::{UnitVariantAccess, VariantAccess};
use self::map::MapAccess;
use self::seq::SeqAccess;

Expand All @@ -18,6 +18,7 @@ pub type Result<T> = core::result::Result<T, Error>;

/// This type represents all possible errors that can occur when deserializing JSON data
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub enum Error {
/// EOF while parsing a list.
EofWhileParsingList,
Expand Down Expand Up @@ -73,9 +74,6 @@ pub enum Error {
/// Error with a custom message that was preserved.
#[cfg(feature = "custom-error-messages")]
CustomErrorWithMessage(heapless::String<heapless::consts::U64>),

#[doc(hidden)]
__Extensible,
}

#[cfg(feature = "std")]
Expand Down Expand Up @@ -498,28 +496,40 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
}
}

/// Unsupported. Use a more specific deserialize_* method
fn deserialize_unit<V>(self, _visitor: V) -> Result<V::Value>
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
unreachable!()
let peek = match self.parse_whitespace() {
Some(b) => b,
None => {
return Err(Error::EofWhileParsingValue);
}
};

match peek {
b'n' => {
self.eat_char();
self.parse_ident(b"ull")?;
visitor.visit_unit()
}
_ => Err(Error::InvalidType),
}
}

/// Unsupported. Use a more specific deserialize_* method
fn deserialize_unit_struct<V>(self, _name: &'static str, _visitor: V) -> Result<V::Value>
fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
unreachable!()
self.deserialize_unit(visitor)
}

/// Unsupported. We can’t parse newtypes because we don’t know the underlying type.
fn deserialize_newtype_struct<V>(self, _name: &'static str, _visitor: V) -> Result<V::Value>
fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
unreachable!()
visitor.visit_newtype_struct(self)
}

fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
Expand Down Expand Up @@ -600,6 +610,17 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
{
match self.parse_whitespace().ok_or(Error::EofWhileParsingValue)? {
b'"' => visitor.visit_enum(UnitVariantAccess::new(self)),
b'{' => {
self.eat_char();
let value = visitor.visit_enum(VariantAccess::new(self))?;
match self.parse_whitespace().ok_or(Error::EofWhileParsingValue)? {
b'}' => {
self.eat_char();
Ok(value)
}
_ => Err(Error::ExpectedSomeValue),
}
}
_ => Err(Error::ExpectedSomeValue),
}
}
Expand Down Expand Up @@ -961,6 +982,41 @@ mod tests {
assert!(crate::from_str::<Temperature>(r#"{ "temperature": -1 }"#).is_err());
}

#[test]
fn test_unit() {
assert_eq!(crate::from_str::<()>(r#"null"#), Ok(((), 4)));
}

#[test]
fn newtype_struct() {
#[derive(Deserialize, Debug, PartialEq)]
struct A(pub u32);

assert_eq!(crate::from_str::<A>(r#"54"#), Ok((A(54), 2)));
}

#[test]
fn test_newtype_variant() {
#[derive(Deserialize, Debug, PartialEq)]
enum A {
A(u32),
}
let a = A::A(54);
let x = crate::from_str::<A>(r#"{"A":54}"#);
assert_eq!(x, Ok((a, 8)));
}

#[test]
fn test_struct_variant() {
#[derive(Deserialize, Debug, PartialEq)]
enum A {
A { x: u32, y: u16 },
}
let a = A::A { x: 54, y: 720 };
let x = crate::from_str::<A>(r#"{"A": {"x":54,"y":720 } }"#);
assert_eq!(x, Ok((a, 25)));
}

#[test]
#[cfg(not(feature = "custom-error-messages"))]
fn struct_tuple() {
Expand Down
97 changes: 62 additions & 35 deletions src/ser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
use core::{fmt, fmt::Write};

use serde::ser;
use serde::ser::SerializeStruct as _;

use heapless::{consts::*, String, Vec};

use self::map::SerializeMap;
use self::seq::SerializeSeq;
use self::struct_::SerializeStruct;
use self::struct_::{SerializeStruct, SerializeStructVariant};

mod map;
mod seq;
Expand All @@ -19,11 +20,10 @@ pub type Result<T> = ::core::result::Result<T, Error>;

/// This type represents all possible errors that can occur when serializing JSON data
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
/// Buffer is full
BufferFull,
#[doc(hidden)]
__Extensible,
}

impl From<()> for Error {
Expand Down Expand Up @@ -84,7 +84,7 @@ impl<'a> Serializer<'a> {
Err(Error::BufferFull)
} else {
for c in other {
unsafe { self.push_unchecked(c.clone()) };
unsafe { self.push_unchecked(*c) };
}
Ok(())
}
Expand Down Expand Up @@ -178,7 +178,7 @@ impl<'a, 'b: 'a> ser::Serializer for &'a mut Serializer<'b> {
type SerializeTupleVariant = Unreachable;
type SerializeMap = SerializeMap<'a, 'b>;
type SerializeStruct = SerializeStruct<'a, 'b>;
type SerializeStructVariant = Unreachable;
type SerializeStructVariant = SerializeStructVariant<'a, 'b>;

fn serialize_bool(self, v: bool) -> Result<Self::Ok> {
if v {
Expand Down Expand Up @@ -320,11 +320,11 @@ impl<'a, 'b: 'a> ser::Serializer for &'a mut Serializer<'b> {
}

fn serialize_unit(self) -> Result<Self::Ok> {
unreachable!()
self.serialize_none()
}

fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok> {
unreachable!()
self.serialize_unit()
}

fn serialize_unit_variant(
Expand All @@ -336,28 +336,28 @@ impl<'a, 'b: 'a> ser::Serializer for &'a mut Serializer<'b> {
self.serialize_str(variant)
}

fn serialize_newtype_struct<T: ?Sized>(
self,
_name: &'static str,
_value: &T,
) -> Result<Self::Ok>
fn serialize_newtype_struct<T: ?Sized>(self, _name: &'static str, value: &T) -> Result<Self::Ok>
where
T: ser::Serialize,
{
unreachable!()
value.serialize(self)
}

fn serialize_newtype_variant<T: ?Sized>(
self,
mut self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_value: &T,
variant: &'static str,
value: &T,
) -> Result<Self::Ok>
where
T: ser::Serialize,
{
unreachable!()
self.push(b'{')?;
let mut s = SerializeStruct::new(&mut self);
s.serialize_field(variant, value)?;
s.end()?;
Ok(())
}

fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
Expand Down Expand Up @@ -404,10 +404,14 @@ impl<'a, 'b: 'a> ser::Serializer for &'a mut Serializer<'b> {
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
variant: &'static str,
_len: usize,
) -> Result<Self::SerializeStructVariant> {
unreachable!()
self.extend_from_slice(b"{\"")?;
self.extend_from_slice(variant.as_bytes())?;
self.extend_from_slice(b"\":{")?;

Ok(SerializeStructVariant::new(self))
}

fn collect_str<T: ?Sized>(self, _value: &T) -> Result<Self::Ok>
Expand Down Expand Up @@ -510,22 +514,6 @@ impl ser::SerializeMap for Unreachable {
}
}

impl ser::SerializeStructVariant for Unreachable {
type Ok = ();
type Error = Error;

fn serialize_field<T: ?Sized>(&mut self, _key: &'static str, _value: &T) -> Result<()>
where
T: ser::Serialize,
{
unreachable!()
}

fn end(self) -> Result<Self::Ok> {
unreachable!()
}
}

#[cfg(test)]
mod tests {
use serde_derive::Serialize;
Expand Down Expand Up @@ -768,4 +756,43 @@ mod tests {
r#"{"a":true,"b":false}"#
);
}

#[test]
fn test_unit() {
let a = ();
assert_eq!(&*crate::to_string::<N, _>(&a).unwrap(), r#"null"#);
}

#[test]
fn test_newtype_struct() {
#[derive(Serialize)]
struct A(pub u32);
let a = A(54);
assert_eq!(&*crate::to_string::<N, _>(&a).unwrap(), r#"54"#);
}

#[test]
fn test_newtype_variant() {
#[derive(Serialize)]
enum A {
A(u32),
}
let a = A::A(54);

assert_eq!(&*crate::to_string::<N, _>(&a).unwrap(), r#"{"A":54}"#);
}

#[test]
fn test_struct_variant() {
#[derive(Serialize)]
enum A {
A { x: u32, y: u16 },
}
let a = A::A { x: 54, y: 720 };

assert_eq!(
&*crate::to_string::<N, _>(&a).unwrap(),
r#"{"A":{"x":54,"y":720}}"#
);
}
}
Loading