Skip to content
Prev Previous commit
Next Next commit
Make errors std::Error, std::Vec not heapless
  • Loading branch information
ethanfrey committed Oct 25, 2019
commit 2022b8238add9f45bad9f1f5600dad6f6c2b8401
95 changes: 50 additions & 45 deletions src/de/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Deserialize JSON data to a Rust data structure

use core::{fmt, str};
use std::{fmt, error};

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

Expand Down Expand Up @@ -67,13 +67,59 @@ pub enum Error {
__Extensible,
}

#[cfg(feature = "std")]
impl ::std::error::Error for Error {
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}

fn description(&self) -> &str {
""
"(use display)"
}
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
Error::EofWhileParsingList => "EOF while parsing a list.",
Error::EofWhileParsingObject => "EOF while parsing an object.",
Error::EofWhileParsingString => "EOF while parsing a string.",
Error::EofWhileParsingValue => "EOF while parsing a JSON value.",
Error::ExpectedColon => "Expected this character to be a `':'`.",
Error::ExpectedListCommaOrEnd => {
"Expected this character to be either a `','` or\
a \
`']'`."
}
Error::ExpectedObjectCommaOrEnd => {
"Expected this character to be either a `','` \
or a \
`'}'`."
}
Error::ExpectedSomeIdent => {
"Expected to parse either a `true`, `false`, or a \
`null`."
}
Error::ExpectedSomeValue => "Expected this character to start a JSON value.",
Error::InvalidNumber => "Invalid number.",
Error::InvalidType => "Invalid type",
Error::InvalidUnicodeCodePoint => "Invalid unicode code point.",
Error::KeyMustBeAString => "Object key is not a string.",
Error::TrailingCharacters => {
"JSON has non-whitespace trailing characters after \
the \
value."
}
Error::TrailingComma => "JSON has a comma after the last value in an array or map.",
_ => "Invalid JSON",
}
)
}
}


pub(crate) struct Deserializer<'b> {
slice: &'b [u8],
index: usize,
Expand Down Expand Up @@ -558,47 +604,6 @@ impl de::Error for Error {
}
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
Error::EofWhileParsingList => "EOF while parsing a list.",
Error::EofWhileParsingObject => "EOF while parsing an object.",
Error::EofWhileParsingString => "EOF while parsing a string.",
Error::EofWhileParsingValue => "EOF while parsing a JSON value.",
Error::ExpectedColon => "Expected this character to be a `':'`.",
Error::ExpectedListCommaOrEnd => {
"Expected this character to be either a `','` or\
a \
`']'`."
}
Error::ExpectedObjectCommaOrEnd => {
"Expected this character to be either a `','` \
or a \
`'}'`."
}
Error::ExpectedSomeIdent => {
"Expected to parse either a `true`, `false`, or a \
`null`."
}
Error::ExpectedSomeValue => "Expected this character to start a JSON value.",
Error::InvalidNumber => "Invalid number.",
Error::InvalidType => "Invalid type",
Error::InvalidUnicodeCodePoint => "Invalid unicode code point.",
Error::KeyMustBeAString => "Object key is not a string.",
Error::TrailingCharacters => {
"JSON has non-whitespace trailing characters after \
the \
value."
}
Error::TrailingComma => "JSON has a comma after the last value in an array or map.",
_ => "Invalid JSON",
}
)
}
}

/// Deserializes an instance of type `T` from bytes of JSON text
pub fn from_slice<'a, T>(v: &'a [u8]) -> Result<T>
Expand Down
76 changes: 33 additions & 43 deletions src/ser/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
//! Serialize a Rust data structure into JSON data

use core::{fmt, mem};
use std::{fmt, error};

use serde::ser;

use heapless::{String, Vec};
use std::vec::Vec;

use self::seq::SerializeSeq;
use self::struct_::SerializeStruct;
Expand Down Expand Up @@ -36,10 +36,14 @@ impl From<u8> for Error {
}
}

#[cfg(feature = "std")]
impl ::std::error::Error for Error {

impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}

fn description(&self) -> &str {
""
"(use display)"
}
}

Expand All @@ -49,17 +53,12 @@ impl fmt::Display for Error {
}
}

pub(crate) struct Serializer<B>
where
B: heapless::ArrayLength<u8>,
pub(crate) struct Serializer
{
buf: Vec<u8, B>,
buf: Vec<u8>,
}

impl<B> Serializer<B>
where
B: heapless::ArrayLength<u8>,
{
impl Serializer {
fn new() -> Self {
Serializer { buf: Vec::new() }
}
Expand Down Expand Up @@ -123,18 +122,15 @@ macro_rules! serialize_signed {
}};
}

impl<'a, B> ser::Serializer for &'a mut Serializer<B>
where
B: heapless::ArrayLength<u8>,
{
impl<'a> ser::Serializer for &'a mut Serializer {
type Ok = ();
type Error = Error;
type SerializeSeq = SerializeSeq<'a, B>;
type SerializeTuple = SerializeSeq<'a, B>;
type SerializeSeq = SerializeSeq<'a>;
type SerializeTuple = SerializeSeq<'a>;
type SerializeTupleStruct = Unreachable;
type SerializeTupleVariant = Unreachable;
type SerializeMap = Unreachable;
type SerializeStruct = SerializeStruct<'a, B>;
type SerializeStruct = SerializeStruct<'a>;
type SerializeStructVariant = Unreachable;

fn serialize_bool(self, v: bool) -> Result<Self::Ok> {
Expand Down Expand Up @@ -320,9 +316,8 @@ where
}

/// Serializes the given data structure as a string of JSON text
pub fn to_string<B, T>(value: &T) -> Result<String<B>>
pub fn to_string<T>(value: &T) -> Result<String>
where
B: heapless::ArrayLength<u8>,
T: ser::Serialize + ?Sized,
{
let mut ser = Serializer::new();
Expand All @@ -331,9 +326,8 @@ where
}

/// Serializes the given data structure as a JSON byte vector
pub fn to_vec<B, T>(value: &T) -> Result<Vec<u8, B>>
pub fn to_vec<T>(value: &T) -> Result<Vec<u8>>
where
B: heapless::ArrayLength<u8>,
T: ser::Serialize + ?Sized,
{
let mut ser = Serializer::new();
Expand Down Expand Up @@ -421,18 +415,14 @@ impl ser::SerializeStructVariant for Unreachable {
mod tests {
use serde_derive::Serialize;

use heapless::consts::U128;

type N = U128;

#[test]
fn array() {
assert_eq!(&*crate::to_string::<N, _>(&[0, 1, 2]).unwrap(), "[0,1,2]");
assert_eq!(&*crate::to_string(&[0, 1, 2]).unwrap(), "[0,1,2]");
}

#[test]
fn bool() {
assert_eq!(&*crate::to_string::<N, _>(&true).unwrap(), "true");
assert_eq!(&*crate::to_string(&true).unwrap(), "true");
}

#[test]
Expand All @@ -446,19 +436,19 @@ mod tests {
}

assert_eq!(
&*crate::to_string::<N, _>(&Type::Boolean).unwrap(),
&*crate::to_string(&Type::Boolean).unwrap(),
r#""boolean""#
);

assert_eq!(
&*crate::to_string::<N, _>(&Type::Number).unwrap(),
&*crate::to_string(&Type::Number).unwrap(),
r#""number""#
);
}

#[test]
fn str() {
assert_eq!(&*crate::to_string::<N, _>("hello").unwrap(), r#""hello""#);
assert_eq!(&*crate::to_string("hello").unwrap(), r#""hello""#);
}

#[test]
Expand All @@ -469,7 +459,7 @@ mod tests {
}

assert_eq!(
&*crate::to_string::<N, _>(&Led { led: true }).unwrap(),
&*crate::to_string(&Led { led: true }).unwrap(),
r#"{"led":true}"#
);
}
Expand All @@ -482,22 +472,22 @@ mod tests {
}

assert_eq!(
&*crate::to_string::<N, _>(&Temperature { temperature: 127 }).unwrap(),
&*crate::to_string(&Temperature { temperature: 127 }).unwrap(),
r#"{"temperature":127}"#
);

assert_eq!(
&*crate::to_string::<N, _>(&Temperature { temperature: 20 }).unwrap(),
&*crate::to_string(&Temperature { temperature: 20 }).unwrap(),
r#"{"temperature":20}"#
);

assert_eq!(
&*crate::to_string::<N, _>(&Temperature { temperature: -17 }).unwrap(),
&*crate::to_string(&Temperature { temperature: -17 }).unwrap(),
r#"{"temperature":-17}"#
);

assert_eq!(
&*crate::to_string::<N, _>(&Temperature { temperature: -128 }).unwrap(),
&*crate::to_string(&Temperature { temperature: -128 }).unwrap(),
r#"{"temperature":-128}"#
);
}
Expand All @@ -510,7 +500,7 @@ mod tests {
}

assert_eq!(
crate::to_string::<N, _>(&Property {
crate::to_string(&Property {
description: Some("An ambient temperature sensor"),
})
.unwrap(),
Expand All @@ -519,7 +509,7 @@ mod tests {

// XXX Ideally this should produce "{}"
assert_eq!(
crate::to_string::<N, _>(&Property { description: None }).unwrap(),
crate::to_string(&Property { description: None }).unwrap(),
r#"{"description":null}"#
);
}
Expand All @@ -532,7 +522,7 @@ mod tests {
}

assert_eq!(
&*crate::to_string::<N, _>(&Temperature { temperature: 20 }).unwrap(),
&*crate::to_string(&Temperature { temperature: 20 }).unwrap(),
r#"{"temperature":20}"#
);
}
Expand All @@ -542,7 +532,7 @@ mod tests {
#[derive(Serialize)]
struct Empty {}

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

#[derive(Serialize)]
struct Tuple {
Expand All @@ -551,7 +541,7 @@ mod tests {
}

assert_eq!(
&*crate::to_string::<N, _>(&Tuple { a: true, b: false }).unwrap(),
&*crate::to_string(&Tuple { a: true, b: false }).unwrap(),
r#"{"a":true,"b":false}"#
);
}
Expand Down
24 changes: 6 additions & 18 deletions src/ser/seq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,18 @@ use heapless::ArrayLength;

use crate::ser::{Error, Result, Serializer};

pub struct SerializeSeq<'a, B>
where
B: ArrayLength<u8>,
{
de: &'a mut Serializer<B>,
pub struct SerializeSeq<'a> {
de: &'a mut Serializer,
first: bool,
}

impl<'a, B> SerializeSeq<'a, B>
where
B: ArrayLength<u8>,
{
pub(crate) fn new(de: &'a mut Serializer<B>) -> Self {
impl<'a> SerializeSeq<'a> {
pub(crate) fn new(de: &'a mut Serializer) -> Self {
SerializeSeq { de, first: true }
}
}

impl<'a, B> ser::SerializeSeq for SerializeSeq<'a, B>
where
B: ArrayLength<u8>,
{
impl<'a> ser::SerializeSeq for SerializeSeq<'a> {
type Ok = ();
type Error = Error;

Expand All @@ -47,10 +38,7 @@ where
}
}

impl<'a, B> ser::SerializeTuple for SerializeSeq<'a, B>
where
B: ArrayLength<u8>,
{
impl<'a> ser::SerializeTuple for SerializeSeq<'a> {
type Ok = ();
type Error = Error;

Expand Down
Loading