Skip to content

Commit 6b72fd8

Browse files
authored
Merge pull request #55 from c410-f3r/array
Add support for arbritrary arrays
2 parents f3301e0 + f69268c commit 6b72fd8

File tree

1 file changed

+71
-41
lines changed

1 file changed

+71
-41
lines changed

src/lib.rs

+71-41
Original file line numberDiff line numberDiff line change
@@ -571,61 +571,91 @@ macro_rules! arbitrary_tuple {
571571
}
572572
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);
573573

574-
macro_rules! arbitrary_array {
575-
{$n:expr, ($t:ident, $a:ident) $(($ts:ident, $as:ident))*} => {
576-
arbitrary_array!{($n - 1), $(($ts, $as))*}
577-
578-
impl<'a, T: Arbitrary<'a>> Arbitrary<'a> for [T; $n] {
579-
fn arbitrary(u: &mut Unstructured<'a>) -> Result<[T; $n]> {
580-
Ok([
581-
Arbitrary::arbitrary(u)?,
582-
$(<$ts as Arbitrary>::arbitrary(u)?),*
583-
])
584-
}
585-
586-
#[allow(unused_mut)]
587-
fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result<[T; $n]> {
588-
$(let $as = $ts::arbitrary(&mut u)?;)*
589-
let last = Arbitrary::arbitrary_take_rest(u)?;
574+
// Helper to safely create arrays since the standard library doesn't
575+
// provide one yet. Shouldn't be necessary in the future.
576+
struct ArrayGuard<T, const N: usize> {
577+
dst: *mut T,
578+
initialized: usize,
579+
}
590580

591-
Ok([
592-
$($as,)* last
593-
])
594-
}
581+
impl<T, const N: usize> Drop for ArrayGuard<T, N> {
582+
fn drop(&mut self) {
583+
debug_assert!(self.initialized <= N);
584+
let initialized_part = core::ptr::slice_from_raw_parts_mut(self.dst, self.initialized);
585+
unsafe {
586+
core::ptr::drop_in_place(initialized_part);
587+
}
588+
}
589+
}
595590

596-
#[inline]
597-
fn size_hint(depth: usize) -> (usize, Option<usize>) {
598-
crate::size_hint::and_all(&[
599-
<$t as Arbitrary>::size_hint(depth),
600-
$( <$ts as Arbitrary>::size_hint(depth) ),*
601-
])
602-
}
591+
fn create_array<F, T, const N: usize>(mut cb: F) -> [T; N]
592+
where
593+
F: FnMut(usize) -> T,
594+
{
595+
let mut array: mem::MaybeUninit<[T; N]> = mem::MaybeUninit::uninit();
596+
let array_ptr = array.as_mut_ptr();
597+
let dst = array_ptr as _;
598+
let mut guard: ArrayGuard<T, N> = ArrayGuard {
599+
dst,
600+
initialized: 0,
601+
};
602+
unsafe {
603+
for (idx, value_ptr) in (&mut *array.as_mut_ptr()).iter_mut().enumerate() {
604+
core::ptr::write(value_ptr, cb(idx));
605+
guard.initialized += 1;
603606
}
607+
mem::forget(guard);
608+
array.assume_init()
609+
}
610+
}
611+
612+
fn try_create_array<F, T, const N: usize>(mut cb: F) -> Result<[T; N]>
613+
where
614+
F: FnMut(usize) -> Result<T>,
615+
{
616+
let mut array: mem::MaybeUninit<[T; N]> = mem::MaybeUninit::uninit();
617+
let array_ptr = array.as_mut_ptr();
618+
let dst = array_ptr as _;
619+
let mut guard: ArrayGuard<T, N> = ArrayGuard {
620+
dst,
621+
initialized: 0,
604622
};
605-
($n: expr,) => {};
623+
unsafe {
624+
for (idx, value_ptr) in (&mut *array.as_mut_ptr()).iter_mut().enumerate() {
625+
core::ptr::write(value_ptr, cb(idx)?);
626+
guard.initialized += 1;
627+
}
628+
mem::forget(guard);
629+
Ok(array.assume_init())
630+
}
606631
}
607632

608-
impl<'a, T: Arbitrary<'a>> Arbitrary<'a> for [T; 0] {
609-
fn arbitrary(_: &mut Unstructured<'a>) -> Result<[T; 0]> {
610-
Ok([])
633+
impl<'a, T, const N: usize> Arbitrary<'a> for [T; N]
634+
where
635+
T: Arbitrary<'a>,
636+
{
637+
#[inline]
638+
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
639+
try_create_array(|_| <T as Arbitrary<'a>>::arbitrary(u))
611640
}
612641

613-
fn arbitrary_take_rest(_: Unstructured<'a>) -> Result<[T; 0]> {
614-
Ok([])
642+
#[inline]
643+
fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result<Self> {
644+
let mut array = Self::arbitrary(&mut u)?;
645+
if let Some(last) = array.last_mut() {
646+
*last = Arbitrary::arbitrary_take_rest(u)?;
647+
}
648+
Ok(array)
615649
}
616650

617651
#[inline]
618-
fn size_hint(_: usize) -> (usize, Option<usize>) {
619-
crate::size_hint::and_all(&[])
652+
fn size_hint(d: usize) -> (usize, Option<usize>) {
653+
crate::size_hint::and_all(&create_array::<_, (usize, Option<usize>), N>(|_| {
654+
<T as Arbitrary>::size_hint(d)
655+
}))
620656
}
621657
}
622658

623-
arbitrary_array! { 32, (T, a) (T, b) (T, c) (T, d) (T, e) (T, f) (T, g) (T, h)
624-
(T, i) (T, j) (T, k) (T, l) (T, m) (T, n) (T, o) (T, p)
625-
(T, q) (T, r) (T, s) (T, u) (T, v) (T, w) (T, x) (T, y)
626-
(T, z) (T, aa) (T, ab) (T, ac) (T, ad) (T, ae) (T, af)
627-
(T, ag) }
628-
629659
impl<'a> Arbitrary<'a> for &'a [u8] {
630660
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
631661
let len = u.arbitrary_len::<u8>()?;

0 commit comments

Comments
 (0)