diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 1dbac58..fc4c3c6 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -61,3 +61,17 @@ jobs: run: cargo install cargo-fuzz - name: "Fuzz for 3 minutes" run: cargo fuzz run int_in_range -- -max_total_time=$((3 * 60)) + no_std_build: + name: no_std Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: rustup update + - name: "Build" + run: cargo build --verbose --no-default-features + - name: "Build" + run: cargo build --verbose --no-default-features --features=alloc + - name: "Run tests" + run: cargo test --verbose --no-default-features + - name: "Run tests as no_std with alloc" + run: cargo test --verbose --no-default-features --features=alloc diff --git a/Cargo.toml b/Cargo.toml index a060234..1795dca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,12 +2,12 @@ name = "arbitrary" version = "1.4.2" # Make sure this matches the derive crate version (not including the patch version) authors = [ - "The Rust-Fuzz Project Developers", - "Nick Fitzgerald ", - "Manish Goregaokar ", - "Simonas Kazlauskas ", - "Brian L. Troutwine ", - "Corey Farwell ", + "The Rust-Fuzz Project Developers", + "Nick Fitzgerald ", + "Manish Goregaokar ", + "Simonas Kazlauskas ", + "Brian L. Troutwine ", + "Corey Farwell ", ] categories = ["development-tools::testing"] edition = "2021" @@ -24,7 +24,10 @@ derive_arbitrary = { version = "~1.4.0", path = "./derive", optional = true } [features] # Turn this feature on to enable support for `#[derive(Arbitrary)]`. +default = ["std"] derive = ["derive_arbitrary"] +std = ["alloc"] +alloc = [] [[example]] name = "derive_enum" diff --git a/fuzz/fuzz_targets/int_in_range.rs b/fuzz/fuzz_targets/int_in_range.rs index 14c07f0..6bedddf 100755 --- a/fuzz/fuzz_targets/int_in_range.rs +++ b/fuzz/fuzz_targets/int_in_range.rs @@ -1,8 +1,8 @@ #![no_main] use arbitrary::{unstructured::Int, Arbitrary, Result, Unstructured}; +use core::{fmt::Display, ops::RangeInclusive}; use libfuzzer_sys::fuzz_target; -use std::{fmt::Display, ops::RangeInclusive}; fuzz_target!(|data: &[u8]| { fuzz(data).expect("`int_in_range` should never return an error"); diff --git a/src/error.rs b/src/error.rs index 8cdf39b..71698a5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,4 @@ -use std::{error, fmt}; +use core::{error, fmt}; /// An enumeration of buffer creation errors #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -41,14 +41,14 @@ 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; #[cfg(test)] mod tests { // Often people will import our custom `Result` type because 99.9% of // results in a file will be `arbitrary::Result` but then have that one last // 0.1% that want to have a custom error type. Don't make them prefix that - // 0.1% as `std::result::Result`; instead, let `arbitrary::Result` have an + // 0.1% as `core::result::Result`; instead, let `arbitrary::Result` have an // overridable error type. #[test] fn can_use_custom_error_types_with_result() -> super::Result<(), String> { diff --git a/src/foreign/alloc/borrow.rs b/src/foreign/alloc/borrow.rs index b5b1e22..617afcb 100644 --- a/src/foreign/alloc/borrow.rs +++ b/src/foreign/alloc/borrow.rs @@ -1,6 +1,6 @@ use { crate::{size_hint, Arbitrary, Result, Unstructured}, - std::borrow::{Cow, ToOwned}, + alloc::borrow::{Cow, ToOwned}, }; impl<'a, A> Arbitrary<'a> for Cow<'a, A> diff --git a/src/foreign/alloc/boxed.rs b/src/foreign/alloc/boxed.rs index c3014a3..f397557 100644 --- a/src/foreign/alloc/boxed.rs +++ b/src/foreign/alloc/boxed.rs @@ -1,6 +1,6 @@ use { crate::{size_hint, Arbitrary, Result, Unstructured}, - std::boxed::Box, + alloc::{boxed::Box, string::String}, }; impl<'a, A> Arbitrary<'a> for Box diff --git a/src/foreign/alloc/collections/binary_heap.rs b/src/foreign/alloc/collections/binary_heap.rs index 25a0384..02ef3fc 100644 --- a/src/foreign/alloc/collections/binary_heap.rs +++ b/src/foreign/alloc/collections/binary_heap.rs @@ -1,6 +1,6 @@ use { crate::{Arbitrary, Result, Unstructured}, - std::collections::binary_heap::BinaryHeap, + alloc::collections::binary_heap::BinaryHeap, }; impl<'a, A> Arbitrary<'a> for BinaryHeap diff --git a/src/foreign/alloc/collections/btree_map.rs b/src/foreign/alloc/collections/btree_map.rs index 21b93a4..65790c1 100644 --- a/src/foreign/alloc/collections/btree_map.rs +++ b/src/foreign/alloc/collections/btree_map.rs @@ -1,6 +1,6 @@ use { crate::{Arbitrary, Result, Unstructured}, - std::collections::btree_map::BTreeMap, + alloc::collections::btree_map::BTreeMap, }; impl<'a, K, V> Arbitrary<'a> for BTreeMap diff --git a/src/foreign/alloc/collections/btree_set.rs b/src/foreign/alloc/collections/btree_set.rs index 8c6e92f..b862a0f 100644 --- a/src/foreign/alloc/collections/btree_set.rs +++ b/src/foreign/alloc/collections/btree_set.rs @@ -1,6 +1,6 @@ use { crate::{Arbitrary, Result, Unstructured}, - std::collections::btree_set::BTreeSet, + alloc::collections::btree_set::BTreeSet, }; impl<'a, A> Arbitrary<'a> for BTreeSet diff --git a/src/foreign/alloc/collections/linked_list.rs b/src/foreign/alloc/collections/linked_list.rs index 6bf2e98..7bb6425 100644 --- a/src/foreign/alloc/collections/linked_list.rs +++ b/src/foreign/alloc/collections/linked_list.rs @@ -1,6 +1,6 @@ use { crate::{Arbitrary, Result, Unstructured}, - std::collections::linked_list::LinkedList, + alloc::collections::linked_list::LinkedList, }; impl<'a, A> Arbitrary<'a> for LinkedList diff --git a/src/foreign/alloc/collections/vec_deque.rs b/src/foreign/alloc/collections/vec_deque.rs index 40e0413..44a37b6 100644 --- a/src/foreign/alloc/collections/vec_deque.rs +++ b/src/foreign/alloc/collections/vec_deque.rs @@ -1,6 +1,6 @@ use { crate::{Arbitrary, Result, Unstructured}, - std::collections::vec_deque::VecDeque, + alloc::collections::vec_deque::VecDeque, }; impl<'a, A> Arbitrary<'a> for VecDeque diff --git a/src/foreign/alloc/ffi/c_str.rs b/src/foreign/alloc/ffi/c_str.rs index a1b2383..e95bbed 100644 --- a/src/foreign/alloc/ffi/c_str.rs +++ b/src/foreign/alloc/ffi/c_str.rs @@ -1,6 +1,6 @@ use { crate::{Arbitrary, Result, Unstructured}, - std::ffi::CString, + alloc::{ffi::CString, vec::Vec}, }; impl<'a> Arbitrary<'a> for CString { diff --git a/src/foreign/alloc/rc.rs b/src/foreign/alloc/rc.rs index 6d58167..2243be4 100644 --- a/src/foreign/alloc/rc.rs +++ b/src/foreign/alloc/rc.rs @@ -1,6 +1,6 @@ use { crate::{size_hint, Arbitrary, Result, Unstructured}, - std::rc::Rc, + alloc::rc::Rc, }; impl<'a, A> Arbitrary<'a> for Rc diff --git a/src/foreign/alloc/string.rs b/src/foreign/alloc/string.rs index a579784..47ea9eb 100644 --- a/src/foreign/alloc/string.rs +++ b/src/foreign/alloc/string.rs @@ -1,6 +1,6 @@ use { crate::{Arbitrary, Result, Unstructured}, - std::string::String, + alloc::string::String, }; impl<'a> Arbitrary<'a> for String { diff --git a/src/foreign/alloc/sync.rs b/src/foreign/alloc/sync.rs index c8ca1db..64d2dcd 100644 --- a/src/foreign/alloc/sync.rs +++ b/src/foreign/alloc/sync.rs @@ -1,6 +1,6 @@ use { crate::{size_hint, Arbitrary, Result, Unstructured}, - std::sync::Arc, + alloc::sync::Arc, }; impl<'a, A> Arbitrary<'a> for Arc diff --git a/src/foreign/alloc/vec.rs b/src/foreign/alloc/vec.rs index 63313ba..2985712 100644 --- a/src/foreign/alloc/vec.rs +++ b/src/foreign/alloc/vec.rs @@ -1,6 +1,6 @@ use { crate::{Arbitrary, Result, Unstructured}, - std::vec::Vec, + alloc::vec::Vec, }; impl<'a, A> Arbitrary<'a> for Vec diff --git a/src/foreign/mod.rs b/src/foreign/mod.rs index b1c42be..3868936 100644 --- a/src/foreign/mod.rs +++ b/src/foreign/mod.rs @@ -2,6 +2,8 @@ //! //! [`Arbitrary`]: crate::Arbitrary +#[cfg(feature = "alloc")] mod alloc; mod core; +#[cfg(feature = "std")] mod std; diff --git a/src/foreign/std/collections/hash_map.rs b/src/foreign/std/collections/hash_map.rs index d2e77af..85afe3a 100644 --- a/src/foreign/std/collections/hash_map.rs +++ b/src/foreign/std/collections/hash_map.rs @@ -1,9 +1,7 @@ use { crate::{Arbitrary, Result, Unstructured}, - std::{ - collections::hash_map::HashMap, - hash::{BuildHasher, Hash}, - }, + core::hash::{BuildHasher, Hash}, + std::collections::hash_map::HashMap, }; impl<'a, K, V, S> Arbitrary<'a> for HashMap diff --git a/src/foreign/std/collections/hash_set.rs b/src/foreign/std/collections/hash_set.rs index 5cb63d2..07c4c8a 100644 --- a/src/foreign/std/collections/hash_set.rs +++ b/src/foreign/std/collections/hash_set.rs @@ -1,9 +1,7 @@ use { crate::{Arbitrary, Result, Unstructured}, - std::{ - collections::hash_set::HashSet, - hash::{BuildHasher, Hash}, - }, + core::hash::{BuildHasher, Hash}, + std::collections::hash_set::HashSet, }; impl<'a, A, S> Arbitrary<'a> for HashSet diff --git a/src/lib.rs b/src/lib.rs index 8b28c69..50804f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,7 @@ //! [`Arbitrary`] trait's documentation for details on //! automatically deriving, implementing, and/or using the trait. +#![cfg_attr(not(any(feature = "std", test)), no_std)] #![deny(bad_style)] #![deny(missing_docs)] #![deny(future_incompatible)] @@ -22,6 +23,9 @@ #![deny(rust_2018_idioms)] #![deny(unused)] +#[cfg(feature = "alloc")] +extern crate alloc; + mod error; mod foreign; pub mod size_hint; @@ -49,7 +53,7 @@ impl core::fmt::Display for MaxRecursionReached { } } -impl std::error::Error for MaxRecursionReached {} +impl core::error::Error for MaxRecursionReached {} /// Generate arbitrary structured values from raw, unstructured data. /// @@ -122,9 +126,9 @@ impl std::error::Error for MaxRecursionReached {} /// /// ``` /// # #[cfg(feature = "derive")] mod foo { -/// # pub struct MyCollection { _t: std::marker::PhantomData } +/// # pub struct MyCollection { _t: core::marker::PhantomData } /// # impl MyCollection { -/// # pub fn new() -> Self { MyCollection { _t: std::marker::PhantomData } } +/// # pub fn new() -> Self { MyCollection { _t: core::marker::PhantomData } } /// # pub fn insert(&mut self, element: T) {} /// # } /// use arbitrary::{Arbitrary, Result, Unstructured}; @@ -554,7 +558,7 @@ pub struct CompileFailTests; // Support for `#[derive(Arbitrary)]`. #[doc(hidden)] -#[cfg(feature = "derive")] +#[cfg(all(feature = "derive", feature = "std"))] pub mod details { use super::*; diff --git a/src/size_hint.rs b/src/size_hint.rs index 95707ee..9f73346 100644 --- a/src/size_hint.rs +++ b/src/size_hint.rs @@ -67,10 +67,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/tests.rs b/src/tests.rs index 7746715..69c5c0e 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,6 +1,9 @@ +#[cfg(feature = "alloc")] +use alloc::{rc::Rc, string::String, sync::Arc, vec::Vec}; use { super::{Arbitrary, Result, Unstructured}, - std::{collections::HashSet, fmt::Debug, hash::Hash, rc::Rc, sync::Arc}, + core::{fmt::Debug, hash::Hash}, + std::collections::HashSet, }; /// Assert that the given expected values are all generated. @@ -154,6 +157,7 @@ fn arbitrary_take_rest_for_bytes() { } #[test] +#[cfg(feature = "alloc")] fn arbitrary_for_vec_u8() { assert_generates::>([ vec![], @@ -175,6 +179,7 @@ fn arbitrary_for_vec_u8() { } #[test] +#[cfg(feature = "alloc")] fn arbitrary_for_vec_vec_u8() { assert_generates::>>([ vec![], @@ -193,6 +198,7 @@ fn arbitrary_for_vec_vec_u8() { } #[test] +#[cfg(feature = "alloc")] fn arbitrary_for_vec_vec_vec_u8() { assert_generates::>>>([ vec![], @@ -217,11 +223,13 @@ fn arbitrary_for_vec_vec_vec_u8() { } #[test] +#[cfg(feature = "alloc")] fn arbitrary_for_string() { assert_generates::(["".into(), "a".into(), "aa".into(), "aaa".into()]); } #[test] +#[cfg(feature = "alloc")] fn arbitrary_collection() { let x = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 12, @@ -257,6 +265,7 @@ fn arbitrary_collection() { } #[test] +#[cfg(feature = "alloc")] fn arbitrary_take_rest() { // Basic examples let x = [1, 2, 3, 4]; @@ -307,6 +316,7 @@ fn arbitrary_take_rest() { } #[test] +#[cfg(feature = "alloc")] fn size_hint_for_tuples() { assert_eq!( (7, Some(7)), diff --git a/src/unstructured.rs b/src/unstructured.rs index 2b5e043..edccef2 100644 --- a/src/unstructured.rs +++ b/src/unstructured.rs @@ -9,9 +9,9 @@ //! Wrappers around raw, unstructured bytes. use crate::{Arbitrary, Error, Result}; -use std::marker::PhantomData; -use std::ops::ControlFlow; -use std::{mem, ops}; +use core::marker::PhantomData; +use core::ops::ControlFlow; +use core::{mem, ops}; /// A source of unstructured data. /// @@ -186,9 +186,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) {} /// # } /// @@ -218,7 +218,7 @@ impl<'a> Unstructured<'a> { let byte_size = self.arbitrary_byte_size()?; let (lower, upper) = ::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); Ok(byte_size / elem_size) } @@ -575,7 +575,7 @@ impl<'a> Unstructured<'a> { /// assert_eq!(buf, [0, 0]); /// ``` 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()); buffer[..n].copy_from_slice(&self.data[..n]); for byte in buffer[n..].iter_mut() { *byte = 0; @@ -691,8 +691,8 @@ impl<'a> Unstructured<'a> { /// times the function is called. /// /// You may break out of the loop early by returning - /// `Ok(std::ops::ControlFlow::Break)`. To continue the loop, return - /// `Ok(std::ops::ControlFlow::Continue)`. + /// `Ok(core::ops::ControlFlow::Break)`. To continue the loop, return + /// `Ok(core::ops::ControlFlow::Continue)`. /// /// # Panics /// @@ -705,7 +705,7 @@ impl<'a> Unstructured<'a> { /// /// ``` /// use arbitrary::{Result, Unstructured}; - /// use std::ops::ControlFlow; + /// use core::ops::ControlFlow; /// /// enum Type { /// /// A boolean type. @@ -819,7 +819,7 @@ impl<'a, ElementType: Arbitrary<'a>> Iterator for ArbitraryTakeRestIter<'a, Elem /// Don't implement this trait yourself. pub trait Int: Copy - + std::fmt::Debug + + core::fmt::Debug + PartialOrd + Ord + ops::Sub