diff --git a/Cargo.toml b/Cargo.toml index f875802..5fb1847 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,15 +20,17 @@ edition = "2018" members = ['test-suite'] [dependencies] -serde = "1.0.97" +serde = { version = "1.0.97", default-features = false, features = ["alloc"] } indexmap = { version = "1.0", optional = true } +hashbrown = { version = "0.7.2" } [dev-dependencies] serde_derive = "1.0" -serde_json = "1.0" +serde_json = { version = "1.0", default-features = false, features = ["alloc"] } [features] -default = [] +default = ["std"] +std = ["serde/std"] # Use indexmap rather than BTreeMap as the map type of toml::Value. # This allows data to be read into a Value and written back to a TOML string diff --git a/src/datetime.rs b/src/datetime.rs index a68b075..e7f9bc3 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -1,6 +1,13 @@ +#[cfg(feature = "std")] use std::error; -use std::fmt; -use std::str::{self, FromStr}; + +use core::fmt; +use core::str::{self, FromStr}; + +#[cfg(not(feature = "std"))] +use alloc::format; +#[cfg(not(feature = "std"))] +use alloc::string::ToString; use serde::{de, ser}; @@ -541,4 +548,5 @@ impl fmt::Display for DatetimeParseError { } } +#[cfg(feature = "std")] impl error::Error for DatetimeParseError {} diff --git a/src/de.rs b/src/de.rs index fbc6009..5155445 100644 --- a/src/de.rs +++ b/src/de.rs @@ -4,15 +4,26 @@ //! into Rust structures. Note that some top-level functions here are also //! provided at the top of the crate. -use std::borrow::Cow; -use std::collections::HashMap; +use alloc::borrow::Cow; +#[cfg(not(feature = "std"))] +use alloc::borrow::ToOwned; +#[cfg(not(feature = "std"))] +use alloc::boxed::Box; +#[cfg(not(feature = "std"))] +use alloc::string::String; +#[cfg(not(feature = "std"))] +use alloc::string::ToString; +use alloc::vec; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; +use core::f64; +use core::fmt; +use core::iter; +use core::marker::PhantomData; +use core::str; +use hashbrown::HashMap; +#[cfg(feature = "std")] use std::error; -use std::f64; -use std::fmt; -use std::iter; -use std::marker::PhantomData; -use std::str; -use std::vec; use serde::de; use serde::de::value::BorrowedStrDeserializer; @@ -2082,6 +2093,7 @@ impl Error { } } +#[cfg(feature = "std")] impl std::convert::From for std::io::Error { fn from(e: Error) -> Self { std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()) @@ -2171,6 +2183,7 @@ impl fmt::Display for Error { } } +#[cfg(feature = "std")] impl error::Error for Error {} impl de::Error for Error { diff --git a/src/lib.rs b/src/lib.rs index 00421b1..97f629a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -152,6 +152,10 @@ // and lets them ensure that there is indeed no unsafe code as opposed to // something they couldn't detect (e.g. unsafe added via macro expansion, etc). #![forbid(unsafe_code)] +// When not testing and when the 'std' feature is not enabled, use no_std. +#![cfg_attr(all(not(test), not(feature = "std")), no_std)] + +extern crate alloc; pub mod map; pub mod value; diff --git a/src/macros.rs b/src/macros.rs index 0731afe..bb65a13 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -428,6 +428,9 @@ pub fn push_toml(root: &mut Value, path: &[&str]) { } fn traverse<'a>(root: &'a mut Value, path: &[&str]) -> &'a mut Value { + #[cfg(not(feature = "std"))] + use alloc::borrow::ToOwned; + let mut cur = root; for &key in path { // Lexical lifetimes :D diff --git a/src/map.rs b/src/map.rs index d130a1d..b6a3a02 100644 --- a/src/map.rs +++ b/src/map.rs @@ -15,15 +15,18 @@ //! [`LinkedHashMap`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html use crate::value::Value; +use core::borrow::Borrow; +use core::fmt::{self, Debug}; +use core::hash::Hash; +use core::iter::FromIterator; +use core::ops; use serde::{de, ser}; -use std::borrow::Borrow; -use std::fmt::{self, Debug}; -use std::hash::Hash; -use std::iter::FromIterator; -use std::ops; + +#[cfg(not(feature = "std"))] +use alloc::string::String; #[cfg(not(feature = "preserve_order"))] -use std::collections::{btree_map, BTreeMap}; +use alloc::collections::{btree_map, BTreeMap}; #[cfg(feature = "preserve_order")] use indexmap::{self, IndexMap}; @@ -144,10 +147,10 @@ impl Map { where S: Into, { + #[cfg(not(feature = "preserve_order"))] + use alloc::collections::btree_map::Entry as EntryImpl; #[cfg(feature = "preserve_order")] use indexmap::map::Entry as EntryImpl; - #[cfg(not(feature = "preserve_order"))] - use std::collections::btree_map::Entry as EntryImpl; match self.map.entry(key.into()) { EntryImpl::Vacant(vacant) => Entry::Vacant(VacantEntry { vacant }), diff --git a/src/ser.rs b/src/ser.rs index 2a13d4f..0e5bf10 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -25,11 +25,18 @@ //! # fn main() {} //! ``` -use std::cell::Cell; +use alloc::rc::Rc; +#[cfg(not(feature = "std"))] +use alloc::string::String; +#[cfg(not(feature = "std"))] +use alloc::string::ToString; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; +use core::cell::Cell; +use core::fmt::{self, Write}; +use core::marker; +#[cfg(feature = "std")] use std::error; -use std::fmt::{self, Write}; -use std::marker; -use std::rc::Rc; use crate::datetime; use serde::ser; @@ -1548,6 +1555,7 @@ impl fmt::Display for Error { } } +#[cfg(feature = "std")] impl error::Error for Error {} impl ser::Error for Error { diff --git a/src/spanned.rs b/src/spanned.rs index 9ee56ae..1e84ca9 100644 --- a/src/spanned.rs +++ b/src/spanned.rs @@ -1,8 +1,11 @@ +use core::borrow::Borrow; +use core::cmp::Ordering; +use core::fmt; +use core::hash::{Hash, Hasher}; use serde::{de, ser}; -use std::borrow::Borrow; -use std::cmp::Ordering; -use std::fmt; -use std::hash::{Hash, Hasher}; + +#[cfg(not(feature = "std"))] +use alloc::string::String; pub(crate) const NAME: &str = "$__toml_private_Spanned"; pub(crate) const START: &str = "$__toml_private_start"; @@ -113,7 +116,7 @@ where where D: de::Deserializer<'de>, { - struct SpannedVisitor(::std::marker::PhantomData); + struct SpannedVisitor(::core::marker::PhantomData); impl<'de, T> de::Visitor<'de> for SpannedVisitor where @@ -151,7 +154,7 @@ where } } - let visitor = SpannedVisitor(::std::marker::PhantomData); + let visitor = SpannedVisitor(::core::marker::PhantomData); static FIELDS: [&str; 3] = [START, END, VALUE]; deserializer.deserialize_struct(NAME, &FIELDS, visitor) diff --git a/src/tokens.rs b/src/tokens.rs index c242282..485783d 100644 --- a/src/tokens.rs +++ b/src/tokens.rs @@ -1,8 +1,8 @@ -use std::borrow::Cow; -use std::char; -use std::str; -use std::string; -use std::string::String as StdString; +use alloc::borrow::Cow; +use alloc::string; +use alloc::string::String as StdString; +use core::char; +use core::str; use self::Token::*; @@ -507,6 +507,9 @@ impl MaybeString { } fn to_owned(&mut self, input: &str) { + #[cfg(not(feature = "std"))] + use alloc::borrow::ToOwned; + match *self { MaybeString::NotEscaped(start) => { *self = MaybeString::Owned(input[start..].to_owned()); diff --git a/src/value.rs b/src/value.rs index 1a1756d..761a4ef 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,12 +1,24 @@ //! Definition of a TOML value -use std::collections::{BTreeMap, HashMap}; -use std::fmt; -use std::hash::Hash; -use std::mem::discriminant; -use std::ops; -use std::str::FromStr; -use std::vec; +use alloc::collections::BTreeMap; +use alloc::vec; +use core::fmt; +use core::hash::Hash; +use core::mem::discriminant; +use core::ops; +use core::str::FromStr; +use hashbrown::HashMap; + +#[cfg(not(feature = "std"))] +use alloc::borrow::ToOwned; +#[cfg(not(feature = "std"))] +use alloc::format; +#[cfg(not(feature = "std"))] +use alloc::string::String; +#[cfg(not(feature = "std"))] +use alloc::string::ToString; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; use serde::de; use serde::de::IntoDeserializer;