diff --git a/Cargo.toml b/Cargo.toml index f177ed4..7fb4487 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,8 +24,13 @@ derive_arbitrary = { version = "1.0.0", path = "./derive", optional = true } [dev-dependencies] [features] +# Provide support for std types by default. +default = ["std"] # Turn this feature on to enable support for `#[derive(Arbitrary)]`. derive = ["derive_arbitrary"] +# Whether or not to require the standard library. Turning off this feature +# makes Arbitrary work with no_std crates. +std = [] [[example]] name = "derive_enum" diff --git a/src/error.rs b/src/error.rs index f590c12..863632e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,7 @@ -use std::{error, fmt}; +#[cfg(feature = "std")] +use std::error; + +use core::fmt; /// An enumeration of buffer creation errors #[derive(Debug, Clone, Copy)] @@ -32,9 +35,10 @@ impl fmt::Display for Error { } } +#[cfg(feature = "std")] impl error::Error for Error {} /// A `Result` with the error type fixed as `arbitrary::Error`. /// /// Either an `Ok(T)` or `Err(arbitrary::Error)`. -pub type Result = std::result::Result; +pub type Result = core::result::Result; diff --git a/src/lib.rs b/src/lib.rs index 48898a8..ce58410 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,7 @@ //! [`Arbitrary`](./trait.Arbitrary.html) trait's documentation for details on //! automatically deriving, implementing, and/or using the trait. +#![cfg_attr(not(feature = "std"), no_std)] #![deny(bad_style)] #![deny(missing_docs)] #![deny(future_incompatible)] @@ -40,12 +41,25 @@ use core::mem; use core::ops::{Range, RangeBounds, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive}; use core::str; use core::time::Duration; + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + +#[cfg(feature = "std")] use std::borrow::{Cow, ToOwned}; +#[cfg(feature = "std")] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; +#[cfg(feature = "std")] use std::ffi::{CString, OsString}; +#[cfg(feature = "std")] use std::path::PathBuf; +#[cfg(feature = "std")] use std::rc::Rc; +#[cfg(feature = "std")] use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize}; +#[cfg(feature = "std")] use std::sync::{Arc, Mutex}; /// Generate arbitrary structured values from raw, unstructured data. @@ -75,11 +89,13 @@ use std::sync::{Arc, Mutex}; /// use arbitrary::Arbitrary; /// use std::collections::HashSet; /// +/// # #[cfg(feature = "std")] /// #[derive(Arbitrary)] /// pub struct AddressBook { /// friends: HashSet, /// } /// +/// # #[cfg(feature = "std")] /// #[derive(Arbitrary, Hash, Eq, PartialEq)] /// pub enum Friend { /// Buddy { name: String }, @@ -344,7 +360,7 @@ impl_arbitrary_for_floats! { impl<'a> Arbitrary<'a> for char { fn arbitrary(u: &mut Unstructured<'a>) -> Result { - use std::char; + use core::char; const CHAR_END: u32 = 0x0011_000; // The size of the surrogate blocks const SURROGATES_START: u32 = 0xD800; @@ -365,6 +381,7 @@ impl<'a> Arbitrary<'a> for char { } } +#[cfg(feature = "std")] impl<'a> Arbitrary<'a> for AtomicBool { fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) @@ -376,6 +393,7 @@ impl<'a> Arbitrary<'a> for AtomicBool { } } +#[cfg(feature = "std")] impl<'a> Arbitrary<'a> for AtomicIsize { fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) @@ -387,6 +405,7 @@ impl<'a> Arbitrary<'a> for AtomicIsize { } } +#[cfg(feature = "std")] impl<'a> Arbitrary<'a> for AtomicUsize { fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) @@ -521,7 +540,7 @@ impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Option { } } -impl<'a, A: Arbitrary<'a>, B: Arbitrary<'a>> Arbitrary<'a> for std::result::Result { +impl<'a, A: Arbitrary<'a>, B: Arbitrary<'a>> Arbitrary<'a> for core::result::Result { fn arbitrary(u: &mut Unstructured<'a>) -> Result { Ok(if >::arbitrary(u)? { Ok(::arbitrary(u)?) @@ -657,6 +676,7 @@ impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Vec { } } +#[cfg(feature = "std")] impl<'a, K: Arbitrary<'a> + Ord, V: Arbitrary<'a>> Arbitrary<'a> for BTreeMap { fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() @@ -672,6 +692,7 @@ impl<'a, K: Arbitrary<'a> + Ord, V: Arbitrary<'a>> Arbitrary<'a> for BTreeMap + Ord> Arbitrary<'a> for BTreeSet { fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() @@ -687,6 +708,7 @@ impl<'a, A: Arbitrary<'a> + Ord> Arbitrary<'a> for BTreeSet { } } +#[cfg(feature = "std")] impl<'a, A: Arbitrary<'a> + Ord> Arbitrary<'a> for BinaryHeap { fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() @@ -702,6 +724,7 @@ impl<'a, A: Arbitrary<'a> + Ord> Arbitrary<'a> for BinaryHeap { } } +#[cfg(feature = "std")] impl<'a, K: Arbitrary<'a> + Eq + ::std::hash::Hash, V: Arbitrary<'a>> Arbitrary<'a> for HashMap { @@ -719,6 +742,7 @@ impl<'a, K: Arbitrary<'a> + Eq + ::std::hash::Hash, V: Arbitrary<'a>> Arbitrary< } } +#[cfg(feature = "std")] impl<'a, A: Arbitrary<'a> + Eq + ::std::hash::Hash> Arbitrary<'a> for HashSet { fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() @@ -734,6 +758,7 @@ impl<'a, A: Arbitrary<'a> + Eq + ::std::hash::Hash> Arbitrary<'a> for HashSet } } +#[cfg(feature = "std")] impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for LinkedList { fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() @@ -749,6 +774,7 @@ impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for LinkedList { } } +#[cfg(feature = "std")] impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for VecDeque { fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() @@ -764,6 +790,7 @@ impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for VecDeque { } } +#[cfg(feature = "std")] impl<'a, A> Arbitrary<'a> for Cow<'a, A> where A: ToOwned + ?Sized, @@ -814,6 +841,7 @@ impl<'a> Arbitrary<'a> for &'a str { } } +#[cfg(feature = "std")] impl<'a> Arbitrary<'a> for String { fn arbitrary(u: &mut Unstructured<'a>) -> Result { <&str as Arbitrary>::arbitrary(u).map(Into::into) @@ -829,6 +857,7 @@ impl<'a> Arbitrary<'a> for String { } } +#[cfg(feature = "std")] impl<'a> Arbitrary<'a> for CString { fn arbitrary(u: &mut Unstructured<'a>) -> Result { as Arbitrary>::arbitrary(u).map(|mut x| { @@ -843,6 +872,7 @@ impl<'a> Arbitrary<'a> for CString { } } +#[cfg(feature = "std")] impl<'a> Arbitrary<'a> for OsString { fn arbitrary(u: &mut Unstructured<'a>) -> Result { ::arbitrary(u).map(From::from) @@ -854,6 +884,7 @@ impl<'a> Arbitrary<'a> for OsString { } } +#[cfg(feature = "std")] impl<'a> Arbitrary<'a> for PathBuf { fn arbitrary(u: &mut Unstructured<'a>) -> Result { ::arbitrary(u).map(From::from) @@ -865,6 +896,7 @@ impl<'a> Arbitrary<'a> for PathBuf { } } +#[cfg(feature = "std")] impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Box { fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) @@ -876,6 +908,7 @@ impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Box { } } +#[cfg(feature = "std")] impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Box<[A]> { fn arbitrary(u: &mut Unstructured<'a>) -> Result { as Arbitrary>::arbitrary(u).map(|x| x.into_boxed_slice()) @@ -887,6 +920,7 @@ impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Box<[A]> { } } +#[cfg(feature = "std")] impl<'a> Arbitrary<'a> for Box { fn arbitrary(u: &mut Unstructured<'a>) -> Result { ::arbitrary(u).map(|x| x.into_boxed_str()) @@ -911,6 +945,7 @@ impl<'a> Arbitrary<'a> for Box { // } // } +#[cfg(feature = "std")] impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Arc { fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) @@ -922,6 +957,7 @@ impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Arc { } } +#[cfg(feature = "std")] impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Rc { fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) @@ -966,6 +1002,7 @@ impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for UnsafeCell { } } +#[cfg(feature = "std")] impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Mutex { fn arbitrary(u: &mut Unstructured<'a>) -> Result { Arbitrary::arbitrary(u).map(Self::new) @@ -988,9 +1025,9 @@ impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for iter::Empty { } } -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for ::std::marker::PhantomData { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for core::marker::PhantomData { fn arbitrary(_: &mut Unstructured<'a>) -> Result { - Ok(::std::marker::PhantomData) + Ok(core::marker::PhantomData) } #[inline] @@ -999,9 +1036,9 @@ impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for ::std::marker::PhantomData { } } -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for ::std::num::Wrapping { +impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for core::num::Wrapping { fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Arbitrary::arbitrary(u).map(::std::num::Wrapping) + Arbitrary::arbitrary(u).map(core::num::Wrapping) } #[inline] @@ -1067,6 +1104,7 @@ mod test { Vec::::arbitrary(&mut Unstructured::new(&x)).unwrap(), &[84148994] ); + #[cfg(feature = "std")] assert_eq!( String::arbitrary(&mut Unstructured::new(&x)).unwrap(), "\x01\x02\x03\x04\x05\x06\x07\x08" @@ -1084,6 +1122,7 @@ mod test { Vec::::arbitrary_take_rest(Unstructured::new(&x)).unwrap(), &[0x4030201] ); + #[cfg(feature = "std")] assert_eq!( String::arbitrary_take_rest(Unstructured::new(&x)).unwrap(), "\x01\x02\x03\x04" diff --git a/src/size_hint.rs b/src/size_hint.rs index 045c148..2d32a5e 100644 --- a/src/size_hint.rs +++ b/src/size_hint.rs @@ -42,10 +42,10 @@ pub fn and_all(hints: &[(usize, Option)]) -> (usize, Option) { /// `lhs` and `rhs` size hints. #[inline] pub fn or(lhs: (usize, Option), rhs: (usize, Option)) -> (usize, Option) { - let lower = std::cmp::min(lhs.0, rhs.0); + let lower = core::cmp::min(lhs.0, rhs.0); let upper = lhs .1 - .and_then(|lhs| rhs.1.map(|rhs| std::cmp::max(lhs, rhs))); + .and_then(|lhs| rhs.1.map(|rhs| core::cmp::max(lhs, rhs))); (lower, upper) } diff --git a/src/unstructured.rs b/src/unstructured.rs index 9e2f497..16c2d3f 100644 --- a/src/unstructured.rs +++ b/src/unstructured.rs @@ -9,8 +9,8 @@ //! Wrappers around raw, unstructured bytes. use crate::{Arbitrary, Error, Result}; -use std::marker::PhantomData; -use std::{mem, ops}; +use core::marker::PhantomData; +use core::{mem, ops}; /// A source of unstructured data. /// @@ -184,9 +184,9 @@ impl<'a> Unstructured<'a> { /// /// ``` /// use arbitrary::{Arbitrary, Result, Unstructured}; - /// # pub struct MyCollection { _t: std::marker::PhantomData } + /// # pub struct MyCollection { _t: core::marker::PhantomData } /// # impl MyCollection { - /// # pub fn with_capacity(capacity: usize) -> Self { MyCollection { _t: std::marker::PhantomData } } + /// # pub fn with_capacity(capacity: usize) -> Self { MyCollection { _t: core::marker::PhantomData } } /// # pub fn insert(&mut self, element: T) {} /// # } /// @@ -216,7 +216,7 @@ impl<'a> Unstructured<'a> { let byte_size = self.arbitrary_byte_size()?; let (lower, upper) = ::size_hint(0); let elem_size = upper.unwrap_or_else(|| lower * 2); - let elem_size = std::cmp::max(1, elem_size); + let elem_size = core::cmp::max(1, elem_size); Ok(byte_size / elem_size) } @@ -235,19 +235,19 @@ impl<'a> Unstructured<'a> { // We only consume as many bytes as necessary to cover the entire // range of the byte string. - let len = if self.data.len() <= std::u8::MAX as usize + 1 { + let len = if self.data.len() <= core::u8::MAX as usize + 1 { let bytes = 1; let max_size = self.data.len() - bytes; let (rest, for_size) = self.data.split_at(max_size); self.data = rest; Self::int_in_range_impl(0..=max_size as u8, for_size.iter().copied())?.0 as usize - } else if self.data.len() <= std::u16::MAX as usize + 1 { + } else if self.data.len() <= core::u16::MAX as usize + 1 { let bytes = 2; let max_size = self.data.len() - bytes; let (rest, for_size) = self.data.split_at(max_size); self.data = rest; Self::int_in_range_impl(0..=max_size as u16, for_size.iter().copied())?.0 as usize - } else if self.data.len() <= std::u32::MAX as usize + 1 { + } else if self.data.len() <= core::u32::MAX as usize + 1 { let bytes = 4; let max_size = self.data.len() - bytes; let (rest, for_size) = self.data.split_at(max_size); @@ -404,7 +404,7 @@ impl<'a> Unstructured<'a> { /// assert!(u.fill_buffer(&mut buf).is_ok()); /// ``` pub fn fill_buffer(&mut self, buffer: &mut [u8]) -> Result<()> { - let n = std::cmp::min(buffer.len(), self.data.len()); + let n = core::cmp::min(buffer.len(), self.data.len()); for i in 0..n { buffer[i] = self.data[i]; } @@ -510,7 +510,7 @@ impl<'a> Unstructured<'a> { let (lower, upper) = ElementType::size_hint(0); let elem_size = upper.unwrap_or(lower * 2); - let elem_size = std::cmp::max(1, elem_size); + let elem_size = core::cmp::max(1, elem_size); let size = self.len() / elem_size; Ok(ArbitraryTakeRestIter { size, @@ -678,6 +678,7 @@ mod tests { use super::*; #[test] + #[cfg(feature = "std")] fn test_byte_size() { let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 6]); // Should take one byte off the end diff --git a/tests/derive.rs b/tests/derive.rs index 9dfbbd5..a4f46f6 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -40,12 +40,15 @@ fn tuple_struct() { assert_eq!((2, Some(2)), ::size_hint(0)); } +#[cfg(feature = "std")] #[derive(Clone, Debug, Arbitrary)] struct EndingInVec(u8, bool, u32, Vec); +#[cfg(feature = "std")] #[derive(Clone, Debug, Arbitrary)] struct EndingInString(u8, bool, u32, String); #[test] +#[cfg(feature = "std")] fn test_take_rest() { let bytes = [1, 1, 1, 2, 3, 4, 5, 6, 7, 8]; let s1 = EndingInVec::arbitrary_take_rest(Unstructured::new(&bytes)).unwrap(); @@ -113,6 +116,7 @@ fn derive_enum() { assert_eq!((4, Some(17)), ::size_hint(0)); } +#[cfg(feature = "std")] #[derive(Arbitrary, Debug)] enum RecursiveTree { Leaf, @@ -122,6 +126,7 @@ enum RecursiveTree { }, } +#[cfg(feature = "std")] #[test] fn recursive() { let raw = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; diff --git a/tests/path.rs b/tests/path.rs index 15dbbe3..13dbcdc 100644 --- a/tests/path.rs +++ b/tests/path.rs @@ -20,6 +20,7 @@ pub enum Enum { Y(u8), } +#[cfg(feature = "std")] #[derive(arbitrary::Arbitrary, Clone, Debug)] struct EndingInVec(u8, bool, u32, Vec);