Skip to content

Commit dc12cde

Browse files
committed
Add const-generics feature
1 parent ab4adcf commit dc12cde

File tree

1 file changed

+68
-67
lines changed

1 file changed

+68
-67
lines changed

src/lib.rs

Lines changed: 68 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -713,89 +713,90 @@ macro_rules! arbitrary_tuple {
713713
}
714714
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);
715715

716-
macro_rules! arbitrary_array {
717-
{$n:expr, ($t:ident, $a:ident) $(($ts:ident, $as:ident))*} => {
718-
arbitrary_array!{($n - 1), $(($ts, $as))*}
719-
720-
impl<T: Arbitrary> Arbitrary for [T; $n] {
721-
fn arbitrary(u: &mut Unstructured<'_>) -> Result<[T; $n]> {
722-
Ok([
723-
Arbitrary::arbitrary(u)?,
724-
$(<$ts as Arbitrary>::arbitrary(u)?),*
725-
])
726-
}
727-
728-
#[allow(unused_mut)]
729-
fn arbitrary_take_rest(mut u: Unstructured<'_>) -> Result<[T; $n]> {
730-
$(let $as = $ts::arbitrary(&mut u)?;)*
731-
let last = Arbitrary::arbitrary_take_rest(u)?;
732-
733-
Ok([
734-
$($as,)* last
735-
])
736-
}
716+
struct ArrayGuard<T, const N: usize> {
717+
dst: *mut T,
718+
initialized: usize,
719+
}
737720

738-
#[inline]
739-
fn size_hint(depth: usize) -> (usize, Option<usize>) {
740-
crate::size_hint::and_all(&[
741-
<$t as Arbitrary>::size_hint(depth),
742-
$( <$ts as Arbitrary>::size_hint(depth) ),*
743-
])
744-
}
721+
impl<T, const N: usize> Drop for ArrayGuard<T, N> {
722+
fn drop(&mut self) {
723+
debug_assert!(self.initialized <= N);
724+
let initialized_part = core::ptr::slice_from_raw_parts_mut(self.dst, self.initialized);
725+
unsafe {
726+
core::ptr::drop_in_place(initialized_part);
727+
}
728+
}
729+
}
745730

746-
#[allow(unused_mut)] // For the `[T; 1]` case.
747-
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
748-
let mut i = 0;
749-
let mut shrinkers = [
750-
self[i].shrink(),
751-
$({
752-
i += 1;
753-
let t: &$ts = &self[i];
754-
t.shrink()
755-
}),*
756-
];
757-
Box::new(iter::from_fn(move || {
758-
let mut i = 0;
759-
Some([
760-
shrinkers[i].next()?,
761-
$({
762-
i += 1;
763-
let t: $ts = shrinkers[i].next()?;
764-
t
765-
}),*
766-
])
767-
}))
768-
}
731+
fn create_array<F, T, const N: usize>(mut cb: F) -> [T; N]
732+
where
733+
F: FnMut(usize) -> T,
734+
{
735+
let mut array: mem::MaybeUninit<[T; N]> = mem::MaybeUninit::uninit();
736+
let mut guard: ArrayGuard<T, N> = ArrayGuard {
737+
dst: array.as_mut_ptr() as _,
738+
initialized: 0,
739+
};
740+
unsafe {
741+
for (idx, value_ptr) in (&mut *array.as_mut_ptr()).iter_mut().enumerate() {
742+
core::ptr::write(value_ptr, cb(idx));
743+
guard.initialized += 1;
769744
}
745+
mem::forget(guard);
746+
array.assume_init()
747+
}
748+
}
749+
750+
fn try_create_array<F, T, const N: usize>(mut cb: F) -> Result<[T; N]>
751+
where
752+
F: FnMut(usize) -> Result<T>,
753+
{
754+
let mut array: mem::MaybeUninit<[T; N]> = mem::MaybeUninit::uninit();
755+
let mut guard: ArrayGuard<T, N> = ArrayGuard {
756+
dst: array.as_mut_ptr() as _,
757+
initialized: 0,
770758
};
771-
($n: expr,) => {};
759+
unsafe {
760+
for (idx, value_ptr) in (&mut *array.as_mut_ptr()).iter_mut().enumerate() {
761+
core::ptr::write(value_ptr, cb(idx)?);
762+
guard.initialized += 1;
763+
}
764+
mem::forget(guard);
765+
Ok(array.assume_init())
766+
}
772767
}
773768

774-
impl<T: Arbitrary> Arbitrary for [T; 0] {
775-
fn arbitrary(_: &mut Unstructured<'_>) -> Result<[T; 0]> {
776-
Ok([])
769+
impl<T, const N: usize> Arbitrary for [T; N]
770+
where
771+
T: Arbitrary,
772+
{
773+
fn arbitrary(u: &mut Unstructured<'_>) -> Result<[T; N]> {
774+
try_create_array(|_| <T as Arbitrary>::arbitrary(u))
777775
}
778776

779-
fn arbitrary_take_rest(_: Unstructured<'_>) -> Result<[T; 0]> {
780-
Ok([])
777+
fn arbitrary_take_rest(mut u: Unstructured<'_>) -> Result<[T; N]> {
778+
let mut array = Self::arbitrary(&mut u)?;
779+
if let Some(last) = array.last_mut() {
780+
*last = Arbitrary::arbitrary_take_rest(u)?;
781+
}
782+
Ok(array)
781783
}
782784

783-
#[inline]
784-
fn size_hint(_: usize) -> (usize, Option<usize>) {
785-
crate::size_hint::and_all(&[])
785+
fn size_hint(d: usize) -> (usize, Option<usize>) {
786+
crate::size_hint::and_all(&create_array::<_, (usize, Option<usize>), N>(|_| {
787+
<T as Arbitrary>::size_hint(d)
788+
}))
786789
}
787790

788791
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
789-
Box::new(iter::from_fn(|| None))
792+
let mut shrinkers =
793+
create_array::<_, Box<dyn Iterator<Item = T>>, N>(|idx| self[idx].shrink());
794+
Box::new(iter::from_fn(move || {
795+
try_create_array(|idx| shrinkers[idx].next().ok_or(Error::NotEnoughData)).ok()
796+
}))
790797
}
791798
}
792799

793-
arbitrary_array! { 32, (T, a) (T, b) (T, c) (T, d) (T, e) (T, f) (T, g) (T, h)
794-
(T, i) (T, j) (T, k) (T, l) (T, m) (T, n) (T, o) (T, p)
795-
(T, q) (T, r) (T, s) (T, u) (T, v) (T, w) (T, x) (T, y)
796-
(T, z) (T, aa) (T, ab) (T, ac) (T, ad) (T, ae) (T, af)
797-
(T, ag) }
798-
799800
fn shrink_collection<'a, T, A: Arbitrary>(
800801
entries: impl Iterator<Item = T>,
801802
f: impl Fn(&T) -> Box<dyn Iterator<Item = A>>,

0 commit comments

Comments
 (0)