exhaustive_map/
finite.rs

1#[cfg(target_pointer_width = "64")]
2use std::num::{NonZeroI64, NonZeroU64};
3use std::{
4    borrow::Cow,
5    num::{
6        NonZeroI16, NonZeroI32, NonZeroI8, NonZeroIsize, NonZeroU16, NonZeroU32, NonZeroU8,
7        NonZeroUsize,
8    },
9    rc::Rc,
10    sync::Arc,
11};
12
13pub use exhaustive_map_macros::Finite;
14use exhaustive_map_macros::__impl_tuples;
15
16/// Represents a type that has a finite number of inhabitants.
17///
18/// If the number of inhabitants is more than `usize::MAX`,
19/// such as `usize`, `isize`, `u64`, `i64` and `f64`,
20/// then `Finite` should not be implemented for the type.
21///
22/// Example:
23/// ```
24/// use exhaustive_map::{Finite, FiniteExt};
25///
26/// #[derive(Finite, Debug, PartialEq)]
27/// enum Color {
28///     Red,
29///     Green,
30///     Blue,
31/// }
32///
33/// assert_eq!(Color::INHABITANTS, 3);
34/// assert_eq!(Color::from_usize(0), Some(Color::Red));
35/// assert_eq!(Color::from_usize(1), Some(Color::Green));
36/// assert_eq!(Color::from_usize(2), Some(Color::Blue));
37/// assert_eq!(Color::from_usize(3), None);
38///
39/// let all: Vec<_> = Color::iter_all().collect();
40/// assert_eq!(all, vec![Color::Red, Color::Green, Color::Blue]);
41/// ```
42pub trait Finite: Sized {
43    /// The total number of different inhabitants of the type.
44    const INHABITANTS: usize;
45
46    /// Should return a number in the range `0..INHABITANTS`.
47    #[must_use]
48    fn to_usize(&self) -> usize;
49
50    /// Should be the inverse function of `to_usize`.
51    ///
52    /// This should return `Some` if and only if `i < T::INHABITANTS`.
53    #[must_use]
54    fn from_usize(i: usize) -> Option<Self>;
55}
56
57/// An extension for [`Finite`] providing the [`iter_all`](FiniteExt::iter_all) method.
58pub trait FiniteExt: Finite {
59    /// An iterator over all inhabitants of the type, ordered by the order provided by [`Finite`].
60    fn iter_all() -> IterAll<Self> {
61        IterAll((0..Self::INHABITANTS).map(|i| {
62            Self::from_usize(i).expect("unexpected None returned from Finite::from_usize in range")
63        }))
64    }
65}
66
67impl<T: Finite> FiniteExt for T {}
68
69/// An owned iterator over all inhabitants of a type implementing [`Finite`].
70///
71/// This `struct` is created by the [`FiniteExt::iter_all`] method.
72#[must_use = "iterators are lazy and do nothing unless consumed"]
73pub struct IterAll<T>(std::iter::Map<std::ops::Range<usize>, fn(usize) -> T>);
74
75impl<T> Iterator for IterAll<T> {
76    type Item = T;
77
78    fn next(&mut self) -> Option<Self::Item> {
79        self.0.next()
80    }
81
82    fn size_hint(&self) -> (usize, Option<usize>) {
83        (self.0.len(), Some(self.0.len()))
84    }
85}
86
87impl<T> ExactSizeIterator for IterAll<T> {
88    fn len(&self) -> usize {
89        self.0.len()
90    }
91}
92
93impl<T> DoubleEndedIterator for IterAll<T> {
94    fn next_back(&mut self) -> Option<Self::Item> {
95        self.0.next_back()
96    }
97}
98
99impl<T: ?Sized> Finite for std::marker::PhantomData<T> {
100    const INHABITANTS: usize = 1;
101
102    fn to_usize(&self) -> usize {
103        0
104    }
105
106    fn from_usize(i: usize) -> Option<Self> {
107        match i {
108            0 => Some(Self),
109            _ => None,
110        }
111    }
112}
113
114impl Finite for bool {
115    const INHABITANTS: usize = 2;
116
117    fn to_usize(&self) -> usize {
118        usize::from(*self)
119    }
120
121    fn from_usize(i: usize) -> Option<Self> {
122        match i {
123            0 => Some(false),
124            1 => Some(true),
125            _ => None,
126        }
127    }
128}
129
130macro_rules! impl_uprim {
131    ($type:path) => {
132        impl Finite for $type {
133            const INHABITANTS: usize = <$type>::MAX as usize + 1;
134
135            fn to_usize(&self) -> usize {
136                *self as usize
137            }
138
139            fn from_usize(i: usize) -> Option<Self> {
140                i.try_into().ok()
141            }
142        }
143    };
144}
145
146impl_uprim!(u8);
147impl_uprim!(u16);
148#[cfg(target_pointer_width = "64")]
149impl_uprim!(u32);
150
151macro_rules! impl_iprim {
152    ($itype:path, $utype:path) => {
153        impl Finite for $itype {
154            const INHABITANTS: usize = <$utype as Finite>::INHABITANTS;
155
156            fn to_usize(&self) -> usize {
157                #[allow(clippy::cast_sign_loss)]
158                (*self as $utype).to_usize()
159            }
160
161            fn from_usize(i: usize) -> Option<Self> {
162                #[allow(clippy::cast_possible_wrap)]
163                <$utype as Finite>::from_usize(i).map(|v| v as Self)
164            }
165        }
166    };
167}
168
169impl_iprim!(i8, u8);
170impl_iprim!(i16, u16);
171#[cfg(target_pointer_width = "64")]
172impl_iprim!(i32, u32);
173
174const fn pow(a: usize, b: usize) -> usize {
175    if a <= 1 {
176        return a;
177    }
178
179    assert!(b <= u32::MAX as usize, "doesn't fit in a usize");
180    #[allow(clippy::cast_possible_truncation)]
181    let b = b as u32;
182
183    a.pow(b)
184}
185
186const fn pow_minus_one(a: usize, b: usize) -> usize {
187    assert!(a != 0, "-1 doesn't fit in a usize");
188    if a == 1 {
189        return 0;
190    }
191
192    assert!(b <= u32::MAX as usize, "doesn't fit in a usize");
193    #[allow(clippy::cast_possible_truncation)]
194    let b = b as u32;
195
196    let res = (a as u128).pow(b) - 1;
197    assert!(res <= usize::MAX as u128, "doesn't fit in a usize");
198    res as usize
199}
200
201macro_rules! impl_unonzero {
202    ($type:path) => {
203        impl Finite for $type {
204            const INHABITANTS: usize = pow_minus_one(2, std::mem::size_of::<$type>() * 8);
205
206            fn to_usize(&self) -> usize {
207                usize::try_from(self.get()).unwrap() - 1
208            }
209
210            fn from_usize(i: usize) -> Option<Self> {
211                <$type>::new((i.checked_add(1)?).try_into().ok()?)
212            }
213        }
214    };
215}
216
217impl_unonzero!(NonZeroU8);
218impl_unonzero!(NonZeroU16);
219impl_unonzero!(NonZeroU32);
220#[cfg(target_pointer_width = "64")]
221impl_unonzero!(NonZeroU64);
222impl_unonzero!(NonZeroUsize);
223
224macro_rules! impl_inonzero {
225    ($nonzero_type:path, $itype:path, $utype:path) => {
226        impl Finite for $nonzero_type {
227            const INHABITANTS: usize = pow_minus_one(2, std::mem::size_of::<$nonzero_type>() * 8);
228
229            #[allow(clippy::cast_sign_loss)]
230            fn to_usize(&self) -> usize {
231                usize::try_from(self.get() as $utype).unwrap() - 1
232            }
233
234            #[allow(clippy::cast_possible_wrap)]
235            fn from_usize(i: usize) -> Option<Self> {
236                <$nonzero_type>::new(
237                    <$utype>::try_from(i.checked_add(1)?)
238                        .map(|v| v as $itype)
239                        .ok()?,
240                )
241            }
242        }
243    };
244}
245
246impl_inonzero!(NonZeroI8, i8, u8);
247impl_inonzero!(NonZeroI16, i16, u16);
248impl_inonzero!(NonZeroI32, i32, u32);
249#[cfg(target_pointer_width = "64")]
250impl_inonzero!(NonZeroI64, i64, u64);
251impl_inonzero!(NonZeroIsize, isize, usize);
252
253const CHAR_GAP_START: usize = 0xD800;
254const CHAR_GAP_END: usize = 0xDFFF;
255const CHAR_GAP_SIZE: usize = CHAR_GAP_END - CHAR_GAP_START + 1;
256impl Finite for char {
257    const INHABITANTS: usize = char::MAX as usize + 1 - CHAR_GAP_SIZE;
258
259    fn to_usize(&self) -> usize {
260        let mut v = *self as usize;
261        if v > CHAR_GAP_END {
262            v -= CHAR_GAP_SIZE;
263        }
264        v
265    }
266
267    fn from_usize(mut i: usize) -> Option<Self> {
268        if i >= CHAR_GAP_START {
269            i = i.checked_add(CHAR_GAP_SIZE)?;
270        }
271        char::from_u32(i.try_into().ok()?)
272    }
273}
274
275#[cfg(target_pointer_width = "64")]
276impl Finite for f32 {
277    const INHABITANTS: usize = u32::INHABITANTS;
278
279    fn to_usize(&self) -> usize {
280        self.to_bits().to_usize()
281    }
282
283    fn from_usize(i: usize) -> Option<Self> {
284        u32::from_usize(i).map(Self::from_bits)
285    }
286}
287
288#[cfg(target_pointer_width = "64")]
289macro_rules! impl_from {
290    ($type:path, $from:path) => {
291        impl Finite for $type {
292            const INHABITANTS: usize = <$from as Finite>::INHABITANTS;
293
294            fn to_usize(&self) -> usize {
295                <$from>::from(*self).to_usize()
296            }
297
298            fn from_usize(i: usize) -> Option<Self> {
299                Self::try_from(<$from>::from_usize(i)?).ok()
300            }
301        }
302    };
303}
304
305#[cfg(target_pointer_width = "64")]
306impl_from!(std::net::Ipv4Addr, u32);
307
308impl<const N: usize, T: Finite> Finite for [T; N] {
309    const INHABITANTS: usize = pow(T::INHABITANTS, N);
310
311    fn to_usize(&self) -> usize {
312        let mut res = 0;
313        for v in self.iter().rev() {
314            res *= T::INHABITANTS;
315            res += v.to_usize();
316        }
317        res
318    }
319
320    fn from_usize(mut i: usize) -> Option<Self> {
321        if i >= Self::INHABITANTS {
322            None
323        } else {
324            let arr = std::array::from_fn(|_| {
325                let v = T::from_usize(i % T::INHABITANTS).unwrap();
326                i /= T::INHABITANTS;
327                v
328            });
329            Some(arr)
330        }
331    }
332}
333
334__impl_tuples!(16);
335
336macro_rules! impl_deref {
337    ($type:path) => {
338        impl<T: Finite> Finite for $type {
339            const INHABITANTS: usize = T::INHABITANTS;
340
341            fn to_usize(&self) -> usize {
342                (**self).to_usize()
343            }
344
345            fn from_usize(i: usize) -> Option<Self> {
346                Some(T::from_usize(i)?.into())
347            }
348        }
349    };
350}
351
352impl_deref!(Box<T>);
353impl_deref!(Rc<T>);
354impl_deref!(Arc<T>);
355
356impl<T: Finite + Clone> Finite for Cow<'_, T> {
357    const INHABITANTS: usize = T::INHABITANTS;
358
359    fn to_usize(&self) -> usize {
360        (**self).to_usize()
361    }
362
363    fn from_usize(i: usize) -> Option<Self> {
364        Some(Cow::Owned(T::from_usize(i)?))
365    }
366}
367
368#[derive(Finite)]
369#[__finite_foreign(std::convert::Infallible)]
370enum _Infallible {}
371
372#[derive(Finite)]
373#[__finite_foreign(std::alloc::System)]
374struct _System;
375
376#[derive(Finite)]
377#[__finite_foreign(std::marker::PhantomPinned)]
378struct _PhantomPinned;
379
380#[derive(Finite)]
381#[__finite_foreign(std::cmp::Ordering)]
382enum _Ordering {
383    Less,
384    Equal,
385    Greater,
386}
387
388#[derive(Finite)]
389#[__finite_foreign(std::net::Shutdown)]
390enum _Shutdown {
391    Read,
392    Write,
393    Both,
394}
395
396#[derive(Finite)]
397#[__finite_foreign(std::num::FpCategory)]
398enum _FpCategory {
399    Nan,
400    Infinite,
401    Zero,
402    Subnormal,
403    Normal,
404}
405
406#[derive(Finite)]
407#[__finite_foreign(std::sync::mpsc::RecvTimeoutError)]
408enum _RecvTimeoutError {
409    Timeout,
410    Disconnected,
411}
412
413#[derive(Finite)]
414#[__finite_foreign(std::sync::mpsc::TryRecvError)]
415enum _TryRecvError {
416    Empty,
417    Disconnected,
418}
419
420#[derive(Finite)]
421#[__finite_foreign(std::fmt::Alignment)]
422enum _Alignment {
423    Left,
424    Right,
425    Center,
426}
427
428#[derive(Finite)]
429#[__finite_foreign(Option)]
430enum _Option<T> {
431    None,
432    Some(T),
433}
434
435#[derive(Finite)]
436#[__finite_foreign(Result)]
437enum _Result<T, E> {
438    Ok(T),
439    Err(E),
440}
441
442#[derive(Finite)]
443#[__finite_foreign(std::task::Poll)]
444enum _Poll<T> {
445    Ready(T),
446    Pending,
447}
448
449#[derive(Finite)]
450#[__finite_foreign(std::ops::Bound)]
451enum _Bound<T> {
452    Included(T),
453    Excluded(T),
454    Unbounded,
455}
456
457#[derive(Finite)]
458#[__finite_foreign(std::ops::ControlFlow)]
459enum _ControlFlow<B, C> {
460    Continue(C),
461    Break(B),
462}
463
464#[derive(Finite)]
465#[__finite_foreign(std::ops::Range)]
466struct _Range<Idx> {
467    start: Idx,
468    end: Idx,
469}
470
471#[derive(Finite)]
472#[__finite_foreign(std::ops::RangeFrom)]
473struct _RangeFrom<Idx> {
474    start: Idx,
475}
476
477#[derive(Finite)]
478#[__finite_foreign(std::ops::RangeTo)]
479struct _RangeTo<Idx> {
480    end: Idx,
481}
482
483#[derive(Finite)]
484#[__finite_foreign(std::ops::RangeToInclusive)]
485struct _RangeToInclusive<Idx> {
486    end: Idx,
487}
488
489#[derive(Finite)]
490#[__finite_foreign(std::ops::RangeFull)]
491struct _RangeFull;
492
493#[cfg(test)]
494mod test {
495    use std::{
496        fmt::Debug,
497        marker::PhantomData,
498        num::{NonZeroI16, NonZeroI8, NonZeroU16, NonZeroU8},
499    };
500
501    use super::*;
502
503    fn test_some<T: Finite + Debug + PartialEq>(expected_elements: usize) {
504        assert_eq!(T::INHABITANTS, expected_elements);
505
506        let mut values: Vec<_> = (0..1000).collect();
507        for base in [usize::MAX, T::INHABITANTS] {
508            for offset in -10..=10 {
509                if let Some(i) = base.checked_add_signed(offset) {
510                    values.push(i);
511                }
512            }
513        }
514
515        for i in values {
516            match T::from_usize(i) {
517                None => {
518                    assert!(
519                        i >= T::INHABITANTS,
520                        "Got {i}usize -> None, but INHABITANTS={}",
521                        T::INHABITANTS
522                    );
523                }
524                Some(v) => {
525                    assert!(
526                        i < T::INHABITANTS,
527                        "Got {i}usize -> {v:?}, but INHABITANTS={}",
528                        T::INHABITANTS
529                    );
530                    let i2 = v.to_usize();
531                    assert_eq!(i2, i, "{i}usize -> {v:?} -> {i2}usize");
532                }
533            }
534        }
535    }
536
537    fn test_all<T: Finite + Debug + PartialEq>(expected_elements: usize) {
538        test_some::<T>(expected_elements);
539
540        for i in 0..T::INHABITANTS {
541            let v = T::from_usize(i).unwrap();
542            let i2 = v.to_usize();
543            assert_eq!(i2, i, "{i}usize -> {v:?} -> {i2}usize");
544        }
545
546        for k in [8, 16, 32, 64] {
547            for k in [k - 1, k, k + 1] {
548                let Some(n) = 2usize.checked_pow(k) else {
549                    continue;
550                };
551                for i in [n - 1, n, n + 1] {
552                    if i >= T::INHABITANTS {
553                        assert_eq!(
554                            T::from_usize(i),
555                            None,
556                            "expected None from T::from_usize({i})"
557                        );
558                    }
559                }
560            }
561        }
562    }
563
564    #[test]
565    fn test_infallible() {
566        test_all::<std::convert::Infallible>(0);
567    }
568
569    #[test]
570    fn test_unit() {
571        test_all::<()>(1);
572    }
573
574    #[test]
575    fn test_bool() {
576        test_all::<bool>(2);
577    }
578
579    #[test]
580    fn test_u8() {
581        test_all::<u8>(256);
582    }
583
584    #[test]
585    fn test_u16() {
586        test_all::<u16>(256 * 256);
587    }
588
589    #[test]
590    #[cfg_attr(debug_assertions, ignore = "too slow in debug build")]
591    #[cfg(target_pointer_width = "64")]
592    fn test_u32() {
593        test_all::<u32>(256 * 256 * 256 * 256);
594    }
595
596    #[test]
597    fn test_i8() {
598        test_all::<i8>(256);
599    }
600
601    #[test]
602    fn test_i16() {
603        test_all::<i16>(256 * 256);
604    }
605
606    #[test]
607    #[cfg_attr(debug_assertions, ignore = "too slow in debug build")]
608    #[cfg(target_pointer_width = "64")]
609    fn test_i32() {
610        test_all::<i32>(256 * 256 * 256 * 256);
611    }
612
613    #[test]
614    fn test_nonzero_u8() {
615        test_all::<NonZeroU8>(256 - 1);
616    }
617
618    #[test]
619    fn test_nonzero_u16() {
620        test_all::<NonZeroU16>(256 * 256 - 1);
621    }
622
623    #[test]
624    #[cfg_attr(debug_assertions, ignore = "too slow in debug build")]
625    fn test_nonzero_u32() {
626        test_all::<NonZeroU32>(usize::try_from(256u64 * 256 * 256 * 256 - 1).unwrap());
627    }
628
629    #[test]
630    #[cfg(target_pointer_width = "64")]
631    fn test_nonzero_u64() {
632        test_some::<NonZeroU64>(usize::try_from(2u128.pow(64) - 1).unwrap());
633    }
634
635    #[test]
636    fn test_nonzero_usize() {
637        test_some::<NonZeroUsize>(usize::try_from(2u128.pow(isize::BITS) - 1).unwrap());
638    }
639
640    #[test]
641    fn test_nonzero_i8() {
642        test_all::<NonZeroI8>(256 - 1);
643    }
644
645    #[test]
646    fn test_nonzero_i16() {
647        test_all::<NonZeroI16>(256 * 256 - 1);
648    }
649
650    #[test]
651    #[cfg_attr(debug_assertions, ignore = "too slow in debug build")]
652    fn test_nonzero_i32() {
653        test_all::<NonZeroI32>(usize::try_from(256u64 * 256 * 256 * 256 - 1).unwrap());
654    }
655
656    #[test]
657    #[cfg(target_pointer_width = "64")]
658    fn test_nonzero_i64() {
659        test_some::<NonZeroI64>(usize::try_from(2u128.pow(64) - 1).unwrap());
660    }
661
662    #[test]
663    fn test_nonzero_isize() {
664        test_some::<NonZeroIsize>(usize::try_from(2u128.pow(isize::BITS) - 1).unwrap());
665    }
666
667    #[test]
668    fn test_char() {
669        test_all::<char>(0x11_0000 - CHAR_GAP_SIZE);
670    }
671
672    #[test]
673    #[cfg_attr(debug_assertions, ignore = "too slow in debug build")]
674    #[cfg(target_pointer_width = "64")]
675    fn test_f32() {
676        test_all::<f32>(256usize.pow(4));
677    }
678
679    #[test]
680    fn test_u8_arr_0() {
681        test_all::<[u8; 0]>(1);
682    }
683
684    #[test]
685    fn test_u8_arr_1() {
686        test_all::<[u8; 1]>(256);
687    }
688
689    #[test]
690    fn test_u8_arr_2() {
691        test_all::<[u8; 2]>(256 * 256);
692    }
693
694    #[test]
695    fn test_unit_arr() {
696        test_all::<[(); 100]>(1);
697    }
698
699    #[test]
700    fn test_tuple_u8_bool() {
701        test_all::<(u8, bool)>(512);
702    }
703
704    #[test]
705    fn test_tuple_bool_u8() {
706        test_all::<(bool, u8)>(512);
707    }
708
709    #[test]
710    fn test_cow_arr() {
711        test_all::<Cow<[bool; 2]>>(4);
712    }
713
714    #[test]
715    fn test_tuple_and_arr_same_encoding() {
716        let i1 = [1u8, 2u8].to_usize();
717        let i2 = (1u8, 2u8).to_usize();
718        assert_eq!(i1, i2);
719    }
720
721    #[test]
722    #[cfg_attr(debug_assertions, ignore = "too slow in debug build")]
723    #[cfg(target_pointer_width = "64")]
724    fn test_ipv4_address() {
725        test_all::<std::net::Ipv4Addr>(256usize.pow(4));
726    }
727
728    #[test]
729    fn test_std_cmp_ordering() {
730        test_all::<std::cmp::Ordering>(3);
731    }
732
733    #[test]
734    fn test_derive_unit_struct() {
735        #[derive(Finite, Debug, PartialEq)]
736        struct UnitStruct;
737        test_all::<UnitStruct>(1);
738    }
739
740    #[test]
741    fn test_derive_empty_tuple_struct() {
742        #[derive(Finite, Debug, PartialEq)]
743        struct EmptyTupleStruct();
744        test_all::<EmptyTupleStruct>(1);
745    }
746
747    #[test]
748    fn test_derive_tuple_struct() {
749        #[allow(dead_code)]
750        #[derive(Finite, Debug, PartialEq)]
751        struct TupleStruct(u8, bool);
752        test_all::<TupleStruct>(256 * 2);
753    }
754
755    #[test]
756    fn test_derive_empty_named_struct() {
757        #[derive(Finite, Debug, PartialEq)]
758        struct EmptyNamedStruct {}
759        test_all::<EmptyNamedStruct>(1);
760    }
761
762    #[test]
763    fn test_derive_named_struct() {
764        #[derive(Finite, Debug, PartialEq)]
765        struct Struct {
766            _a: bool,
767            _b: u8,
768            _c: Option<bool>,
769        }
770        test_all::<Struct>(2 * 256 * 3);
771    }
772
773    #[test]
774    fn test_derive_empty_enum() {
775        #[derive(Finite, Debug, PartialEq)]
776        enum EmptyEnum {}
777        test_all::<EmptyEnum>(0);
778    }
779
780    #[test]
781    fn test_derive_simple_enum() {
782        #[derive(Finite, Debug, PartialEq)]
783        enum SimpleEnum {
784            _A,
785            _B,
786            _C,
787        }
788        test_all::<SimpleEnum>(3);
789    }
790
791    #[test]
792    fn test_tuple_enum() {
793        #[derive(Finite, Debug, PartialEq)]
794        enum TupleEnum {
795            _A(u8, bool),
796            _B(()),
797            _C(),
798        }
799        test_all::<TupleEnum>(256 * 2 + 1 + 1);
800    }
801
802    #[test]
803    fn test_derive_struct_enum() {
804        #[derive(Finite, Debug, PartialEq)]
805        enum StructEnum {
806            _A { _a: u8, _b: bool },
807            _B { _c: () },
808            _C {},
809        }
810        test_all::<StructEnum>(256 * 2 + 1 + 1);
811    }
812
813    #[test]
814    fn test_derive_mixed_enum() {
815        #[derive(Finite, Debug, PartialEq)]
816        enum MixedEnum {
817            _A,
818            _B(u8),
819            _C { _a: Option<bool>, _b: u8 },
820        }
821        test_all::<MixedEnum>(1 + 256 + 3 * 256);
822    }
823
824    #[test]
825    fn test_derive_struct_with_non_clone_field() {
826        #[derive(Finite, Debug, PartialEq)]
827        struct NonCopy(u8);
828
829        #[derive(Finite, Debug, PartialEq)]
830        struct Outer {
831            inner: NonCopy,
832        }
833
834        test_all::<Outer>(256);
835    }
836
837    #[test]
838    fn test_derive_enum_with_non_clone_field() {
839        #[derive(Finite, Debug, PartialEq)]
840        struct NonCopy(u8);
841
842        #[derive(Finite, Debug, PartialEq)]
843        enum Outer {
844            A(NonCopy),
845            B { inner: NonCopy },
846        }
847
848        test_all::<Outer>(2 * 256);
849    }
850
851    #[test]
852    fn test_derive_struct_with_names_from_implementation() {
853        #[allow(clippy::struct_excessive_bools)]
854        #[derive(Finite, Debug, PartialEq)]
855        struct Struct {
856            v: bool,
857            i: bool,
858            res: bool,
859            r#type: bool,
860        }
861
862        test_all::<Struct>(2usize.pow(4));
863    }
864
865    #[test]
866    fn test_derive_enum_with_names_from_implementation() {
867        #[derive(Finite, Debug, PartialEq)]
868        enum Enum {
869            Variant {
870                v: bool,
871                i: bool,
872                res: bool,
873                r#type: bool,
874            },
875        }
876
877        test_all::<Enum>(2usize.pow(4));
878    }
879
880    #[test]
881    fn test_derive_generic() {
882        #[derive(Finite, Debug, PartialEq)]
883        struct Generic<T> {
884            _a: Option<T>,
885        }
886        test_all::<Generic<u8>>(257);
887    }
888
889    #[test]
890    fn test_derive_generic_lifetime() {
891        #[derive(Finite, Debug, PartialEq)]
892        struct Lifetime<'a> {
893            _a: PhantomData<&'a ()>,
894        }
895        test_all::<Lifetime>(1);
896    }
897}