add alloc/no_std support

This commit is contained in:
freax13 2019-11-26 20:11:07 +01:00 committed by Igor Matuszewski
parent 88ee1a69da
commit 4600a9af7f
16 changed files with 301 additions and 39 deletions

View File

@ -16,7 +16,7 @@ travis-ci = { repository = "serde-rs/json" }
appveyor = { repository = "serde-rs/json" } appveyor = { repository = "serde-rs/json" }
[dependencies] [dependencies]
serde = "1.0.60" serde = { version = "1.0.60", default-features = false }
indexmap = { version = "1.2", optional = true } indexmap = { version = "1.2", optional = true }
itoa = "0.4.3" itoa = "0.4.3"
ryu = "1.0" ryu = "1.0"
@ -42,7 +42,11 @@ features = ["raw_value"]
### FEATURES ################################################################# ### FEATURES #################################################################
[features] [features]
default = [] default = ["std"]
std = ["serde/std"]
alloc = ["serde/alloc"]
# Use a different representation for the map type of serde_json::Value. # Use a different representation for the map type of serde_json::Value.
# This allows data to be read into a Value and written back to a JSON string # This allows data to be read into a Value and written back to a JSON string

View File

@ -1,10 +1,14 @@
//! Deserialize JSON data to a Rust data structure. //! Deserialize JSON data to a Rust data structure.
use std::io; use io;
use std::marker::PhantomData; use core::marker::PhantomData;
use std::result; use core::result;
use std::str::FromStr; use core::str::FromStr;
use std::{i32, u64}; use core::{i32, u64};
#[cfg(feature = "alloc")]
use alloc::string::String;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use serde::de::{self, Expected, Unexpected}; use serde::de::{self, Expected, Unexpected};

View File

@ -1,10 +1,15 @@
//! When serializing or deserializing JSON goes wrong. //! When serializing or deserializing JSON goes wrong.
#[cfg(feature = "std")]
use std::error; use std::error;
use std::fmt::{self, Debug, Display}; use core::fmt::{self, Debug, Display};
use std::io; use io;
use std::result; use core::result;
use std::str::FromStr; use core::str::FromStr;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[cfg(feature = "alloc")]
use alloc::string::{String, ToString};
use serde::de; use serde::de;
use serde::ser; use serde::ser;
@ -131,6 +136,7 @@ pub enum Category {
} }
#[cfg_attr(feature = "cargo-clippy", allow(fallible_impl_from))] #[cfg_attr(feature = "cargo-clippy", allow(fallible_impl_from))]
#[cfg(feature = "std")]
impl From<Error> for io::Error { impl From<Error> for io::Error {
/// Convert a `serde_json::Error` into an `io::Error`. /// Convert a `serde_json::Error` into an `io::Error`.
/// ///
@ -333,6 +339,7 @@ impl Display for ErrorCode {
} }
} }
#[cfg(feature = "std")]
impl error::Error for Error { impl error::Error for Error {
fn source(&self) -> Option<&(error::Error + 'static)> { fn source(&self) -> Option<&(error::Error + 'static)> {
match self.err.code { match self.err.code {
@ -342,6 +349,9 @@ impl error::Error for Error {
} }
} }
#[cfg(not(feature = "std"))]
impl serde::de::StdError for Error {}
impl Display for Error { impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&*self.err, f) Display::fmt(&*self.err, f)

79
src/io.rs Normal file
View File

@ -0,0 +1,79 @@
#[cfg(not(feature = "std"))]
use core::slice;
#[cfg(feature = "std")]
pub use std::io::{Result, Write, Read, Error, Bytes, ErrorKind};
#[cfg(not(feature = "std"))]
pub type Error = &'static str;
#[cfg(not(feature = "std"))]
pub type Result<T> = core::result::Result<T, Error>;
#[cfg(not(feature = "std"))]
pub trait Write {
fn write(&mut self, buf: &[u8]) -> Result<usize>;
fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
while !buf.is_empty() {
match self.write(buf) {
Ok(0) => return Err("failed to write whole buffer"),
Ok(n) => buf = &buf[n..],
Err(e) => return Err(e),
}
}
Ok(())
}
fn flush(&mut self) -> Result<()>;
}
#[cfg(not(feature = "std"))]
impl<W: Write> Write for &mut W {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
(*self).write(buf)
}
fn flush(&mut self) -> Result<()> {
(*self).flush()
}
}
#[cfg(all(not(feature = "std"), feature = "alloc"))]
impl Write for &mut serde::export::Vec<u8> {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.extend(buf);
Ok(buf.len())
}
fn flush(&mut self) -> Result<()> {Ok(())}
}
#[cfg(not(feature = "std"))]
pub trait Read {
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
fn bytes(self) -> Bytes<Self> where Self: Sized {
Bytes {
inner: self,
}
}
}
#[cfg(not(feature = "std"))]
pub struct Bytes<R> {
inner: R,
}
#[cfg(not(feature = "std"))]
impl<R: Read> Iterator for Bytes<R> {
type Item = Result<u8>;
fn next(&mut self) -> Option<Result<u8>> {
let mut byte = 0;
match self.inner.read(slice::from_mut(&mut byte)) {
Ok(0) => None,
Ok(..) => Some(Ok(byte)),
Err(e) => Some(Err(e)),
}
}
}

View File

@ -1,4 +1,4 @@
use std::io; use io;
pub struct LineColIterator<I> { pub struct LineColIterator<I> {
iter: I, iter: I,

View File

@ -331,6 +331,7 @@
must_use_candidate, must_use_candidate,
))] ))]
#![deny(missing_docs)] #![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
#[macro_use] #[macro_use]
extern crate serde; extern crate serde;
@ -338,6 +339,10 @@ extern crate serde;
extern crate indexmap; extern crate indexmap;
extern crate itoa; extern crate itoa;
extern crate ryu; extern crate ryu;
#[cfg(feature = "std")]
extern crate core;
#[cfg(feature = "alloc")]
extern crate alloc;
#[doc(inline)] #[doc(inline)]
pub use self::de::{from_reader, from_slice, from_str, Deserializer, StreamDeserializer}; pub use self::de::{from_reader, from_slice, from_str, Deserializer, StreamDeserializer};
@ -355,8 +360,8 @@ pub use self::value::{from_value, to_value, Map, Number, Value};
macro_rules! try { macro_rules! try {
($e:expr) => { ($e:expr) => {
match $e { match $e {
::std::result::Result::Ok(val) => val, ::core::result::Result::Ok(val) => val,
::std::result::Result::Err(err) => return ::std::result::Result::Err(err), ::core::result::Result::Err(err) => return ::core::result::Result::Err(err),
} }
}; };
} }
@ -370,6 +375,7 @@ pub mod map;
pub mod ser; pub mod ser;
pub mod value; pub mod value;
mod io;
mod iter; mod iter;
mod number; mod number;
mod read; mod read;

View File

@ -7,15 +7,19 @@
//! [`IndexMap`]: https://docs.rs/indexmap/*/indexmap/map/struct.IndexMap.html //! [`IndexMap`]: https://docs.rs/indexmap/*/indexmap/map/struct.IndexMap.html
use serde::{de, ser}; use serde::{de, ser};
use std::borrow::Borrow; use core::borrow::Borrow;
use std::fmt::{self, Debug}; use core::fmt::{self, Debug};
use std::hash::Hash; use core::hash::Hash;
use std::iter::FromIterator; use core::iter::FromIterator;
use std::ops; use core::ops;
use value::Value; use value::Value;
#[cfg(feature = "alloc")]
use alloc::string::String;
#[cfg(not(feature = "preserve_order"))] #[cfg(all(not(feature = "preserve_order"), feature = "std"))]
use std::collections::{btree_map, BTreeMap}; use std::collections::{btree_map, BTreeMap};
#[cfg(all(not(feature = "preserve_order"), feature = "alloc"))]
use alloc::collections::{btree_map, BTreeMap};
#[cfg(feature = "preserve_order")] #[cfg(feature = "preserve_order")]
use indexmap::{self, IndexMap}; use indexmap::{self, IndexMap};
@ -151,8 +155,10 @@ impl Map<String, Value> {
{ {
#[cfg(feature = "preserve_order")] #[cfg(feature = "preserve_order")]
use indexmap::map::Entry as EntryImpl; use indexmap::map::Entry as EntryImpl;
#[cfg(not(feature = "preserve_order"))] #[cfg(all(not(feature = "preserve_order"), feature = "std"))]
use std::collections::btree_map::Entry as EntryImpl; use std::collections::btree_map::Entry as EntryImpl;
#[cfg(all(not(feature = "preserve_order"), feature = "alloc"))]
use alloc::collections::btree_map::Entry as EntryImpl;
match self.map.entry(key.into()) { match self.map.entry(key.into()) {
EntryImpl::Vacant(vacant) => Entry::Vacant(VacantEntry { vacant: vacant }), EntryImpl::Vacant(vacant) => Entry::Vacant(VacantEntry { vacant: vacant }),

View File

@ -1,7 +1,7 @@
use error::Error; use error::Error;
use serde::de::{self, Unexpected, Visitor}; use serde::de::{self, Unexpected, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::{self, Debug, Display}; use core::fmt::{self, Debug, Display};
#[cfg(feature = "arbitrary_precision")] #[cfg(feature = "arbitrary_precision")]
use itoa; use itoa;

View File

@ -1,5 +1,8 @@
use std::ops::Deref; use core::ops::Deref;
use std::{char, cmp, io, str}; use io;
use core::{char, cmp, str};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[cfg(feature = "raw_value")] #[cfg(feature = "raw_value")]
use serde::de::Visitor; use serde::de::Visitor;

View File

@ -1,9 +1,13 @@
//! Serialize a Rust data structure into JSON data. //! Serialize a Rust data structure into JSON data.
use std::fmt; use core::fmt;
use std::io; use io;
use std::num::FpCategory; use core::num::FpCategory;
use std::str; use core::str;
#[cfg(feature = "alloc")]
use alloc::string::{String, ToString};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use super::error::{Error, ErrorCode, Result}; use super::error::{Error, ErrorCode, Result};
use serde::ser::{self, Impossible, Serialize}; use serde::ser::{self, Impossible, Serialize};
@ -460,7 +464,7 @@ where
where where
T: fmt::Display, T: fmt::Display,
{ {
use std::fmt::Write; use core::fmt::Write;
struct Adapter<'ser, W: 'ser, F: 'ser> { struct Adapter<'ser, W: 'ser, F: 'ser> {
writer: &'ser mut W, writer: &'ser mut W,
@ -1634,6 +1638,7 @@ pub trait Formatter {
/// Writes an integer value like `-123` to the specified writer. /// Writes an integer value like `-123` to the specified writer.
#[inline] #[inline]
#[cfg(feature = "std")]
fn write_i8<W: ?Sized>(&mut self, writer: &mut W, value: i8) -> io::Result<()> fn write_i8<W: ?Sized>(&mut self, writer: &mut W, value: i8) -> io::Result<()>
where where
W: io::Write, W: io::Write,
@ -1643,6 +1648,19 @@ pub trait Formatter {
/// Writes an integer value like `-123` to the specified writer. /// Writes an integer value like `-123` to the specified writer.
#[inline] #[inline]
#[cfg(not(feature = "std"))]
fn write_i8<W: ?Sized>(&mut self, writer: &mut W, value: i8) -> io::Result<()>
where
W: io::Write,
{
let mut buffer = itoa::Buffer::new();
let s = buffer.format(value);
writer.write_all(s.as_bytes())
}
/// Writes an integer value like `-123` to the specified writer.
#[inline]
#[cfg(feature = "std")]
fn write_i16<W: ?Sized>(&mut self, writer: &mut W, value: i16) -> io::Result<()> fn write_i16<W: ?Sized>(&mut self, writer: &mut W, value: i16) -> io::Result<()>
where where
W: io::Write, W: io::Write,
@ -1652,6 +1670,19 @@ pub trait Formatter {
/// Writes an integer value like `-123` to the specified writer. /// Writes an integer value like `-123` to the specified writer.
#[inline] #[inline]
#[cfg(not(feature = "std"))]
fn write_i16<W: ?Sized>(&mut self, writer: &mut W, value: i16) -> io::Result<()>
where
W: io::Write,
{
let mut buffer = itoa::Buffer::new();
let s = buffer.format(value);
writer.write_all(s.as_bytes())
}
/// Writes an integer value like `-123` to the specified writer.
#[inline]
#[cfg(feature = "std")]
fn write_i32<W: ?Sized>(&mut self, writer: &mut W, value: i32) -> io::Result<()> fn write_i32<W: ?Sized>(&mut self, writer: &mut W, value: i32) -> io::Result<()>
where where
W: io::Write, W: io::Write,
@ -1661,6 +1692,19 @@ pub trait Formatter {
/// Writes an integer value like `-123` to the specified writer. /// Writes an integer value like `-123` to the specified writer.
#[inline] #[inline]
#[cfg(not(feature = "std"))]
fn write_i32<W: ?Sized>(&mut self, writer: &mut W, value: i32) -> io::Result<()>
where
W: io::Write,
{
let mut buffer = itoa::Buffer::new();
let s = buffer.format(value);
writer.write_all(s.as_bytes())
}
/// Writes an integer value like `-123` to the specified writer.
#[inline]
#[cfg(feature = "std")]
fn write_i64<W: ?Sized>(&mut self, writer: &mut W, value: i64) -> io::Result<()> fn write_i64<W: ?Sized>(&mut self, writer: &mut W, value: i64) -> io::Result<()>
where where
W: io::Write, W: io::Write,
@ -1668,8 +1712,21 @@ pub trait Formatter {
itoa::write(writer, value).map(drop) itoa::write(writer, value).map(drop)
} }
/// Writes an integer value like `-123` to the specified writer.
#[inline]
#[cfg(not(feature = "std"))]
fn write_i64<W: ?Sized>(&mut self, writer: &mut W, value: i64) -> io::Result<()>
where
W: io::Write,
{
let mut buffer = itoa::Buffer::new();
let s = buffer.format(value);
writer.write_all(s.as_bytes())
}
/// Writes an integer value like `123` to the specified writer. /// Writes an integer value like `123` to the specified writer.
#[inline] #[inline]
#[cfg(feature = "std")]
fn write_u8<W: ?Sized>(&mut self, writer: &mut W, value: u8) -> io::Result<()> fn write_u8<W: ?Sized>(&mut self, writer: &mut W, value: u8) -> io::Result<()>
where where
W: io::Write, W: io::Write,
@ -1679,6 +1736,19 @@ pub trait Formatter {
/// Writes an integer value like `123` to the specified writer. /// Writes an integer value like `123` to the specified writer.
#[inline] #[inline]
#[cfg(not(feature = "std"))]
fn write_u8<W: ?Sized>(&mut self, writer: &mut W, value: u8) -> io::Result<()>
where
W: io::Write,
{
let mut buffer = itoa::Buffer::new();
let s = buffer.format(value);
writer.write_all(s.as_bytes())
}
/// Writes an integer value like `123` to the specified writer.
#[inline]
#[cfg(feature = "std")]
fn write_u16<W: ?Sized>(&mut self, writer: &mut W, value: u16) -> io::Result<()> fn write_u16<W: ?Sized>(&mut self, writer: &mut W, value: u16) -> io::Result<()>
where where
W: io::Write, W: io::Write,
@ -1688,6 +1758,19 @@ pub trait Formatter {
/// Writes an integer value like `123` to the specified writer. /// Writes an integer value like `123` to the specified writer.
#[inline] #[inline]
#[cfg(not(feature = "std"))]
fn write_u16<W: ?Sized>(&mut self, writer: &mut W, value: u16) -> io::Result<()>
where
W: io::Write,
{
let mut buffer = itoa::Buffer::new();
let s = buffer.format(value);
writer.write_all(s.as_bytes())
}
/// Writes an integer value like `123` to the specified writer.
#[inline]
#[cfg(feature = "std")]
fn write_u32<W: ?Sized>(&mut self, writer: &mut W, value: u32) -> io::Result<()> fn write_u32<W: ?Sized>(&mut self, writer: &mut W, value: u32) -> io::Result<()>
where where
W: io::Write, W: io::Write,
@ -1697,6 +1780,19 @@ pub trait Formatter {
/// Writes an integer value like `123` to the specified writer. /// Writes an integer value like `123` to the specified writer.
#[inline] #[inline]
#[cfg(not(feature = "std"))]
fn write_u32<W: ?Sized>(&mut self, writer: &mut W, value: u32) -> io::Result<()>
where
W: io::Write,
{
let mut buffer = itoa::Buffer::new();
let s = buffer.format(value);
writer.write_all(s.as_bytes())
}
/// Writes an integer value like `123` to the specified writer.
#[inline]
#[cfg(feature = "std")]
fn write_u64<W: ?Sized>(&mut self, writer: &mut W, value: u64) -> io::Result<()> fn write_u64<W: ?Sized>(&mut self, writer: &mut W, value: u64) -> io::Result<()>
where where
W: io::Write, W: io::Write,
@ -1704,6 +1800,18 @@ pub trait Formatter {
itoa::write(writer, value).map(drop) itoa::write(writer, value).map(drop)
} }
/// Writes an integer value like `123` to the specified writer.
#[inline]
#[cfg(not(feature = "std"))]
fn write_u64<W: ?Sized>(&mut self, writer: &mut W, value: u64) -> io::Result<()>
where
W: io::Write,
{
let mut buffer = itoa::Buffer::new();
let s = buffer.format(value);
writer.write_all(s.as_bytes())
}
/// Writes a floating point value like `-31.26e+12` to the specified writer. /// Writes a floating point value like `-31.26e+12` to the specified writer.
#[inline] #[inline]
fn write_f32<W: ?Sized>(&mut self, writer: &mut W, value: f32) -> io::Result<()> fn write_f32<W: ?Sized>(&mut self, writer: &mut W, value: f32) -> io::Result<()>

View File

@ -1,8 +1,18 @@
#[cfg(feature = "std")]
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt; #[cfg(feature = "alloc")]
use std::slice; use alloc::borrow::{Cow, ToOwned};
use std::str; use core::fmt;
use core::slice;
use core::str;
#[cfg(feature = "std")]
use std::vec; use std::vec;
#[cfg(feature = "alloc")]
use alloc::vec;
#[cfg(feature = "alloc")]
use alloc::string::String;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use serde; use serde;
use serde::de::{ use serde::de::{

View File

@ -1,4 +1,11 @@
#[cfg(feature = "std")]
use std::borrow::Cow; use std::borrow::Cow;
#[cfg(feature = "alloc")]
use alloc::borrow::Cow;
#[cfg(feature = "alloc")]
use alloc::string::{String, ToString};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use super::Value; use super::Value;
use map::Map; use map::Map;
@ -182,7 +189,7 @@ impl<'a, T: Clone + Into<Value>> From<&'a [T]> for Value {
} }
} }
impl<T: Into<Value>> ::std::iter::FromIterator<T> for Value { impl<T: Into<Value>> ::core::iter::FromIterator<T> for Value {
/// Convert an iteratable type to a `Value` /// Convert an iteratable type to a `Value`
/// ///
/// # Examples /// # Examples

View File

@ -1,5 +1,9 @@
use std::fmt; use core::fmt;
use std::ops; use core::ops;
#[cfg(feature = "alloc")]
use alloc::string::String;
#[cfg(feature = "alloc")]
use alloc::borrow::ToOwned;
use super::Value; use super::Value;
use map::Map; use map::Map;
@ -132,6 +136,9 @@ where
// Prevent users from implementing the Index trait. // Prevent users from implementing the Index trait.
mod private { mod private {
#[cfg(feature = "alloc")]
use alloc::string::String;
pub trait Sealed {} pub trait Sealed {}
impl Sealed for usize {} impl Sealed for usize {}
impl Sealed for str {} impl Sealed for str {}

View File

@ -90,10 +90,14 @@
//! [from_slice]: https://docs.serde.rs/serde_json/de/fn.from_slice.html //! [from_slice]: https://docs.serde.rs/serde_json/de/fn.from_slice.html
//! [from_reader]: https://docs.serde.rs/serde_json/de/fn.from_reader.html //! [from_reader]: https://docs.serde.rs/serde_json/de/fn.from_reader.html
use std::fmt::{self, Debug}; use core::fmt::{self, Debug};
use std::io; use io;
use std::mem; use core::mem;
use std::str; use core::str;
#[cfg(feature = "alloc")]
use alloc::string::String;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::ser::Serialize; use serde::ser::Serialize;
@ -194,11 +198,16 @@ struct WriterFormatter<'a, 'b: 'a> {
impl<'a, 'b> io::Write for WriterFormatter<'a, 'b> { impl<'a, 'b> io::Write for WriterFormatter<'a, 'b> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
#[cfg(feature = "std")]
fn io_error<E>(_: E) -> io::Error { fn io_error<E>(_: E) -> io::Error {
// Error value does not matter because fmt::Display impl below just // Error value does not matter because fmt::Display impl below just
// maps it to fmt::Error // maps it to fmt::Error
io::Error::new(io::ErrorKind::Other, "fmt error") io::Error::new(io::ErrorKind::Other, "fmt error")
} }
#[cfg(not(feature = "std"))]
fn io_error<E>(_: E) -> &'static str {
"fmt error"
}
let s = try!(str::from_utf8(buf).map_err(io_error)); let s = try!(str::from_utf8(buf).map_err(io_error));
try!(self.inner.write_str(s).map_err(io_error)); try!(self.inner.write_str(s).map_err(io_error));
Ok(buf.len()) Ok(buf.len())

View File

@ -1,4 +1,6 @@
use super::Value; use super::Value;
#[cfg(feature = "alloc")]
use alloc::string::String;
fn eq_i64(value: &Value, other: i64) -> bool { fn eq_i64(value: &Value, other: i64) -> bool {
value.as_i64().map_or(false, |i| i == other) value.as_i64().map_or(false, |i| i == other)

View File

@ -6,6 +6,13 @@ use map::Map;
use number::Number; use number::Number;
use value::{to_value, Value}; use value::{to_value, Value};
#[cfg(feature = "alloc")]
use alloc::string::{String, ToString};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[cfg(feature = "alloc")]
use alloc::borrow::ToOwned;
impl Serialize for Value { impl Serialize for Value {
#[inline] #[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>