Skip to content

Commit 72f8f1a

Browse files
committed
Add const-generics feature
1 parent f3301e0 commit 72f8f1a

File tree

1 file changed

+61
-53
lines changed

1 file changed

+61
-53
lines changed

src/lib.rs

Lines changed: 61 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -571,74 +571,82 @@ 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)?;
590-
591-
Ok([
592-
$($as,)* last
593-
])
594-
}
595-
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-
}
603-
}
604-
};
605-
($n: expr,) => {};
574+
struct ArrayGuard<T, const N: usize> {
575+
dst: *mut T,
576+
initialized: usize,
606577
}
607578

608-
impl<'a, T: Arbitrary<'a>> Arbitrary<'a> for [T; 0] {
609-
fn arbitrary(_: &mut Unstructured<'a>) -> Result<[T; 0]> {
610-
Ok([])
579+
impl<T, const N: usize> Drop for ArrayGuard<T, N> {
580+
fn drop(&mut self) {
581+
debug_assert!(self.initialized <= N);
582+
let initialized_part = core::ptr::slice_from_raw_parts_mut(self.dst, self.initialized);
583+
unsafe {
584+
core::ptr::drop_in_place(initialized_part);
585+
}
611586
}
587+
}
612588

613-
fn arbitrary_take_rest(_: Unstructured<'a>) -> Result<[T; 0]> {
614-
Ok([])
589+
fn create_array<F, T, const N: usize>(mut cb: F) -> [T; N]
590+
where
591+
F: FnMut(usize) -> T,
592+
{
593+
let mut array: mem::MaybeUninit<[T; N]> = mem::MaybeUninit::uninit();
594+
let mut guard: ArrayGuard<T, N> = ArrayGuard {
595+
dst: array.as_mut_ptr() as _,
596+
initialized: 0,
597+
};
598+
unsafe {
599+
for (idx, value_ptr) in (&mut *array.as_mut_ptr()).iter_mut().enumerate() {
600+
core::ptr::write(value_ptr, cb(idx));
601+
guard.initialized += 1;
602+
}
603+
mem::forget(guard);
604+
array.assume_init()
615605
}
606+
}
616607

617-
#[inline]
618-
fn size_hint(_: usize) -> (usize, Option<usize>) {
619-
crate::size_hint::and_all(&[])
608+
fn try_create_array<F, T, const N: usize>(mut cb: F) -> Result<[T; N]>
609+
where
610+
F: FnMut(usize) -> Result<T>,
611+
{
612+
let mut array: mem::MaybeUninit<[T; N]> = mem::MaybeUninit::uninit();
613+
let mut guard: ArrayGuard<T, N> = ArrayGuard {
614+
dst: array.as_mut_ptr() as _,
615+
initialized: 0,
616+
};
617+
unsafe {
618+
for (idx, value_ptr) in (&mut *array.as_mut_ptr()).iter_mut().enumerate() {
619+
core::ptr::write(value_ptr, cb(idx)?);
620+
guard.initialized += 1;
621+
}
622+
mem::forget(guard);
623+
Ok(array.assume_init())
620624
}
621625
}
622626

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-
629-
impl<'a> Arbitrary<'a> for &'a [u8] {
627+
impl<'a, T, const N: usize> Arbitrary<'a> for [T; N]
628+
where
629+
T: Arbitrary<'a>
630+
{
631+
#[inline]
630632
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
631-
let len = u.arbitrary_len::<u8>()?;
632-
u.bytes(len)
633+
try_create_array(|_| <T as Arbitrary<'a>>::arbitrary(u))
633634
}
634635

635-
fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self> {
636-
Ok(u.take_rest())
636+
#[inline]
637+
fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result<Self> {
638+
let mut array = Self::arbitrary(&mut u)?;
639+
if let Some(last) = array.last_mut() {
640+
*last = Arbitrary::arbitrary_take_rest(u)?;
641+
}
642+
Ok(array)
637643
}
638644

639645
#[inline]
640-
fn size_hint(depth: usize) -> (usize, Option<usize>) {
641-
<usize as Arbitrary>::size_hint(depth)
646+
fn size_hint(d: usize) -> (usize, Option<usize>) {
647+
crate::size_hint::and_all(&create_array::<_, (usize, Option<usize>), N>(|_| {
648+
<T as Arbitrary>::size_hint(d)
649+
}))
642650
}
643651
}
644652

0 commit comments

Comments
 (0)