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" }
[dependencies]
serde = "1.0.60"
serde = { version = "1.0.60", default-features = false }
indexmap = { version = "1.2", optional = true }
itoa = "0.4.3"
ryu = "1.0"
@ -42,7 +42,11 @@ features = ["raw_value"]
### FEATURES #################################################################
[features]
default = []
default = ["std"]
std = ["serde/std"]
alloc = ["serde/alloc"]
# 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

View File

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

View File

@ -1,10 +1,15 @@
//! When serializing or deserializing JSON goes wrong.
#[cfg(feature = "std")]
use std::error;
use std::fmt::{self, Debug, Display};
use std::io;
use std::result;
use std::str::FromStr;
use core::fmt::{self, Debug, Display};
use io;
use core::result;
use core::str::FromStr;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[cfg(feature = "alloc")]
use alloc::string::{String, ToString};
use serde::de;
use serde::ser;
@ -131,6 +136,7 @@ pub enum Category {
}
#[cfg_attr(feature = "cargo-clippy", allow(fallible_impl_from))]
#[cfg(feature = "std")]
impl From<Error> for 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 {
fn source(&self) -> Option<&(error::Error + 'static)> {
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 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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> {
iter: I,

View File

@ -331,6 +331,7 @@
must_use_candidate,
))]
#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
#[macro_use]
extern crate serde;
@ -338,6 +339,10 @@ extern crate serde;
extern crate indexmap;
extern crate itoa;
extern crate ryu;
#[cfg(feature = "std")]
extern crate core;
#[cfg(feature = "alloc")]
extern crate alloc;
#[doc(inline)]
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 {
($e:expr) => {
match $e {
::std::result::Result::Ok(val) => val,
::std::result::Result::Err(err) => return ::std::result::Result::Err(err),
::core::result::Result::Ok(val) => val,
::core::result::Result::Err(err) => return ::core::result::Result::Err(err),
}
};
}
@ -370,6 +375,7 @@ pub mod map;
pub mod ser;
pub mod value;
mod io;
mod iter;
mod number;
mod read;

View File

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

View File

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

View File

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

View File

@ -1,9 +1,13 @@
//! Serialize a Rust data structure into JSON data.
use std::fmt;
use std::io;
use std::num::FpCategory;
use std::str;
use core::fmt;
use io;
use core::num::FpCategory;
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 serde::ser::{self, Impossible, Serialize};
@ -460,7 +464,7 @@ where
where
T: fmt::Display,
{
use std::fmt::Write;
use core::fmt::Write;
struct Adapter<'ser, W: 'ser, F: 'ser> {
writer: &'ser mut W,
@ -1634,6 +1638,7 @@ pub trait Formatter {
/// Writes an integer value like `-123` to the specified writer.
#[inline]
#[cfg(feature = "std")]
fn write_i8<W: ?Sized>(&mut self, writer: &mut W, value: i8) -> io::Result<()>
where
W: io::Write,
@ -1643,6 +1648,19 @@ pub trait Formatter {
/// Writes an integer value like `-123` to the specified writer.
#[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<()>
where
W: io::Write,
@ -1652,6 +1670,19 @@ pub trait Formatter {
/// Writes an integer value like `-123` to the specified writer.
#[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<()>
where
W: io::Write,
@ -1661,6 +1692,19 @@ pub trait Formatter {
/// Writes an integer value like `-123` to the specified writer.
#[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<()>
where
W: io::Write,
@ -1668,8 +1712,21 @@ pub trait Formatter {
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.
#[inline]
#[cfg(feature = "std")]
fn write_u8<W: ?Sized>(&mut self, writer: &mut W, value: u8) -> io::Result<()>
where
W: io::Write,
@ -1679,6 +1736,19 @@ pub trait Formatter {
/// Writes an integer value like `123` to the specified writer.
#[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<()>
where
W: io::Write,
@ -1688,6 +1758,19 @@ pub trait Formatter {
/// Writes an integer value like `123` to the specified writer.
#[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<()>
where
W: io::Write,
@ -1697,6 +1780,19 @@ pub trait Formatter {
/// Writes an integer value like `123` to the specified writer.
#[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<()>
where
W: io::Write,
@ -1704,6 +1800,18 @@ pub trait Formatter {
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.
#[inline]
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::fmt;
use std::slice;
use std::str;
#[cfg(feature = "alloc")]
use alloc::borrow::{Cow, ToOwned};
use core::fmt;
use core::slice;
use core::str;
#[cfg(feature = "std")]
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::de::{

View File

@ -1,4 +1,11 @@
#[cfg(feature = "std")]
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 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`
///
/// # Examples

View File

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

View File

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

View File

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

View File

@ -6,6 +6,13 @@ use map::Map;
use number::Number;
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 {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>