Skip to content

Commit 23c6602

Browse files
committed
Add const-generics feature
1 parent f3301e0 commit 23c6602

File tree

1 file changed

+65
-41
lines changed

1 file changed

+65
-41
lines changed

src/lib.rs

Lines changed: 65 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -571,61 +571,85 @@ 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+
struct ArrayGuard<T, const N: usize> {
575+
dst: *mut T,
576+
initialized: usize,
577+
}
590578

591-
Ok([
592-
$($as,)* last
593-
])
594-
}
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+
}
586+
}
587+
}
595588

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-
}
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;
603602
}
603+
mem::forget(guard);
604+
array.assume_init()
605+
}
606+
}
607+
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,
604616
};
605-
($n: expr,) => {};
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())
624+
}
606625
}
607626

608-
impl<'a, T: Arbitrary<'a>> Arbitrary<'a> for [T; 0] {
609-
fn arbitrary(_: &mut Unstructured<'a>) -> Result<[T; 0]> {
610-
Ok([])
627+
impl<'a, T, const N: usize> Arbitrary<'a> for [T; N]
628+
where
629+
T: Arbitrary<'a>,
630+
{
631+
#[inline]
632+
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
633+
try_create_array(|_| <T as Arbitrary<'a>>::arbitrary(u))
611634
}
612635

613-
fn arbitrary_take_rest(_: Unstructured<'a>) -> Result<[T; 0]> {
614-
Ok([])
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)
615643
}
616644

617645
#[inline]
618-
fn size_hint(_: usize) -> (usize, Option<usize>) {
619-
crate::size_hint::and_all(&[])
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+
}))
620650
}
621651
}
622652

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-
629653
impl<'a> Arbitrary<'a> for &'a [u8] {
630654
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
631655
let len = u.arbitrary_len::<u8>()?;

0 commit comments

Comments
 (0)