Skip to content

No_std support #516

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
21 changes: 13 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ travis-ci = { repository = "serde-rs/json" }
appveyor = { repository = "serde-rs/json" }

[dependencies]
serde = "1.0.60"
serde = { version = "1.0.85", default-features = false }
indexmap = { version = "1.0", optional = true }
itoa = "0.4.3"
itoa = { version = "0.4.3", optional = true, default-features = false }
ryu = "0.2"

[dev-dependencies]
automod = "0.1"
compiletest_rs = { version = "0.3", features = ["stable"] }
serde_bytes = "0.10"
serde_derive = "1.0"
serde_stacker = "0.1"
# automod = "0.1"
# compiletest_rs = { version = "0.3", features = ["stable"] }
# serde_bytes = "0.10"
# serde_derive = "1.0"
# serde_stacker = "0.1"

[package.metadata.docs.rs]
features = ["raw_value", "unbounded_depth"]
Expand All @@ -38,7 +38,7 @@ features = ["raw_value"]
### FEATURES #################################################################

[features]
default = []
default = ["std"]

# 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
Expand All @@ -62,3 +62,8 @@ raw_value = []
# overflow the stack after deserialization has completed, including, but not
# limited to, Display and Debug and Drop impls.
unbounded_depth = []

std = ["serde/default", "itoa/default", "indexmap"]

# No-Std feature
no_std = ["serde/alloc", "itoa"]
23 changes: 22 additions & 1 deletion src/de.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
//! Deserialize JSON data to a Rust data structure.

#[cfg(not(feature = "std"))]
use alloc::str::FromStr;
#[cfg(not(feature = "std"))]
use alloc::string::String;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[cfg(not(feature = "std"))]
use core::marker::PhantomData;
#[cfg(not(feature = "std"))]
use core::result;
#[cfg(not(feature = "std"))]
use core::{i32, u64};
#[cfg(feature = "std")]
use std::io;
#[cfg(feature = "std")]
use std::marker::PhantomData;
#[cfg(feature = "std")]
use std::result;
#[cfg(feature = "std")]
use std::str::FromStr;
#[cfg(feature = "std")]
use std::{i32, u64};

use serde::de::{self, Expected, Unexpected};
Expand All @@ -12,7 +29,9 @@ use super::error::{Error, ErrorCode, Result};

use read::{self, Reference};

pub use read::{IoRead, Read, SliceRead, StrRead};
#[cfg(feature = "std")]
pub use read::IoRead;
pub use read::{Read, SliceRead, StrRead};

use number::Number;
#[cfg(feature = "arbitrary_precision")]
Expand Down Expand Up @@ -63,6 +82,7 @@ where
}
}

#[cfg(feature = "std")]
impl<R> Deserializer<read::IoRead<R>>
where
R: io::Read,
Expand Down Expand Up @@ -2242,6 +2262,7 @@ where
/// is wrong with the data, for example required struct fields are missing from
/// the JSON map or some number is too big to fit in the expected primitive
/// type.
#[cfg(feature = "std")]
pub fn from_reader<R, T>(rdr: R) -> Result<T>
where
R: io::Read,
Expand Down
37 changes: 37 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
//! When serializing or deserializing JSON goes wrong.

#[cfg(not(feature = "std"))]
use alloc::str::FromStr;
#[cfg(not(feature = "std"))]
use core::fmt::{self, Debug, Display};
#[cfg(not(feature = "std"))]
use core::result;
#[cfg(feature = "std")]
use std::error;
#[cfg(feature = "std")]
use std::fmt::{self, Debug, Display};
#[cfg(feature = "std")]
use std::io;
#[cfg(feature = "std")]
use std::result;
#[cfg(feature = "std")]
use std::str::FromStr;

#[cfg(not(feature = "std"))]
use alloc::prelude::*;
#[cfg(not(feature = "std"))]
use alloc::string::String;

use serde::de;
use serde::ser;

Expand Down Expand Up @@ -130,6 +146,7 @@ pub enum Category {
Eof,
}

#[cfg(feature = "std")]
#[cfg_attr(feature = "cargo-clippy", allow(fallible_impl_from))]
impl From<Error> for io::Error {
/// Convert a `serde_json::Error` into an `io::Error`.
Expand Down Expand Up @@ -185,8 +202,13 @@ pub enum ErrorCode {
Message(Box<str>),

/// Some IO error occurred while serializing or deserializing.
#[cfg(feature = "std")]
Io(io::Error),

/// Some IO error occurred while serializing or deserializing.
#[cfg(not(feature = "std"))]
Io(fmt::Error),

/// EOF while parsing a list.
EofWhileParsingList,

Expand Down Expand Up @@ -271,6 +293,7 @@ impl Error {
// Not public API. Should be pub(crate).
//
// Update `eager_json` crate when this function changes.
#[cfg(feature = "std")]
#[doc(hidden)]
#[cold]
pub fn io(error: io::Error) -> Self {
Expand All @@ -283,6 +306,19 @@ impl Error {
}
}

#[cfg(not(feature = "std"))]
#[doc(hidden)]
#[cold]
pub fn io(error: fmt::Error) -> Self {
Error {
err: Box::new(ErrorImpl {
code: ErrorCode::Io(error),
line: 0,
column: 0,
}),
}
}

// Not public API. Should be pub(crate).
#[doc(hidden)]
#[cold]
Expand Down Expand Up @@ -333,6 +369,7 @@ impl Display for ErrorCode {
}
}

#[cfg(feature = "std")]
impl error::Error for Error {
fn description(&self) -> &str {
match self.err.code {
Expand Down
28 changes: 22 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,32 +317,46 @@
redundant_field_names,
))]
#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc))]

#[macro_use]
extern crate serde;
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(feature = "preserve_order")]
extern crate indexmap;
extern crate itoa;
extern crate ryu;

#[cfg(feature = "std")]
#[doc(inline)]
pub use self::de::{from_reader, from_slice, from_str, Deserializer, StreamDeserializer};
pub use self::de::from_reader;
#[doc(inline)]
pub use self::de::{from_slice, from_str, Deserializer, StreamDeserializer};
#[cfg(feature = "std")]
#[doc(inline)]
pub use self::error::{Error, Result};
#[doc(inline)]
pub use self::ser::{
to_string, to_string_pretty, to_vec, to_vec_pretty, to_writer, to_writer_pretty, Serializer,
};
pub use self::ser::{to_string, to_vec, to_writer, Serializer};
#[cfg(feature = "std")]
#[doc(inline)]
pub use self::ser::{to_string_pretty, to_vec_pretty, to_writer_pretty};
#[doc(inline)]
pub use self::value::{from_value, to_value, Map, Number, Value};

#[cfg(not(feature = "std"))]
use core::result;
#[cfg(feature = "std")]
use std::result;

// We only use our own error type; no need for From conversions provided by the
// standard library's try! macro. This reduces lines of LLVM IR by 4%.
macro_rules! try {
($e:expr) => {
match $e {
::std::result::Result::Ok(val) => val,
::std::result::Result::Err(err) => return ::std::result::Result::Err(err),
::result::Result::Ok(val) => val,
::result::Result::Err(err) => return ::result::Result::Err(err),
}
};
}
Expand All @@ -356,9 +370,11 @@ pub mod map;
pub mod ser;
pub mod value;

#[cfg(feature = "std")]
mod iter;
mod number;
mod read;

#[cfg(feature = "std")]
#[cfg(feature = "raw_value")]
mod raw;
26 changes: 26 additions & 0 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,36 @@
//! [`BTreeMap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html
//! [`IndexMap`]: https://docs.rs/indexmap/*/indexmap/map/struct.IndexMap.html

#[cfg(not(feature = "std"))]
use core::borrow::Borrow;
#[cfg(not(feature = "std"))]
use core::fmt::{self, Debug};
#[cfg(not(feature = "std"))]
use core::hash::Hash;
#[cfg(not(feature = "std"))]
use core::iter::FromIterator;
#[cfg(not(feature = "std"))]
use core::ops;
use serde::{de, ser};
#[cfg(feature = "std")]
use std::borrow::Borrow;
#[cfg(feature = "std")]
use std::fmt::{self, Debug};
#[cfg(feature = "std")]
use std::hash::Hash;
#[cfg(feature = "std")]
use std::iter::FromIterator;
#[cfg(feature = "std")]
use std::ops;
use value::Value;

#[cfg(not(feature = "std"))]
use alloc::string::String;

#[cfg(not(feature = "std"))]
#[cfg(not(feature = "preserve_order"))]
use alloc::collections::{btree_map, BTreeMap};
#[cfg(feature = "std")]
#[cfg(not(feature = "preserve_order"))]
use std::collections::{btree_map, BTreeMap};

Expand Down Expand Up @@ -135,8 +157,12 @@ impl Map<String, Value> {
where
S: Into<String>,
{
#[cfg(not(feature = "std"))]
#[cfg(not(feature = "preserve_order"))]
use alloc::collections::btree_map::Entry as EntryImpl;
#[cfg(feature = "preserve_order")]
use indexmap::map::Entry as EntryImpl;
#[cfg(feature = "std")]
#[cfg(not(feature = "preserve_order"))]
use std::collections::btree_map::Entry as EntryImpl;

Expand Down
3 changes: 3 additions & 0 deletions src/number.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#[cfg(not(feature = "std"))]
use core::fmt::{self, Debug, Display};
use error::Error;
use serde::de::{self, Unexpected, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "std")]
use std::fmt::{self, Debug, Display};

#[cfg(feature = "arbitrary_precision")]
Expand Down
15 changes: 15 additions & 0 deletions src/read.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
#[cfg(not(feature = "std"))]
use core::ops::Deref;
#[cfg(not(feature = "std"))]
use core::{char, cmp, str};
#[cfg(feature = "std")]
use std::ops::Deref;
#[cfg(feature = "std")]
use std::{char, cmp, io, str};

#[cfg(feature = "raw_value")]
use serde::de::Visitor;

#[cfg(feature = "std")]
use iter::LineColIterator;

use error::{Error, ErrorCode, Result};

#[cfg(feature = "raw_value")]
use raw::{BorrowedRawDeserializer, OwnedRawDeserializer};

#[cfg(not(feature = "std"))]
use alloc::vec::Vec;

/// Trait used by the deserializer for iterating over input. This is manually
/// "specialized" for iterating over &[u8]. Once feature(specialization) is
/// stable we can use actual specialization.
Expand Down Expand Up @@ -118,6 +128,7 @@ impl<'b, 'c, T: ?Sized + 'static> Deref for Reference<'b, 'c, T> {
}

/// JSON input source that reads from a std::io input stream.
#[cfg(feature = "std")]
pub struct IoRead<R>
where
R: io::Read,
Expand Down Expand Up @@ -157,6 +168,7 @@ mod private {

//////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "std")]
impl<R> IoRead<R>
where
R: io::Read,
Expand All @@ -181,8 +193,10 @@ where
}
}

#[cfg(feature = "std")]
impl<R> private::Sealed for IoRead<R> where R: io::Read {}

#[cfg(feature = "std")]
impl<R> IoRead<R>
where
R: io::Read,
Expand Down Expand Up @@ -221,6 +235,7 @@ where
}
}

#[cfg(feature = "std")]
impl<'de, R> Read<'de> for IoRead<R>
where
R: io::Read,
Expand Down
Loading