From e54d1c7d0459d2c1060b329b9e96bf5e38e3725b Mon Sep 17 00:00:00 2001 From: Sebastian Walz Date: Thu, 22 Aug 2024 14:12:12 +0200 Subject: [PATCH] refactor(foreign): move implementations to dedicated directory At the moment, the trait-definition and all implementations for foreign types are located in `lib.rs` with 1732 LOC. IMHO this is difficult to maintain, especially when adding additional implementations. By moving all implementations into the private submodule foreign, sorting them by `core`, `alloc` and `std`, and submodules similar to those documented, I see i.a. the following advantages: 1. Easier to find for which types the trait is implemented, which implementations are missing, 2. If one wants to add a implementation, one can just place it in the module according to its type definition in `core`/`alloc`/`std` and does not have to guess, whether to place it at the beginning or end of `lib.rs` or somewhere random, 3. It will be easier to feature-gate some implementations, e.g. `std` for std-implementations, which should be a default-feature, which can be disabled for `no_std`-builds, 4. Implementations for additional (common) crates, e.g. `chrono` or `time`, can be placed in foreign behind feature-gates, 5. Changes to one file does not affect changes to other files, so merging multiple PRs might be less conflicting. Somewhat unrelated changes: Harmonising trait-bounds-placement. --- src/foreign/alloc/borrow.rs | 21 + src/foreign/alloc/boxed.rs | 47 + src/foreign/alloc/collections/binary_heap.rs | 22 + src/foreign/alloc/collections/btree_map.rs | 23 + src/foreign/alloc/collections/btree_set.rs | 22 + src/foreign/alloc/collections/linked_list.rs | 22 + src/foreign/alloc/collections/mod.rs | 5 + src/foreign/alloc/collections/vec_deque.rs | 22 + src/foreign/alloc/ffi/c_str.rs | 19 + src/foreign/alloc/ffi/mod.rs | 1 + src/foreign/alloc/mod.rs | 13 + src/foreign/alloc/rc.rs | 47 + src/foreign/alloc/string.rs | 19 + src/foreign/alloc/sync.rs | 47 + src/foreign/alloc/vec.rs | 22 + src/foreign/core/array.rs | 72 + src/foreign/core/bool.rs | 12 + src/foreign/core/cell.rs | 46 + src/foreign/core/char.rs | 24 + src/foreign/core/iter.rs | 18 + src/foreign/core/marker.rs | 29 + src/foreign/core/mod.rs | 20 + src/foreign/core/num.rs | 136 ++ src/foreign/core/ops.rs | 118 ++ src/foreign/core/option.rs | 22 + src/foreign/core/result.rs | 26 + src/foreign/core/slice.rs | 17 + src/foreign/core/str.rs | 39 + src/foreign/core/sync/atomic.rs | 37 + src/foreign/core/sync/mod.rs | 1 + src/foreign/core/time.rs | 21 + src/foreign/core/tuple.rs | 34 + src/foreign/core/unit.rs | 12 + src/foreign/mod.rs | 7 + src/foreign/std/collections/hash_map.rs | 27 + src/foreign/std/collections/hash_set.rs | 26 + src/foreign/std/collections/mod.rs | 2 + src/foreign/std/ffi/c_str.rs | 5 + src/foreign/std/ffi/mod.rs | 2 + src/foreign/std/ffi/os_str.rs | 22 + src/foreign/std/mod.rs | 10 + src/foreign/std/net.rs | 96 ++ src/foreign/std/path.rs | 15 + src/foreign/std/sync.rs | 18 + src/lib.rs | 1349 +----------------- src/tests.rs | 316 ++++ 46 files changed, 1592 insertions(+), 1339 deletions(-) create mode 100644 src/foreign/alloc/borrow.rs create mode 100644 src/foreign/alloc/boxed.rs create mode 100644 src/foreign/alloc/collections/binary_heap.rs create mode 100644 src/foreign/alloc/collections/btree_map.rs create mode 100644 src/foreign/alloc/collections/btree_set.rs create mode 100644 src/foreign/alloc/collections/linked_list.rs create mode 100644 src/foreign/alloc/collections/mod.rs create mode 100644 src/foreign/alloc/collections/vec_deque.rs create mode 100644 src/foreign/alloc/ffi/c_str.rs create mode 100644 src/foreign/alloc/ffi/mod.rs create mode 100644 src/foreign/alloc/mod.rs create mode 100644 src/foreign/alloc/rc.rs create mode 100644 src/foreign/alloc/string.rs create mode 100644 src/foreign/alloc/sync.rs create mode 100644 src/foreign/alloc/vec.rs create mode 100644 src/foreign/core/array.rs create mode 100644 src/foreign/core/bool.rs create mode 100644 src/foreign/core/cell.rs create mode 100644 src/foreign/core/char.rs create mode 100644 src/foreign/core/iter.rs create mode 100644 src/foreign/core/marker.rs create mode 100644 src/foreign/core/mod.rs create mode 100644 src/foreign/core/num.rs create mode 100644 src/foreign/core/ops.rs create mode 100644 src/foreign/core/option.rs create mode 100644 src/foreign/core/result.rs create mode 100644 src/foreign/core/slice.rs create mode 100644 src/foreign/core/str.rs create mode 100644 src/foreign/core/sync/atomic.rs create mode 100644 src/foreign/core/sync/mod.rs create mode 100644 src/foreign/core/time.rs create mode 100644 src/foreign/core/tuple.rs create mode 100644 src/foreign/core/unit.rs create mode 100644 src/foreign/mod.rs create mode 100644 src/foreign/std/collections/hash_map.rs create mode 100644 src/foreign/std/collections/hash_set.rs create mode 100644 src/foreign/std/collections/mod.rs create mode 100644 src/foreign/std/ffi/c_str.rs create mode 100644 src/foreign/std/ffi/mod.rs create mode 100644 src/foreign/std/ffi/os_str.rs create mode 100644 src/foreign/std/mod.rs create mode 100644 src/foreign/std/net.rs create mode 100644 src/foreign/std/path.rs create mode 100644 src/foreign/std/sync.rs create mode 100644 src/tests.rs diff --git a/src/foreign/alloc/borrow.rs b/src/foreign/alloc/borrow.rs new file mode 100644 index 0000000..a2809f0 --- /dev/null +++ b/src/foreign/alloc/borrow.rs @@ -0,0 +1,21 @@ +use { + crate::{size_hint, Arbitrary, Result, Unstructured}, + std::borrow::{Cow, ToOwned}, +}; + +impl<'a, A> Arbitrary<'a> for Cow<'a, A> +where + A: ToOwned + ?Sized, + ::Owned: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Cow::Owned) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::recursion_guard(depth, |depth| { + <::Owned as Arbitrary>::size_hint(depth) + }) + } +} diff --git a/src/foreign/alloc/boxed.rs b/src/foreign/alloc/boxed.rs new file mode 100644 index 0000000..d8c3437 --- /dev/null +++ b/src/foreign/alloc/boxed.rs @@ -0,0 +1,47 @@ +use { + crate::{size_hint, Arbitrary, Result, Unstructured}, + std::boxed::Box, +}; + +impl<'a, A> Arbitrary<'a> for Box +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::recursion_guard(depth, ::size_hint) + } +} + +impl<'a, A> Arbitrary<'a> for Box<[A]> +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} + +impl<'a> Arbitrary<'a> for Box { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + ::arbitrary(u).map(|x| x.into_boxed_str()) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + ::size_hint(depth) + } +} diff --git a/src/foreign/alloc/collections/binary_heap.rs b/src/foreign/alloc/collections/binary_heap.rs new file mode 100644 index 0000000..25a0384 --- /dev/null +++ b/src/foreign/alloc/collections/binary_heap.rs @@ -0,0 +1,22 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::collections::binary_heap::BinaryHeap, +}; + +impl<'a, A> Arbitrary<'a> for BinaryHeap +where + A: Arbitrary<'a> + Ord, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/src/foreign/alloc/collections/btree_map.rs b/src/foreign/alloc/collections/btree_map.rs new file mode 100644 index 0000000..21b93a4 --- /dev/null +++ b/src/foreign/alloc/collections/btree_map.rs @@ -0,0 +1,23 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::collections::btree_map::BTreeMap, +}; + +impl<'a, K, V> Arbitrary<'a> for BTreeMap +where + K: Arbitrary<'a> + Ord, + V: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/src/foreign/alloc/collections/btree_set.rs b/src/foreign/alloc/collections/btree_set.rs new file mode 100644 index 0000000..8c6e92f --- /dev/null +++ b/src/foreign/alloc/collections/btree_set.rs @@ -0,0 +1,22 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::collections::btree_set::BTreeSet, +}; + +impl<'a, A> Arbitrary<'a> for BTreeSet +where + A: Arbitrary<'a> + Ord, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/src/foreign/alloc/collections/linked_list.rs b/src/foreign/alloc/collections/linked_list.rs new file mode 100644 index 0000000..6bf2e98 --- /dev/null +++ b/src/foreign/alloc/collections/linked_list.rs @@ -0,0 +1,22 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::collections::linked_list::LinkedList, +}; + +impl<'a, A> Arbitrary<'a> for LinkedList +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/src/foreign/alloc/collections/mod.rs b/src/foreign/alloc/collections/mod.rs new file mode 100644 index 0000000..67ca908 --- /dev/null +++ b/src/foreign/alloc/collections/mod.rs @@ -0,0 +1,5 @@ +mod binary_heap; +mod btree_map; +mod btree_set; +mod linked_list; +mod vec_deque; diff --git a/src/foreign/alloc/collections/vec_deque.rs b/src/foreign/alloc/collections/vec_deque.rs new file mode 100644 index 0000000..40e0413 --- /dev/null +++ b/src/foreign/alloc/collections/vec_deque.rs @@ -0,0 +1,22 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::collections::vec_deque::VecDeque, +}; + +impl<'a, A> Arbitrary<'a> for VecDeque +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/src/foreign/alloc/ffi/c_str.rs b/src/foreign/alloc/ffi/c_str.rs new file mode 100644 index 0000000..a1b2383 --- /dev/null +++ b/src/foreign/alloc/ffi/c_str.rs @@ -0,0 +1,19 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::ffi::CString, +}; + +impl<'a> Arbitrary<'a> for CString { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + as Arbitrary>::arbitrary(u).map(|mut x| { + x.retain(|&c| c != 0); + // SAFETY: all zero bytes have been removed + unsafe { Self::from_vec_unchecked(x) } + }) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + as Arbitrary>::size_hint(depth) + } +} diff --git a/src/foreign/alloc/ffi/mod.rs b/src/foreign/alloc/ffi/mod.rs new file mode 100644 index 0000000..9238cfc --- /dev/null +++ b/src/foreign/alloc/ffi/mod.rs @@ -0,0 +1 @@ +mod c_str; diff --git a/src/foreign/alloc/mod.rs b/src/foreign/alloc/mod.rs new file mode 100644 index 0000000..a04b62c --- /dev/null +++ b/src/foreign/alloc/mod.rs @@ -0,0 +1,13 @@ +//! Implementations of [`Arbitrary`] for [`alloc`] types, +//! excluding those in [`core`]. +//! +//! [`Arbitrary`]: crate::Arbitrary + +mod borrow; +mod boxed; +mod collections; +mod ffi; +mod rc; +mod string; +mod sync; +mod vec; diff --git a/src/foreign/alloc/rc.rs b/src/foreign/alloc/rc.rs new file mode 100644 index 0000000..f529277 --- /dev/null +++ b/src/foreign/alloc/rc.rs @@ -0,0 +1,47 @@ +use { + crate::{size_hint, Arbitrary, Result, Unstructured}, + std::rc::Rc, +}; + +impl<'a, A> Arbitrary<'a> for Rc +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::recursion_guard(depth, ::size_hint) + } +} + +impl<'a, A> Arbitrary<'a> for Rc<[A]> +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} + +impl<'a> Arbitrary<'a> for Rc { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + <&str as Arbitrary>::arbitrary(u).map(Into::into) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + <&str as Arbitrary>::size_hint(depth) + } +} diff --git a/src/foreign/alloc/string.rs b/src/foreign/alloc/string.rs new file mode 100644 index 0000000..a579784 --- /dev/null +++ b/src/foreign/alloc/string.rs @@ -0,0 +1,19 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::string::String, +}; + +impl<'a> Arbitrary<'a> for String { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + <&str as Arbitrary>::arbitrary(u).map(Into::into) + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + <&str as Arbitrary>::arbitrary_take_rest(u).map(Into::into) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + <&str as Arbitrary>::size_hint(depth) + } +} diff --git a/src/foreign/alloc/sync.rs b/src/foreign/alloc/sync.rs new file mode 100644 index 0000000..8696e20 --- /dev/null +++ b/src/foreign/alloc/sync.rs @@ -0,0 +1,47 @@ +use { + crate::{size_hint, Arbitrary, Result, Unstructured}, + std::sync::Arc, +}; + +impl<'a, A> Arbitrary<'a> for Arc +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::recursion_guard(depth, ::size_hint) + } +} + +impl<'a, A> Arbitrary<'a> for Arc<[A]> +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} + +impl<'a> Arbitrary<'a> for Arc { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + <&str as Arbitrary>::arbitrary(u).map(Into::into) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + <&str as Arbitrary>::size_hint(depth) + } +} diff --git a/src/foreign/alloc/vec.rs b/src/foreign/alloc/vec.rs new file mode 100644 index 0000000..63313ba --- /dev/null +++ b/src/foreign/alloc/vec.rs @@ -0,0 +1,22 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::vec::Vec, +}; + +impl<'a, A> Arbitrary<'a> for Vec +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/src/foreign/core/array.rs b/src/foreign/core/array.rs new file mode 100644 index 0000000..553d95d --- /dev/null +++ b/src/foreign/core/array.rs @@ -0,0 +1,72 @@ +use { + crate::{size_hint, Arbitrary, Result, Unstructured}, + core::{ + array, + mem::{self, MaybeUninit}, + ptr, + }, +}; + +/// Helper to safely create arrays since the standard library doesn't +/// provide one yet. Shouldn't be necessary in the future. +struct ArrayGuard { + dst: *mut T, + initialized: usize, +} + +impl Drop for ArrayGuard { + fn drop(&mut self) { + debug_assert!(self.initialized <= N); + let initialized_part = ptr::slice_from_raw_parts_mut(self.dst, self.initialized); + unsafe { + ptr::drop_in_place(initialized_part); + } + } +} + +fn try_create_array(mut cb: F) -> Result<[T; N]> +where + F: FnMut(usize) -> Result, +{ + let mut array: MaybeUninit<[T; N]> = MaybeUninit::uninit(); + let array_ptr = array.as_mut_ptr(); + let dst = array_ptr as _; + let mut guard: ArrayGuard = ArrayGuard { + dst, + initialized: 0, + }; + unsafe { + for (idx, value_ptr) in (*array.as_mut_ptr()).iter_mut().enumerate() { + ptr::write(value_ptr, cb(idx)?); + guard.initialized += 1; + } + mem::forget(guard); + Ok(array.assume_init()) + } +} + +impl<'a, T, const N: usize> Arbitrary<'a> for [T; N] +where + T: Arbitrary<'a>, +{ + #[inline] + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + try_create_array(|_| >::arbitrary(u)) + } + + #[inline] + fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { + let mut array = Self::arbitrary(&mut u)?; + if let Some(last) = array.last_mut() { + *last = Arbitrary::arbitrary_take_rest(u)?; + } + Ok(array) + } + + #[inline] + fn size_hint(d: usize) -> (usize, Option) { + size_hint::and_all(&array::from_fn::<_, N, _>(|_| { + ::size_hint(d) + })) + } +} diff --git a/src/foreign/core/bool.rs b/src/foreign/core/bool.rs new file mode 100644 index 0000000..42e82fb --- /dev/null +++ b/src/foreign/core/bool.rs @@ -0,0 +1,12 @@ +use crate::{Arbitrary, Result, Unstructured}; + +impl<'a> Arbitrary<'a> for bool { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(>::arbitrary(u)? & 1 == 1) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + >::size_hint(depth) + } +} diff --git a/src/foreign/core/cell.rs b/src/foreign/core/cell.rs new file mode 100644 index 0000000..dea6a64 --- /dev/null +++ b/src/foreign/core/cell.rs @@ -0,0 +1,46 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + core::cell::{Cell, RefCell, UnsafeCell}, +}; + +impl<'a, A> Arbitrary<'a> for Cell +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + >::size_hint(depth) + } +} + +impl<'a, A> Arbitrary<'a> for RefCell +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + >::size_hint(depth) + } +} + +impl<'a, A> Arbitrary<'a> for UnsafeCell +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + >::size_hint(depth) + } +} diff --git a/src/foreign/core/char.rs b/src/foreign/core/char.rs new file mode 100644 index 0000000..1adc62d --- /dev/null +++ b/src/foreign/core/char.rs @@ -0,0 +1,24 @@ +use crate::{Arbitrary, Result, Unstructured}; + +impl<'a> Arbitrary<'a> for char { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + // The highest unicode code point is 0x11_FFFF + const CHAR_END: u32 = 0x11_0000; + // The size of the surrogate blocks + const SURROGATES_START: u32 = 0xD800; + let mut c = >::arbitrary(u)? % CHAR_END; + if let Some(c) = char::from_u32(c) { + Ok(c) + } else { + // We found a surrogate, wrap and try again + c -= SURROGATES_START; + Ok(char::from_u32(c) + .expect("Generated character should be valid! This is a bug in arbitrary-rs")) + } + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + >::size_hint(depth) + } +} diff --git a/src/foreign/core/iter.rs b/src/foreign/core/iter.rs new file mode 100644 index 0000000..8a56f2a --- /dev/null +++ b/src/foreign/core/iter.rs @@ -0,0 +1,18 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + core::iter::{empty, Empty}, +}; + +impl<'a, A> Arbitrary<'a> for Empty +where + A: Arbitrary<'a>, +{ + fn arbitrary(_: &mut Unstructured<'a>) -> Result { + Ok(empty()) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, Some(0)) + } +} diff --git a/src/foreign/core/marker.rs b/src/foreign/core/marker.rs new file mode 100644 index 0000000..aa0afbe --- /dev/null +++ b/src/foreign/core/marker.rs @@ -0,0 +1,29 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + core::marker::{PhantomData, PhantomPinned}, +}; + +impl<'a, A> Arbitrary<'a> for PhantomData +where + A: ?Sized, +{ + fn arbitrary(_: &mut Unstructured<'a>) -> Result { + Ok(PhantomData) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, Some(0)) + } +} + +impl<'a> Arbitrary<'a> for PhantomPinned { + fn arbitrary(_: &mut Unstructured<'a>) -> Result { + Ok(PhantomPinned) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, Some(0)) + } +} diff --git a/src/foreign/core/mod.rs b/src/foreign/core/mod.rs new file mode 100644 index 0000000..1e525f3 --- /dev/null +++ b/src/foreign/core/mod.rs @@ -0,0 +1,20 @@ +//! Implementations of [`Arbitrary`] for [`core`] types. +//! +//! [`Arbitrary`]: crate::Arbitrary + +mod array; +mod bool; +mod cell; +mod char; +mod iter; +mod marker; +mod num; +mod ops; +mod option; +mod result; +mod slice; +mod str; +mod sync; +mod time; +mod tuple; +mod unit; diff --git a/src/foreign/core/num.rs b/src/foreign/core/num.rs new file mode 100644 index 0000000..3828336 --- /dev/null +++ b/src/foreign/core/num.rs @@ -0,0 +1,136 @@ +use { + crate::{Arbitrary, Error, Result, Unstructured}, + core::{ + mem, + num::{ + NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, + NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping, + }, + }, +}; + +macro_rules! impl_arbitrary_for_integers { + ( $( $ty:ty; )* ) => { + $( + impl<'a> Arbitrary<'a> for $ty { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let mut buf = [0; mem::size_of::<$ty>()]; + u.fill_buffer(&mut buf)?; + Ok(Self::from_le_bytes(buf)) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + let n = mem::size_of::<$ty>(); + (n, Some(n)) + } + + } + )* + } +} + +impl_arbitrary_for_integers! { + u8; + u16; + u32; + u64; + u128; + i8; + i16; + i32; + i64; + i128; +} + +// Note: We forward Arbitrary for i/usize to i/u64 in order to simplify corpus +// compatibility between 32-bit and 64-bit builds. This introduces dead space in +// 32-bit builds but keeps the input layout independent of the build platform. +impl<'a> Arbitrary<'a> for usize { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary::().map(|x| x as usize) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + ::size_hint(depth) + } +} + +impl<'a> Arbitrary<'a> for isize { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary::().map(|x| x as isize) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + ::size_hint(depth) + } +} + +macro_rules! impl_arbitrary_for_floats { + ( $( $ty:ident : $unsigned:ty; )* ) => { + $( + impl<'a> Arbitrary<'a> for $ty { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(Self::from_bits(<$unsigned as Arbitrary<'a>>::arbitrary(u)?)) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + <$unsigned as Arbitrary<'a>>::size_hint(depth) + } + } + )* + } +} + +impl_arbitrary_for_floats! { + f32: u32; + f64: u64; +} + +macro_rules! implement_nonzero_int { + ($nonzero:ty, $int:ty) => { + impl<'a> Arbitrary<'a> for $nonzero { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + match Self::new(<$int as Arbitrary<'a>>::arbitrary(u)?) { + Some(n) => Ok(n), + None => Err(Error::IncorrectFormat), + } + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + <$int as Arbitrary<'a>>::size_hint(depth) + } + } + }; +} + +implement_nonzero_int! { NonZeroI8, i8 } +implement_nonzero_int! { NonZeroI16, i16 } +implement_nonzero_int! { NonZeroI32, i32 } +implement_nonzero_int! { NonZeroI64, i64 } +implement_nonzero_int! { NonZeroI128, i128 } +implement_nonzero_int! { NonZeroIsize, isize } +implement_nonzero_int! { NonZeroU8, u8 } +implement_nonzero_int! { NonZeroU16, u16 } +implement_nonzero_int! { NonZeroU32, u32 } +implement_nonzero_int! { NonZeroU64, u64 } +implement_nonzero_int! { NonZeroU128, u128 } +implement_nonzero_int! { NonZeroUsize, usize } + +impl<'a, A> Arbitrary<'a> for Wrapping +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Wrapping) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + >::size_hint(depth) + } +} diff --git a/src/foreign/core/ops.rs b/src/foreign/core/ops.rs new file mode 100644 index 0000000..31cb82e --- /dev/null +++ b/src/foreign/core/ops.rs @@ -0,0 +1,118 @@ +use { + crate::{size_hint, Arbitrary, Result, Unstructured}, + core::{ + mem, + ops::{Bound, Range, RangeBounds, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive}, + }, +}; + +macro_rules! impl_range { + ( + $range:ty, + $value_closure:expr, + $value_ty:ty, + $fun:ident($fun_closure:expr), + $size_hint_closure:expr + ) => { + impl<'a, A> Arbitrary<'a> for $range + where + A: Arbitrary<'a> + Clone + PartialOrd, + { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let value: $value_ty = Arbitrary::arbitrary(u)?; + Ok($fun(value, $fun_closure)) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + #[allow(clippy::redundant_closure_call)] + $size_hint_closure(depth) + } + } + }; +} + +impl_range!( + Range, + |r: &Range| (r.start.clone(), r.end.clone()), + (A, A), + bounded_range(|(a, b)| a..b), + |depth| size_hint::and( + ::size_hint(depth), + ::size_hint(depth) + ) +); +impl_range!( + RangeFrom, + |r: &RangeFrom| r.start.clone(), + A, + unbounded_range(|a| a..), + |depth| ::size_hint(depth) +); +impl_range!( + RangeInclusive, + |r: &RangeInclusive| (r.start().clone(), r.end().clone()), + (A, A), + bounded_range(|(a, b)| a..=b), + |depth| size_hint::and( + ::size_hint(depth), + ::size_hint(depth) + ) +); +impl_range!( + RangeTo, + |r: &RangeTo| r.end.clone(), + A, + unbounded_range(|b| ..b), + |depth| ::size_hint(depth) +); +impl_range!( + RangeToInclusive, + |r: &RangeToInclusive| r.end.clone(), + A, + unbounded_range(|b| ..=b), + |depth| ::size_hint(depth) +); + +pub(crate) fn bounded_range(bounds: (I, I), cb: CB) -> R +where + CB: Fn((I, I)) -> R, + I: PartialOrd, + R: RangeBounds, +{ + let (mut start, mut end) = bounds; + if start > end { + mem::swap(&mut start, &mut end); + } + cb((start, end)) +} + +pub(crate) fn unbounded_range(bound: I, cb: CB) -> R +where + CB: Fn(I) -> R, + R: RangeBounds, +{ + cb(bound) +} + +impl<'a, A> Arbitrary<'a> for Bound +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + match u.int_in_range::(0..=2)? { + 0 => Ok(Bound::Included(A::arbitrary(u)?)), + 1 => Ok(Bound::Excluded(A::arbitrary(u)?)), + 2 => Ok(Bound::Unbounded), + _ => unreachable!(), + } + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::or( + size_hint::and((1, Some(1)), A::size_hint(depth)), + (1, Some(1)), + ) + } +} diff --git a/src/foreign/core/option.rs b/src/foreign/core/option.rs new file mode 100644 index 0000000..cc14833 --- /dev/null +++ b/src/foreign/core/option.rs @@ -0,0 +1,22 @@ +use crate::{size_hint, Arbitrary, Result, Unstructured}; + +impl<'a, A> Arbitrary<'a> for Option +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(if >::arbitrary(u)? { + Some(Arbitrary::arbitrary(u)?) + } else { + None + }) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::and( + ::size_hint(depth), + size_hint::or((0, Some(0)), ::size_hint(depth)), + ) + } +} diff --git a/src/foreign/core/result.rs b/src/foreign/core/result.rs new file mode 100644 index 0000000..28bf075 --- /dev/null +++ b/src/foreign/core/result.rs @@ -0,0 +1,26 @@ +use crate::{size_hint, Arbitrary, Error, Unstructured}; + +impl<'a, T, E> Arbitrary<'a> for Result +where + T: Arbitrary<'a>, + E: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(if >::arbitrary(u)? { + Ok(::arbitrary(u)?) + } else { + Err(::arbitrary(u)?) + }) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::and( + ::size_hint(depth), + size_hint::or( + ::size_hint(depth), + ::size_hint(depth), + ), + ) + } +} diff --git a/src/foreign/core/slice.rs b/src/foreign/core/slice.rs new file mode 100644 index 0000000..296d474 --- /dev/null +++ b/src/foreign/core/slice.rs @@ -0,0 +1,17 @@ +use crate::{Arbitrary, Result, Unstructured}; + +impl<'a> Arbitrary<'a> for &'a [u8] { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let len = u.arbitrary_len::()?; + u.bytes(len) + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + Ok(u.take_rest()) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/src/foreign/core/str.rs b/src/foreign/core/str.rs new file mode 100644 index 0000000..cfca8ad --- /dev/null +++ b/src/foreign/core/str.rs @@ -0,0 +1,39 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + core::str, +}; + +fn arbitrary_str<'a>(u: &mut Unstructured<'a>, size: usize) -> Result<&'a str> { + match str::from_utf8(u.peek_bytes(size).unwrap()) { + Ok(s) => { + u.bytes(size).unwrap(); + Ok(s) + } + Err(e) => { + let i = e.valid_up_to(); + let valid = u.bytes(i).unwrap(); + let s = unsafe { + debug_assert!(str::from_utf8(valid).is_ok()); + str::from_utf8_unchecked(valid) + }; + Ok(s) + } + } +} + +impl<'a> Arbitrary<'a> for &'a str { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let size = u.arbitrary_len::()?; + arbitrary_str(u, size) + } + + fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { + let size = u.len(); + arbitrary_str(&mut u, size) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/src/foreign/core/sync/atomic.rs b/src/foreign/core/sync/atomic.rs new file mode 100644 index 0000000..004c396 --- /dev/null +++ b/src/foreign/core/sync/atomic.rs @@ -0,0 +1,37 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + core::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize}, +}; + +impl<'a> Arbitrary<'a> for AtomicBool { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + >::size_hint(depth) + } +} + +impl<'a> Arbitrary<'a> for AtomicIsize { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + >::size_hint(depth) + } +} + +impl<'a> Arbitrary<'a> for AtomicUsize { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + >::size_hint(depth) + } +} diff --git a/src/foreign/core/sync/mod.rs b/src/foreign/core/sync/mod.rs new file mode 100644 index 0000000..f7b1416 --- /dev/null +++ b/src/foreign/core/sync/mod.rs @@ -0,0 +1 @@ +mod atomic; diff --git a/src/foreign/core/time.rs b/src/foreign/core/time.rs new file mode 100644 index 0000000..9ab3434 --- /dev/null +++ b/src/foreign/core/time.rs @@ -0,0 +1,21 @@ +use { + crate::{size_hint, Arbitrary, Result, Unstructured}, + core::time::Duration, +}; + +impl<'a> Arbitrary<'a> for Duration { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(Self::new( + ::arbitrary(u)?, + u.int_in_range(0..=999_999_999)?, + )) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::and( + ::size_hint(depth), + ::size_hint(depth), + ) + } +} diff --git a/src/foreign/core/tuple.rs b/src/foreign/core/tuple.rs new file mode 100644 index 0000000..d98e019 --- /dev/null +++ b/src/foreign/core/tuple.rs @@ -0,0 +1,34 @@ +use crate::{size_hint, Arbitrary, Result, Unstructured}; + +macro_rules! arbitrary_tuple { + () => {}; + ($last: ident $($xs: ident)*) => { + arbitrary_tuple!($($xs)*); + + impl<'a, $($xs,)* $last> Arbitrary<'a> for ($($xs,)* $last,) + where + $($xs: Arbitrary<'a>,)* + $last: Arbitrary<'a>, + { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(($($xs::arbitrary(u)?,)* Arbitrary::arbitrary(u)?,)) + } + + #[allow(unused_mut, non_snake_case)] + fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { + $(let $xs = $xs::arbitrary(&mut u)?;)* + let $last = $last::arbitrary_take_rest(u)?; + Ok(($($xs,)* $last,)) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::and_all(&[ + <$last as Arbitrary>::size_hint(depth), + $( <$xs as Arbitrary>::size_hint(depth) ),* + ]) + } + } + }; +} +arbitrary_tuple!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z); diff --git a/src/foreign/core/unit.rs b/src/foreign/core/unit.rs new file mode 100644 index 0000000..20523a6 --- /dev/null +++ b/src/foreign/core/unit.rs @@ -0,0 +1,12 @@ +use crate::{Arbitrary, Result, Unstructured}; + +impl<'a> Arbitrary<'a> for () { + fn arbitrary(_: &mut Unstructured<'a>) -> Result { + Ok(()) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, Some(0)) + } +} diff --git a/src/foreign/mod.rs b/src/foreign/mod.rs new file mode 100644 index 0000000..b1c42be --- /dev/null +++ b/src/foreign/mod.rs @@ -0,0 +1,7 @@ +//! Implementations of [`Arbitrary`] for foreign types. +//! +//! [`Arbitrary`]: crate::Arbitrary + +mod alloc; +mod core; +mod std; diff --git a/src/foreign/std/collections/hash_map.rs b/src/foreign/std/collections/hash_map.rs new file mode 100644 index 0000000..d2e77af --- /dev/null +++ b/src/foreign/std/collections/hash_map.rs @@ -0,0 +1,27 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::{ + collections::hash_map::HashMap, + hash::{BuildHasher, Hash}, + }, +}; + +impl<'a, K, V, S> Arbitrary<'a> for HashMap +where + K: Arbitrary<'a> + Eq + Hash, + V: Arbitrary<'a>, + S: BuildHasher + Default, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/src/foreign/std/collections/hash_set.rs b/src/foreign/std/collections/hash_set.rs new file mode 100644 index 0000000..5cb63d2 --- /dev/null +++ b/src/foreign/std/collections/hash_set.rs @@ -0,0 +1,26 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::{ + collections::hash_set::HashSet, + hash::{BuildHasher, Hash}, + }, +}; + +impl<'a, A, S> Arbitrary<'a> for HashSet +where + A: Arbitrary<'a> + Eq + Hash, + S: BuildHasher + Default, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + u.arbitrary_iter()?.collect() + } + + fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { + u.arbitrary_take_rest_iter()?.collect() + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} diff --git a/src/foreign/std/collections/mod.rs b/src/foreign/std/collections/mod.rs new file mode 100644 index 0000000..2bde6a0 --- /dev/null +++ b/src/foreign/std/collections/mod.rs @@ -0,0 +1,2 @@ +mod hash_map; +mod hash_set; diff --git a/src/foreign/std/ffi/c_str.rs b/src/foreign/std/ffi/c_str.rs new file mode 100644 index 0000000..7a1dc29 --- /dev/null +++ b/src/foreign/std/ffi/c_str.rs @@ -0,0 +1,5 @@ +// impl Arbitrary for Box { +// fn arbitrary(u: &mut Unstructured<'_>) -> Result { +// ::arbitrary(u).map(|x| x.into_boxed_c_str()) +// } +// } diff --git a/src/foreign/std/ffi/mod.rs b/src/foreign/std/ffi/mod.rs new file mode 100644 index 0000000..f5d739f --- /dev/null +++ b/src/foreign/std/ffi/mod.rs @@ -0,0 +1,2 @@ +mod c_str; +mod os_str; diff --git a/src/foreign/std/ffi/os_str.rs b/src/foreign/std/ffi/os_str.rs new file mode 100644 index 0000000..9fa0cb3 --- /dev/null +++ b/src/foreign/std/ffi/os_str.rs @@ -0,0 +1,22 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::ffi::OsString, +}; + +impl<'a> Arbitrary<'a> for OsString { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + ::arbitrary(u).map(From::from) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + ::size_hint(depth) + } +} + +// impl Arbitrary for Box { +// fn arbitrary(u: &mut Unstructured<'_>) -> Result { +// ::arbitrary(u).map(|x| x.into_boxed_osstr()) +// +// } +// } diff --git a/src/foreign/std/mod.rs b/src/foreign/std/mod.rs new file mode 100644 index 0000000..bc85aa2 --- /dev/null +++ b/src/foreign/std/mod.rs @@ -0,0 +1,10 @@ +//! Implementations of [`Arbitrary`] for [`std`] types, +//! excluding those in [`core`] and [`alloc`]. +//! +//! [`Arbitrary`]: crate::Arbitrary + +mod collections; +mod ffi; +mod net; +mod path; +mod sync; diff --git a/src/foreign/std/net.rs b/src/foreign/std/net.rs new file mode 100644 index 0000000..41e1f8a --- /dev/null +++ b/src/foreign/std/net.rs @@ -0,0 +1,96 @@ +use { + crate::{size_hint, Arbitrary, Result, Unstructured}, + std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, +}; + +impl<'a> Arbitrary<'a> for Ipv4Addr { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(Ipv4Addr::from(u32::arbitrary(u)?)) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (4, Some(4)) + } +} + +impl<'a> Arbitrary<'a> for Ipv6Addr { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(Ipv6Addr::from(u128::arbitrary(u)?)) + } + + #[inline] + fn size_hint(_depth: usize) -> (usize, Option) { + (16, Some(16)) + } +} + +impl<'a> Arbitrary<'a> for IpAddr { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + if u.arbitrary()? { + Ok(IpAddr::V4(u.arbitrary()?)) + } else { + Ok(IpAddr::V6(u.arbitrary()?)) + } + } + + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::and( + bool::size_hint(depth), + size_hint::or(Ipv4Addr::size_hint(depth), Ipv6Addr::size_hint(depth)), + ) + } +} + +impl<'a> Arbitrary<'a> for SocketAddrV4 { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(SocketAddrV4::new(u.arbitrary()?, u.arbitrary()?)) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::and(Ipv4Addr::size_hint(depth), u16::size_hint(depth)) + } +} + +impl<'a> Arbitrary<'a> for SocketAddrV6 { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Ok(SocketAddrV6::new( + u.arbitrary()?, + u.arbitrary()?, + u.arbitrary()?, + u.arbitrary()?, + )) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::and( + Ipv6Addr::size_hint(depth), + size_hint::and( + u16::size_hint(depth), + size_hint::and(u32::size_hint(depth), u32::size_hint(depth)), + ), + ) + } +} + +impl<'a> Arbitrary<'a> for SocketAddr { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + if u.arbitrary()? { + Ok(SocketAddr::V4(u.arbitrary()?)) + } else { + Ok(SocketAddr::V6(u.arbitrary()?)) + } + } + + fn size_hint(depth: usize) -> (usize, Option) { + size_hint::and( + bool::size_hint(depth), + size_hint::or( + SocketAddrV4::size_hint(depth), + SocketAddrV6::size_hint(depth), + ), + ) + } +} diff --git a/src/foreign/std/path.rs b/src/foreign/std/path.rs new file mode 100644 index 0000000..c94797b --- /dev/null +++ b/src/foreign/std/path.rs @@ -0,0 +1,15 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::{ffi::OsString, path::PathBuf}, +}; + +impl<'a> Arbitrary<'a> for PathBuf { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + ::arbitrary(u).map(From::from) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + ::size_hint(depth) + } +} diff --git a/src/foreign/std/sync.rs b/src/foreign/std/sync.rs new file mode 100644 index 0000000..acc047a --- /dev/null +++ b/src/foreign/std/sync.rs @@ -0,0 +1,18 @@ +use { + crate::{Arbitrary, Result, Unstructured}, + std::sync::Mutex, +}; + +impl<'a, A> Arbitrary<'a> for Mutex +where + A: Arbitrary<'a>, +{ + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + Arbitrary::arbitrary(u).map(Self::new) + } + + #[inline] + fn size_hint(depth: usize) -> (usize, Option) { + >::size_hint(depth) + } +} diff --git a/src/lib.rs b/src/lib.rs index 6ff98f3..56ecac6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,38 +22,22 @@ #![deny(rust_2018_idioms)] #![deny(unused)] -#[cfg(feature = "derive_arbitrary")] -pub use derive_arbitrary::*; - mod error; +mod foreign; +pub mod size_hint; +pub mod unstructured; + +#[cfg(test)] +mod tests; + pub use error::*; -pub mod unstructured; +#[cfg(feature = "derive_arbitrary")] +pub use derive_arbitrary::*; + #[doc(inline)] pub use unstructured::Unstructured; -pub mod size_hint; - -use core::array; -use core::cell::{Cell, RefCell, UnsafeCell}; -use core::iter; -use core::mem; -use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; -use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; -use core::ops::{Range, RangeBounds, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive}; -use core::str; -use core::time::Duration; -use std::borrow::{Cow, ToOwned}; -use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; -use std::ffi::{CString, OsString}; -use std::hash::BuildHasher; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; -use std::ops::Bound; -use std::path::PathBuf; -use std::rc::Rc; -use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize}; -use std::sync::{Arc, Mutex}; - /// Generate arbitrary structured values from raw, unstructured data. /// /// The `Arbitrary` trait allows you to generate valid structured values, like @@ -310,1319 +294,6 @@ pub trait Arbitrary<'a>: Sized { } } -impl<'a> Arbitrary<'a> for () { - fn arbitrary(_: &mut Unstructured<'a>) -> Result { - Ok(()) - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, Some(0)) - } -} - -impl<'a> Arbitrary<'a> for bool { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Ok(>::arbitrary(u)? & 1 == 1) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - >::size_hint(depth) - } -} - -macro_rules! impl_arbitrary_for_integers { - ( $( $ty:ty; )* ) => { - $( - impl<'a> Arbitrary<'a> for $ty { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - let mut buf = [0; mem::size_of::<$ty>()]; - u.fill_buffer(&mut buf)?; - Ok(Self::from_le_bytes(buf)) - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - let n = mem::size_of::<$ty>(); - (n, Some(n)) - } - - } - )* - } -} - -impl_arbitrary_for_integers! { - u8; - u16; - u32; - u64; - u128; - i8; - i16; - i32; - i64; - i128; -} - -// Note: We forward Arbitrary for i/usize to i/u64 in order to simplify corpus -// compatibility between 32-bit and 64-bit builds. This introduces dead space in -// 32-bit builds but keeps the input layout independent of the build platform. -impl<'a> Arbitrary<'a> for usize { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - u.arbitrary::().map(|x| x as usize) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - ::size_hint(depth) - } -} - -impl<'a> Arbitrary<'a> for isize { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - u.arbitrary::().map(|x| x as isize) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - ::size_hint(depth) - } -} - -macro_rules! impl_arbitrary_for_floats { - ( $( $ty:ident : $unsigned:ty; )* ) => { - $( - impl<'a> Arbitrary<'a> for $ty { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Ok(Self::from_bits(<$unsigned as Arbitrary<'a>>::arbitrary(u)?)) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - <$unsigned as Arbitrary<'a>>::size_hint(depth) - } - } - )* - } -} - -impl_arbitrary_for_floats! { - f32: u32; - f64: u64; -} - -impl<'a> Arbitrary<'a> for char { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - use std::char; - // The highest unicode code point is 0x11_FFFF - const CHAR_END: u32 = 0x11_0000; - // The size of the surrogate blocks - const SURROGATES_START: u32 = 0xD800; - let mut c = >::arbitrary(u)? % CHAR_END; - if let Some(c) = char::from_u32(c) { - Ok(c) - } else { - // We found a surrogate, wrap and try again - c -= SURROGATES_START; - Ok(char::from_u32(c) - .expect("Generated character should be valid! This is a bug in arbitrary-rs")) - } - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - >::size_hint(depth) - } -} - -impl<'a> Arbitrary<'a> for AtomicBool { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Arbitrary::arbitrary(u).map(Self::new) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - >::size_hint(depth) - } -} - -impl<'a> Arbitrary<'a> for AtomicIsize { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Arbitrary::arbitrary(u).map(Self::new) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - >::size_hint(depth) - } -} - -impl<'a> Arbitrary<'a> for AtomicUsize { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Arbitrary::arbitrary(u).map(Self::new) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - >::size_hint(depth) - } -} - -macro_rules! impl_range { - ( - $range:ty, - $value_closure:expr, - $value_ty:ty, - $fun:ident($fun_closure:expr), - $size_hint_closure:expr - ) => { - impl<'a, A> Arbitrary<'a> for $range - where - A: Arbitrary<'a> + Clone + PartialOrd, - { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - let value: $value_ty = Arbitrary::arbitrary(u)?; - Ok($fun(value, $fun_closure)) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - #[allow(clippy::redundant_closure_call)] - $size_hint_closure(depth) - } - } - }; -} - -impl_range!( - Range, - |r: &Range| (r.start.clone(), r.end.clone()), - (A, A), - bounded_range(|(a, b)| a..b), - |depth| crate::size_hint::and( - ::size_hint(depth), - ::size_hint(depth) - ) -); -impl_range!( - RangeFrom, - |r: &RangeFrom| r.start.clone(), - A, - unbounded_range(|a| a..), - |depth| ::size_hint(depth) -); -impl_range!( - RangeInclusive, - |r: &RangeInclusive| (r.start().clone(), r.end().clone()), - (A, A), - bounded_range(|(a, b)| a..=b), - |depth| crate::size_hint::and( - ::size_hint(depth), - ::size_hint(depth) - ) -); -impl_range!( - RangeTo, - |r: &RangeTo| r.end.clone(), - A, - unbounded_range(|b| ..b), - |depth| ::size_hint(depth) -); -impl_range!( - RangeToInclusive, - |r: &RangeToInclusive| r.end.clone(), - A, - unbounded_range(|b| ..=b), - |depth| ::size_hint(depth) -); - -pub(crate) fn bounded_range(bounds: (I, I), cb: CB) -> R -where - CB: Fn((I, I)) -> R, - I: PartialOrd, - R: RangeBounds, -{ - let (mut start, mut end) = bounds; - if start > end { - mem::swap(&mut start, &mut end); - } - cb((start, end)) -} - -pub(crate) fn unbounded_range(bound: I, cb: CB) -> R -where - CB: Fn(I) -> R, - R: RangeBounds, -{ - cb(bound) -} - -impl<'a> Arbitrary<'a> for Duration { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Ok(Self::new( - ::arbitrary(u)?, - u.int_in_range(0..=999_999_999)?, - )) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - crate::size_hint::and( - ::size_hint(depth), - ::size_hint(depth), - ) - } -} - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Option { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Ok(if >::arbitrary(u)? { - Some(Arbitrary::arbitrary(u)?) - } else { - None - }) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - crate::size_hint::and( - ::size_hint(depth), - crate::size_hint::or((0, Some(0)), ::size_hint(depth)), - ) - } -} - -impl<'a, A: Arbitrary<'a>, B: Arbitrary<'a>> Arbitrary<'a> for std::result::Result { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Ok(if >::arbitrary(u)? { - Ok(::arbitrary(u)?) - } else { - Err(::arbitrary(u)?) - }) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - crate::size_hint::and( - ::size_hint(depth), - crate::size_hint::or( - ::size_hint(depth), - ::size_hint(depth), - ), - ) - } -} - -macro_rules! arbitrary_tuple { - () => {}; - ($last: ident $($xs: ident)*) => { - arbitrary_tuple!($($xs)*); - - impl<'a, $($xs: Arbitrary<'a>,)* $last: Arbitrary<'a>> Arbitrary<'a> for ($($xs,)* $last,) { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Ok(($($xs::arbitrary(u)?,)* Arbitrary::arbitrary(u)?,)) - } - - #[allow(unused_mut, non_snake_case)] - fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { - $(let $xs = $xs::arbitrary(&mut u)?;)* - let $last = $last::arbitrary_take_rest(u)?; - Ok(($($xs,)* $last,)) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - crate::size_hint::and_all(&[ - <$last as Arbitrary>::size_hint(depth), - $( <$xs as Arbitrary>::size_hint(depth) ),* - ]) - } - } - }; -} -arbitrary_tuple!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z); - -// Helper to safely create arrays since the standard library doesn't -// provide one yet. Shouldn't be necessary in the future. -struct ArrayGuard { - dst: *mut T, - initialized: usize, -} - -impl Drop for ArrayGuard { - fn drop(&mut self) { - debug_assert!(self.initialized <= N); - let initialized_part = core::ptr::slice_from_raw_parts_mut(self.dst, self.initialized); - unsafe { - core::ptr::drop_in_place(initialized_part); - } - } -} - -fn try_create_array(mut cb: F) -> Result<[T; N]> -where - F: FnMut(usize) -> Result, -{ - let mut array: mem::MaybeUninit<[T; N]> = mem::MaybeUninit::uninit(); - let array_ptr = array.as_mut_ptr(); - let dst = array_ptr as _; - let mut guard: ArrayGuard = ArrayGuard { - dst, - initialized: 0, - }; - unsafe { - for (idx, value_ptr) in (*array.as_mut_ptr()).iter_mut().enumerate() { - core::ptr::write(value_ptr, cb(idx)?); - guard.initialized += 1; - } - mem::forget(guard); - Ok(array.assume_init()) - } -} - -impl<'a, T, const N: usize> Arbitrary<'a> for [T; N] -where - T: Arbitrary<'a>, -{ - #[inline] - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - try_create_array(|_| >::arbitrary(u)) - } - - #[inline] - fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { - let mut array = Self::arbitrary(&mut u)?; - if let Some(last) = array.last_mut() { - *last = Arbitrary::arbitrary_take_rest(u)?; - } - Ok(array) - } - - #[inline] - fn size_hint(d: usize) -> (usize, Option) { - crate::size_hint::and_all(&array::from_fn::<_, N, _>(|_| { - ::size_hint(d) - })) - } -} - -impl<'a> Arbitrary<'a> for &'a [u8] { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - let len = u.arbitrary_len::()?; - u.bytes(len) - } - - fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { - Ok(u.take_rest()) - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, None) - } -} - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Vec { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - u.arbitrary_iter()?.collect() - } - - fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { - u.arbitrary_take_rest_iter()?.collect() - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, None) - } -} - -impl<'a, K: Arbitrary<'a> + Ord, V: Arbitrary<'a>> Arbitrary<'a> for BTreeMap { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - u.arbitrary_iter()?.collect() - } - - fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { - u.arbitrary_take_rest_iter()?.collect() - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, None) - } -} - -impl<'a, A: Arbitrary<'a> + Ord> Arbitrary<'a> for BTreeSet { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - u.arbitrary_iter()?.collect() - } - - fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { - u.arbitrary_take_rest_iter()?.collect() - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, None) - } -} - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Bound { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - match u.int_in_range::(0..=2)? { - 0 => Ok(Bound::Included(A::arbitrary(u)?)), - 1 => Ok(Bound::Excluded(A::arbitrary(u)?)), - 2 => Ok(Bound::Unbounded), - _ => unreachable!(), - } - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - size_hint::or( - size_hint::and((1, Some(1)), A::size_hint(depth)), - (1, Some(1)), - ) - } -} - -impl<'a, A: Arbitrary<'a> + Ord> Arbitrary<'a> for BinaryHeap { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - u.arbitrary_iter()?.collect() - } - - fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { - u.arbitrary_take_rest_iter()?.collect() - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, None) - } -} - -impl<'a, K: Arbitrary<'a> + Eq + ::std::hash::Hash, V: Arbitrary<'a>, S: BuildHasher + Default> - Arbitrary<'a> for HashMap -{ - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - u.arbitrary_iter()?.collect() - } - - fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { - u.arbitrary_take_rest_iter()?.collect() - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, None) - } -} - -impl<'a, A: Arbitrary<'a> + Eq + ::std::hash::Hash, S: BuildHasher + Default> Arbitrary<'a> - for HashSet -{ - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - u.arbitrary_iter()?.collect() - } - - fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { - u.arbitrary_take_rest_iter()?.collect() - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, None) - } -} - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for LinkedList { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - u.arbitrary_iter()?.collect() - } - - fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { - u.arbitrary_take_rest_iter()?.collect() - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, None) - } -} - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for VecDeque { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - u.arbitrary_iter()?.collect() - } - - fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { - u.arbitrary_take_rest_iter()?.collect() - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, None) - } -} - -impl<'a, A> Arbitrary<'a> for Cow<'a, A> -where - A: ToOwned + ?Sized, - ::Owned: Arbitrary<'a>, -{ - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Arbitrary::arbitrary(u).map(Cow::Owned) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - crate::size_hint::recursion_guard(depth, |depth| { - <::Owned as Arbitrary>::size_hint(depth) - }) - } -} - -fn arbitrary_str<'a>(u: &mut Unstructured<'a>, size: usize) -> Result<&'a str> { - match str::from_utf8(u.peek_bytes(size).unwrap()) { - Ok(s) => { - u.bytes(size).unwrap(); - Ok(s) - } - Err(e) => { - let i = e.valid_up_to(); - let valid = u.bytes(i).unwrap(); - let s = unsafe { - debug_assert!(str::from_utf8(valid).is_ok()); - str::from_utf8_unchecked(valid) - }; - Ok(s) - } - } -} - -impl<'a> Arbitrary<'a> for &'a str { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - let size = u.arbitrary_len::()?; - arbitrary_str(u, size) - } - - fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { - let size = u.len(); - arbitrary_str(&mut u, size) - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, None) - } -} - -impl<'a> Arbitrary<'a> for String { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - <&str as Arbitrary>::arbitrary(u).map(Into::into) - } - - fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { - <&str as Arbitrary>::arbitrary_take_rest(u).map(Into::into) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - <&str as Arbitrary>::size_hint(depth) - } -} - -impl<'a> Arbitrary<'a> for CString { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - as Arbitrary>::arbitrary(u).map(|mut x| { - x.retain(|&c| c != 0); - // SAFETY: all zero bytes have been removed - unsafe { Self::from_vec_unchecked(x) } - }) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - as Arbitrary>::size_hint(depth) - } -} - -impl<'a> Arbitrary<'a> for OsString { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - ::arbitrary(u).map(From::from) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - ::size_hint(depth) - } -} - -impl<'a> Arbitrary<'a> for PathBuf { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - ::arbitrary(u).map(From::from) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - ::size_hint(depth) - } -} - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Box { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Arbitrary::arbitrary(u).map(Self::new) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - crate::size_hint::recursion_guard(depth, ::size_hint) - } -} - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Box<[A]> { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - u.arbitrary_iter()?.collect() - } - - fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { - u.arbitrary_take_rest_iter()?.collect() - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, None) - } -} - -impl<'a> Arbitrary<'a> for Box { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - ::arbitrary(u).map(|x| x.into_boxed_str()) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - ::size_hint(depth) - } -} - -// impl Arbitrary for Box { -// fn arbitrary(u: &mut Unstructured<'_>) -> Result { -// ::arbitrary(u).map(|x| x.into_boxed_c_str()) -// } -// } - -// impl Arbitrary for Box { -// fn arbitrary(u: &mut Unstructured<'_>) -> Result { -// ::arbitrary(u).map(|x| x.into_boxed_osstr()) -// -// } -// } - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Arc { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Arbitrary::arbitrary(u).map(Self::new) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - crate::size_hint::recursion_guard(depth, ::size_hint) - } -} - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Arc<[A]> { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - u.arbitrary_iter()?.collect() - } - - fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { - u.arbitrary_take_rest_iter()?.collect() - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, None) - } -} - -impl<'a> Arbitrary<'a> for Arc { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - <&str as Arbitrary>::arbitrary(u).map(Into::into) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - <&str as Arbitrary>::size_hint(depth) - } -} - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Rc { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Arbitrary::arbitrary(u).map(Self::new) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - crate::size_hint::recursion_guard(depth, ::size_hint) - } -} - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Rc<[A]> { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - u.arbitrary_iter()?.collect() - } - - fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { - u.arbitrary_take_rest_iter()?.collect() - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, None) - } -} - -impl<'a> Arbitrary<'a> for Rc { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - <&str as Arbitrary>::arbitrary(u).map(Into::into) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - <&str as Arbitrary>::size_hint(depth) - } -} - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Cell { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Arbitrary::arbitrary(u).map(Self::new) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - >::size_hint(depth) - } -} - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for RefCell { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Arbitrary::arbitrary(u).map(Self::new) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - >::size_hint(depth) - } -} - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for UnsafeCell { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Arbitrary::arbitrary(u).map(Self::new) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - >::size_hint(depth) - } -} - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Mutex { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Arbitrary::arbitrary(u).map(Self::new) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - >::size_hint(depth) - } -} - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for iter::Empty { - fn arbitrary(_: &mut Unstructured<'a>) -> Result { - Ok(iter::empty()) - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, Some(0)) - } -} - -impl<'a, A: ?Sized> Arbitrary<'a> for ::std::marker::PhantomData { - fn arbitrary(_: &mut Unstructured<'a>) -> Result { - Ok(::std::marker::PhantomData) - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, Some(0)) - } -} - -impl<'a> Arbitrary<'a> for ::std::marker::PhantomPinned { - fn arbitrary(_: &mut Unstructured<'a>) -> Result { - Ok(::std::marker::PhantomPinned) - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (0, Some(0)) - } -} - -impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for ::std::num::Wrapping { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Arbitrary::arbitrary(u).map(::std::num::Wrapping) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - >::size_hint(depth) - } -} - -macro_rules! implement_nonzero_int { - ($nonzero:ty, $int:ty) => { - impl<'a> Arbitrary<'a> for $nonzero { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - match Self::new(<$int as Arbitrary<'a>>::arbitrary(u)?) { - Some(n) => Ok(n), - None => Err(Error::IncorrectFormat), - } - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - <$int as Arbitrary<'a>>::size_hint(depth) - } - } - }; -} - -implement_nonzero_int! { NonZeroI8, i8 } -implement_nonzero_int! { NonZeroI16, i16 } -implement_nonzero_int! { NonZeroI32, i32 } -implement_nonzero_int! { NonZeroI64, i64 } -implement_nonzero_int! { NonZeroI128, i128 } -implement_nonzero_int! { NonZeroIsize, isize } -implement_nonzero_int! { NonZeroU8, u8 } -implement_nonzero_int! { NonZeroU16, u16 } -implement_nonzero_int! { NonZeroU32, u32 } -implement_nonzero_int! { NonZeroU64, u64 } -implement_nonzero_int! { NonZeroU128, u128 } -implement_nonzero_int! { NonZeroUsize, usize } - -impl<'a> Arbitrary<'a> for Ipv4Addr { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Ok(Ipv4Addr::from(u32::arbitrary(u)?)) - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (4, Some(4)) - } -} - -impl<'a> Arbitrary<'a> for Ipv6Addr { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Ok(Ipv6Addr::from(u128::arbitrary(u)?)) - } - - #[inline] - fn size_hint(_depth: usize) -> (usize, Option) { - (16, Some(16)) - } -} - -impl<'a> Arbitrary<'a> for IpAddr { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - if u.arbitrary()? { - Ok(IpAddr::V4(u.arbitrary()?)) - } else { - Ok(IpAddr::V6(u.arbitrary()?)) - } - } - - fn size_hint(depth: usize) -> (usize, Option) { - size_hint::and( - bool::size_hint(depth), - size_hint::or(Ipv4Addr::size_hint(depth), Ipv6Addr::size_hint(depth)), - ) - } -} - -impl<'a> Arbitrary<'a> for SocketAddrV4 { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Ok(SocketAddrV4::new(u.arbitrary()?, u.arbitrary()?)) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - size_hint::and(Ipv4Addr::size_hint(depth), u16::size_hint(depth)) - } -} - -impl<'a> Arbitrary<'a> for SocketAddrV6 { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - Ok(SocketAddrV6::new( - u.arbitrary()?, - u.arbitrary()?, - u.arbitrary()?, - u.arbitrary()?, - )) - } - - #[inline] - fn size_hint(depth: usize) -> (usize, Option) { - size_hint::and( - Ipv6Addr::size_hint(depth), - size_hint::and( - u16::size_hint(depth), - size_hint::and(u32::size_hint(depth), u32::size_hint(depth)), - ), - ) - } -} - -impl<'a> Arbitrary<'a> for SocketAddr { - fn arbitrary(u: &mut Unstructured<'a>) -> Result { - if u.arbitrary()? { - Ok(SocketAddr::V4(u.arbitrary()?)) - } else { - Ok(SocketAddr::V6(u.arbitrary()?)) - } - } - - fn size_hint(depth: usize) -> (usize, Option) { - size_hint::and( - bool::size_hint(depth), - size_hint::or( - SocketAddrV4::size_hint(depth), - SocketAddrV6::size_hint(depth), - ), - ) - } -} - -#[cfg(test)] -mod test { - use super::*; - - /// Assert that the given expected values are all generated. - /// - /// Exhaustively enumerates all buffers up to length 10 containing the - /// following bytes: `0x00`, `0x01`, `0x61` (aka ASCII 'a'), and `0xff` - fn assert_generates(expected_values: impl IntoIterator) - where - T: Clone + std::fmt::Debug + std::hash::Hash + Eq + for<'a> Arbitrary<'a>, - { - let expected_values: HashSet<_> = expected_values.into_iter().collect(); - let mut arbitrary_expected = expected_values.clone(); - let mut arbitrary_take_rest_expected = expected_values; - - let bytes = [0, 1, b'a', 0xff]; - let max_len = 10; - - let mut buf = Vec::with_capacity(max_len); - - let mut g = exhaustigen::Gen::new(); - while !g.done() { - let len = g.gen(max_len); - - buf.clear(); - buf.extend( - std::iter::repeat_with(|| { - let index = g.gen(bytes.len() - 1); - bytes[index] - }) - .take(len), - ); - - let mut u = Unstructured::new(&buf); - let val = T::arbitrary(&mut u).unwrap(); - arbitrary_expected.remove(&val); - - let u = Unstructured::new(&buf); - let val = T::arbitrary_take_rest(u).unwrap(); - arbitrary_take_rest_expected.remove(&val); - - if arbitrary_expected.is_empty() && arbitrary_take_rest_expected.is_empty() { - return; - } - } - - panic!( - "failed to generate all expected values!\n\n\ - T::arbitrary did not generate: {arbitrary_expected:#?}\n\n\ - T::arbitrary_take_rest did not generate {arbitrary_take_rest_expected:#?}" - ) - } - - /// Generates an arbitrary `T`, and checks that the result is consistent with the - /// `size_hint()` reported by `T`. - fn checked_arbitrary<'a, T: Arbitrary<'a>>(u: &mut Unstructured<'a>) -> Result { - let (min, max) = T::size_hint(0); - - let len_before = u.len(); - let result = T::arbitrary(u); - - let consumed = len_before - u.len(); - - if let Some(max) = max { - assert!( - consumed <= max, - "incorrect maximum size: indicated {}, actually consumed {}", - max, - consumed - ); - } - - if result.is_ok() { - assert!( - consumed >= min, - "incorrect minimum size: indicated {}, actually consumed {}", - min, - consumed - ); - } - - result - } - - /// Like `checked_arbitrary()`, but calls `arbitrary_take_rest()` instead of `arbitrary()`. - fn checked_arbitrary_take_rest<'a, T: Arbitrary<'a>>(u: Unstructured<'a>) -> Result { - let (min, _) = T::size_hint(0); - - let len_before = u.len(); - let result = T::arbitrary_take_rest(u); - - if result.is_ok() { - assert!( - len_before >= min, - "incorrect minimum size: indicated {}, worked with {}", - min, - len_before - ); - } - - result - } - - #[test] - fn finite_buffer_fill_buffer() { - let x = [1, 2, 3, 4]; - let mut rb = Unstructured::new(&x); - let mut z = [0; 2]; - rb.fill_buffer(&mut z).unwrap(); - assert_eq!(z, [1, 2]); - rb.fill_buffer(&mut z).unwrap(); - assert_eq!(z, [3, 4]); - rb.fill_buffer(&mut z).unwrap(); - assert_eq!(z, [0, 0]); - } - - #[test] - fn arbitrary_for_integers() { - let x = [1, 2, 3, 4]; - let mut buf = Unstructured::new(&x); - let expected = 1 | (2 << 8) | (3 << 16) | (4 << 24); - let actual = checked_arbitrary::(&mut buf).unwrap(); - assert_eq!(expected, actual); - - assert_generates([ - i32::from_ne_bytes([0, 0, 0, 0]), - i32::from_ne_bytes([0, 0, 0, 1]), - i32::from_ne_bytes([0, 0, 1, 0]), - i32::from_ne_bytes([0, 1, 0, 0]), - i32::from_ne_bytes([1, 0, 0, 0]), - i32::from_ne_bytes([1, 1, 1, 1]), - i32::from_ne_bytes([0xff, 0xff, 0xff, 0xff]), - ]); - } - - #[test] - fn arbitrary_for_bytes() { - let x = [1, 2, 3, 4, 4]; - let mut buf = Unstructured::new(&x); - let expected = &[1, 2, 3, 4]; - let actual = checked_arbitrary::<&[u8]>(&mut buf).unwrap(); - assert_eq!(expected, actual); - } - - #[test] - fn arbitrary_take_rest_for_bytes() { - let x = [1, 2, 3, 4]; - let buf = Unstructured::new(&x); - let expected = &[1, 2, 3, 4]; - let actual = checked_arbitrary_take_rest::<&[u8]>(buf).unwrap(); - assert_eq!(expected, actual); - } - - #[test] - fn arbitrary_for_vec_u8() { - assert_generates::>([ - vec![], - vec![0], - vec![1], - vec![0, 0], - vec![0, 1], - vec![1, 0], - vec![1, 1], - vec![0, 0, 0], - vec![0, 0, 1], - vec![0, 1, 0], - vec![0, 1, 1], - vec![1, 0, 0], - vec![1, 0, 1], - vec![1, 1, 0], - vec![1, 1, 1], - ]); - } - - #[test] - fn arbitrary_for_vec_vec_u8() { - assert_generates::>>([ - vec![], - vec![vec![]], - vec![vec![0]], - vec![vec![1]], - vec![vec![0, 1]], - vec![vec![], vec![]], - vec![vec![0], vec![]], - vec![vec![], vec![1]], - vec![vec![0], vec![1]], - vec![vec![0, 1], vec![]], - vec![vec![], vec![1, 0]], - vec![vec![], vec![], vec![]], - ]); - } - - #[test] - fn arbitrary_for_vec_vec_vec_u8() { - assert_generates::>>>([ - vec![], - vec![vec![]], - vec![vec![vec![0]]], - vec![vec![vec![1]]], - vec![vec![vec![0, 1]]], - vec![vec![], vec![]], - vec![vec![], vec![vec![]]], - vec![vec![vec![]], vec![]], - vec![vec![vec![]], vec![vec![]]], - vec![vec![vec![0]], vec![]], - vec![vec![], vec![vec![1]]], - vec![vec![vec![0]], vec![vec![1]]], - vec![vec![vec![0, 1]], vec![]], - vec![vec![], vec![vec![0, 1]]], - vec![vec![], vec![], vec![]], - vec![vec![vec![]], vec![], vec![]], - vec![vec![], vec![vec![]], vec![]], - vec![vec![], vec![], vec![vec![]]], - ]); - } - - #[test] - fn arbitrary_for_string() { - assert_generates::(["".into(), "a".into(), "aa".into(), "aaa".into()]); - } - - #[test] - 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, - ]; - assert_eq!( - checked_arbitrary::<&[u8]>(&mut Unstructured::new(&x)).unwrap(), - &[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3] - ); - assert_eq!( - checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), - &[2, 4, 6, 8, 1] - ); - assert_eq!( - &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), - &[2, 4, 6, 8, 1] - ); - assert_eq!( - &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), - &[2, 4, 6, 8, 1] - ); - assert_eq!( - &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), - &[2, 4, 6, 8, 1] - ); - assert_eq!( - checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), - &[84148994] - ); - assert_eq!( - checked_arbitrary::(&mut Unstructured::new(&x)).unwrap(), - "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x01\x02\x03" - ); - } - - #[test] - fn arbitrary_take_rest() { - // Basic examples - let x = [1, 2, 3, 4]; - assert_eq!( - checked_arbitrary_take_rest::<&[u8]>(Unstructured::new(&x)).unwrap(), - &[1, 2, 3, 4] - ); - assert_eq!( - checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), - &[2, 4] - ); - assert_eq!( - &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), - &[2, 4] - ); - assert_eq!( - &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), - &[2, 4] - ); - assert_eq!( - &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), - &[2, 4] - ); - assert_eq!( - checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), - &[0x040302] - ); - assert_eq!( - checked_arbitrary_take_rest::(Unstructured::new(&x)).unwrap(), - "\x01\x02\x03\x04" - ); - - // Empty remainder - assert_eq!( - checked_arbitrary_take_rest::<&[u8]>(Unstructured::new(&[])).unwrap(), - &[] - ); - assert_eq!( - checked_arbitrary_take_rest::>(Unstructured::new(&[])).unwrap(), - &[] - ); - - // Cannot consume all but can consume part of the input - assert_eq!( - checked_arbitrary_take_rest::(Unstructured::new(&[1, 0xFF, 2])).unwrap(), - "\x01" - ); - } - - #[test] - fn size_hint_for_tuples() { - assert_eq!( - (7, Some(7)), - <(bool, u16, i32) as Arbitrary<'_>>::size_hint(0) - ); - assert_eq!((1, None), <(u8, Vec) as Arbitrary>::size_hint(0)); - } -} - /// Multiple conflicting arbitrary attributes are used on the same field: /// ```compile_fail /// #[derive(::arbitrary::Arbitrary)] diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..7746715 --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,316 @@ +use { + super::{Arbitrary, Result, Unstructured}, + std::{collections::HashSet, fmt::Debug, hash::Hash, rc::Rc, sync::Arc}, +}; + +/// Assert that the given expected values are all generated. +/// +/// Exhaustively enumerates all buffers up to length 10 containing the +/// following bytes: `0x00`, `0x01`, `0x61` (aka ASCII 'a'), and `0xff` +fn assert_generates(expected_values: impl IntoIterator) +where + T: Clone + Debug + Hash + Eq + for<'a> Arbitrary<'a>, +{ + let expected_values: HashSet<_> = expected_values.into_iter().collect(); + let mut arbitrary_expected = expected_values.clone(); + let mut arbitrary_take_rest_expected = expected_values; + + let bytes = [0, 1, b'a', 0xff]; + let max_len = 10; + + let mut buf = Vec::with_capacity(max_len); + + let mut g = exhaustigen::Gen::new(); + while !g.done() { + let len = g.gen(max_len); + + buf.clear(); + buf.extend( + std::iter::repeat_with(|| { + let index = g.gen(bytes.len() - 1); + bytes[index] + }) + .take(len), + ); + + let mut u = Unstructured::new(&buf); + let val = T::arbitrary(&mut u).unwrap(); + arbitrary_expected.remove(&val); + + let u = Unstructured::new(&buf); + let val = T::arbitrary_take_rest(u).unwrap(); + arbitrary_take_rest_expected.remove(&val); + + if arbitrary_expected.is_empty() && arbitrary_take_rest_expected.is_empty() { + return; + } + } + + panic!( + "failed to generate all expected values!\n\n\ + T::arbitrary did not generate: {arbitrary_expected:#?}\n\n\ + T::arbitrary_take_rest did not generate {arbitrary_take_rest_expected:#?}" + ) +} + +/// Generates an arbitrary `T`, and checks that the result is consistent with the +/// `size_hint()` reported by `T`. +fn checked_arbitrary<'a, T: Arbitrary<'a>>(u: &mut Unstructured<'a>) -> Result { + let (min, max) = T::size_hint(0); + + let len_before = u.len(); + let result = T::arbitrary(u); + + let consumed = len_before - u.len(); + + if let Some(max) = max { + assert!( + consumed <= max, + "incorrect maximum size: indicated {}, actually consumed {}", + max, + consumed + ); + } + + if result.is_ok() { + assert!( + consumed >= min, + "incorrect minimum size: indicated {}, actually consumed {}", + min, + consumed + ); + } + + result +} + +/// Like `checked_arbitrary()`, but calls `arbitrary_take_rest()` instead of `arbitrary()`. +fn checked_arbitrary_take_rest<'a, T: Arbitrary<'a>>(u: Unstructured<'a>) -> Result { + let (min, _) = T::size_hint(0); + + let len_before = u.len(); + let result = T::arbitrary_take_rest(u); + + if result.is_ok() { + assert!( + len_before >= min, + "incorrect minimum size: indicated {}, worked with {}", + min, + len_before + ); + } + + result +} + +#[test] +fn finite_buffer_fill_buffer() { + let x = [1, 2, 3, 4]; + let mut rb = Unstructured::new(&x); + let mut z = [0; 2]; + rb.fill_buffer(&mut z).unwrap(); + assert_eq!(z, [1, 2]); + rb.fill_buffer(&mut z).unwrap(); + assert_eq!(z, [3, 4]); + rb.fill_buffer(&mut z).unwrap(); + assert_eq!(z, [0, 0]); +} + +#[test] +fn arbitrary_for_integers() { + let x = [1, 2, 3, 4]; + let mut buf = Unstructured::new(&x); + let expected = 1 | (2 << 8) | (3 << 16) | (4 << 24); + let actual = checked_arbitrary::(&mut buf).unwrap(); + assert_eq!(expected, actual); + + assert_generates([ + i32::from_ne_bytes([0, 0, 0, 0]), + i32::from_ne_bytes([0, 0, 0, 1]), + i32::from_ne_bytes([0, 0, 1, 0]), + i32::from_ne_bytes([0, 1, 0, 0]), + i32::from_ne_bytes([1, 0, 0, 0]), + i32::from_ne_bytes([1, 1, 1, 1]), + i32::from_ne_bytes([0xff, 0xff, 0xff, 0xff]), + ]); +} + +#[test] +fn arbitrary_for_bytes() { + let x = [1, 2, 3, 4, 4]; + let mut buf = Unstructured::new(&x); + let expected = &[1, 2, 3, 4]; + let actual = checked_arbitrary::<&[u8]>(&mut buf).unwrap(); + assert_eq!(expected, actual); +} + +#[test] +fn arbitrary_take_rest_for_bytes() { + let x = [1, 2, 3, 4]; + let buf = Unstructured::new(&x); + let expected = &[1, 2, 3, 4]; + let actual = checked_arbitrary_take_rest::<&[u8]>(buf).unwrap(); + assert_eq!(expected, actual); +} + +#[test] +fn arbitrary_for_vec_u8() { + assert_generates::>([ + vec![], + vec![0], + vec![1], + vec![0, 0], + vec![0, 1], + vec![1, 0], + vec![1, 1], + vec![0, 0, 0], + vec![0, 0, 1], + vec![0, 1, 0], + vec![0, 1, 1], + vec![1, 0, 0], + vec![1, 0, 1], + vec![1, 1, 0], + vec![1, 1, 1], + ]); +} + +#[test] +fn arbitrary_for_vec_vec_u8() { + assert_generates::>>([ + vec![], + vec![vec![]], + vec![vec![0]], + vec![vec![1]], + vec![vec![0, 1]], + vec![vec![], vec![]], + vec![vec![0], vec![]], + vec![vec![], vec![1]], + vec![vec![0], vec![1]], + vec![vec![0, 1], vec![]], + vec![vec![], vec![1, 0]], + vec![vec![], vec![], vec![]], + ]); +} + +#[test] +fn arbitrary_for_vec_vec_vec_u8() { + assert_generates::>>>([ + vec![], + vec![vec![]], + vec![vec![vec![0]]], + vec![vec![vec![1]]], + vec![vec![vec![0, 1]]], + vec![vec![], vec![]], + vec![vec![], vec![vec![]]], + vec![vec![vec![]], vec![]], + vec![vec![vec![]], vec![vec![]]], + vec![vec![vec![0]], vec![]], + vec![vec![], vec![vec![1]]], + vec![vec![vec![0]], vec![vec![1]]], + vec![vec![vec![0, 1]], vec![]], + vec![vec![], vec![vec![0, 1]]], + vec![vec![], vec![], vec![]], + vec![vec![vec![]], vec![], vec![]], + vec![vec![], vec![vec![]], vec![]], + vec![vec![], vec![], vec![vec![]]], + ]); +} + +#[test] +fn arbitrary_for_string() { + assert_generates::(["".into(), "a".into(), "aa".into(), "aaa".into()]); +} + +#[test] +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, + ]; + assert_eq!( + checked_arbitrary::<&[u8]>(&mut Unstructured::new(&x)).unwrap(), + &[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3] + ); + assert_eq!( + checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), + &[2, 4, 6, 8, 1] + ); + assert_eq!( + &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), + &[2, 4, 6, 8, 1] + ); + assert_eq!( + &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), + &[2, 4, 6, 8, 1] + ); + assert_eq!( + &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), + &[2, 4, 6, 8, 1] + ); + assert_eq!( + checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), + &[84148994] + ); + assert_eq!( + checked_arbitrary::(&mut Unstructured::new(&x)).unwrap(), + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x01\x02\x03" + ); +} + +#[test] +fn arbitrary_take_rest() { + // Basic examples + let x = [1, 2, 3, 4]; + assert_eq!( + checked_arbitrary_take_rest::<&[u8]>(Unstructured::new(&x)).unwrap(), + &[1, 2, 3, 4] + ); + assert_eq!( + checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), + &[2, 4] + ); + assert_eq!( + &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), + &[2, 4] + ); + assert_eq!( + &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), + &[2, 4] + ); + assert_eq!( + &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), + &[2, 4] + ); + assert_eq!( + checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), + &[0x040302] + ); + assert_eq!( + checked_arbitrary_take_rest::(Unstructured::new(&x)).unwrap(), + "\x01\x02\x03\x04" + ); + + // Empty remainder + assert_eq!( + checked_arbitrary_take_rest::<&[u8]>(Unstructured::new(&[])).unwrap(), + &[] + ); + assert_eq!( + checked_arbitrary_take_rest::>(Unstructured::new(&[])).unwrap(), + &[] + ); + + // Cannot consume all but can consume part of the input + assert_eq!( + checked_arbitrary_take_rest::(Unstructured::new(&[1, 0xFF, 2])).unwrap(), + "\x01" + ); +} + +#[test] +fn size_hint_for_tuples() { + assert_eq!( + (7, Some(7)), + <(bool, u16, i32) as Arbitrary<'_>>::size_hint(0) + ); + assert_eq!((1, None), <(u8, Vec) as Arbitrary>::size_hint(0)); +}