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