Skip to main content

optional_numeric_index/
lib.rs

1#[cfg(test)]
2mod tests;
3
4#[macro_export]
5macro_rules! implement_generic_index {
6    ($index:ident, $optional_index:ident) => {
7        #[cfg_attr(
8            feature = "zerocopy",
9            derive(
10                zerocopy::FromBytes,
11                zerocopy::IntoBytes,
12                zerocopy::KnownLayout,
13                zerocopy::Immutable,
14                zerocopy::Unaligned,
15            )
16        )]
17        #[repr(transparent)]
18        struct $index<IndexType>(IndexType);
19
20        #[cfg_attr(
21            feature = "zerocopy",
22            derive(
23                zerocopy::FromBytes,
24                zerocopy::IntoBytes,
25                zerocopy::KnownLayout,
26                zerocopy::Immutable,
27                zerocopy::Unaligned,
28            )
29        )]
30        #[repr(transparent)]
31        struct $optional_index<IndexType>(IndexType);
32
33        implement_generic_index!($index, $optional_index, __inner__);
34    };
35
36    (pub $index:ident, pub $optional_index:ident) => {
37        #[cfg_attr(
38            feature = "zerocopy",
39            derive(
40                zerocopy::FromBytes,
41                zerocopy::IntoBytes,
42                zerocopy::KnownLayout,
43                zerocopy::Immutable,
44                zerocopy::Unaligned,
45            )
46        )]
47        #[repr(transparent)]
48        pub struct $index<IndexType>(IndexType);
49
50        #[cfg_attr(
51            feature = "zerocopy",
52            derive(
53                zerocopy::FromBytes,
54                zerocopy::IntoBytes,
55                zerocopy::KnownLayout,
56                zerocopy::Immutable,
57                zerocopy::Unaligned,
58            )
59        )]
60        #[repr(transparent)]
61        pub struct $optional_index<IndexType>(IndexType);
62
63        implement_generic_index!($index, $optional_index, __inner__);
64    };
65
66    (pub(crate) $index:ident, pub(crate) $optional_index:ident) => {
67        #[cfg_attr(
68            feature = "zerocopy",
69            derive(
70                zerocopy::FromBytes,
71                zerocopy::IntoBytes,
72                zerocopy::KnownLayout,
73                zerocopy::Immutable,
74                zerocopy::Unaligned,
75            )
76        )]
77        #[repr(transparent)]
78        pub(crate) struct $index<IndexType>(IndexType);
79
80        #[cfg_attr(
81            feature = "zerocopy",
82            derive(
83                zerocopy::FromBytes,
84                zerocopy::IntoBytes,
85                zerocopy::KnownLayout,
86                zerocopy::Immutable,
87                zerocopy::Unaligned,
88            )
89        )]
90        #[repr(transparent)]
91        pub(crate) struct $optional_index<IndexType>(IndexType);
92
93        implement_generic_index!($index, $optional_index, __inner__);
94    };
95
96    (pub(super) $index:ident, pub(super) $optional_index:ident) => {
97        #[cfg_attr(
98            feature = "zerocopy",
99            derive(
100                zerocopy::FromBytes,
101                zerocopy::IntoBytes,
102                zerocopy::KnownLayout,
103                zerocopy::Immutable,
104                zerocopy::Unaligned,
105            )
106        )]
107        #[repr(transparent)]
108        pub(super) struct $index<IndexType>(IndexType);
109
110        #[cfg_attr(
111            feature = "zerocopy",
112            derive(
113                zerocopy::FromBytes,
114                zerocopy::IntoBytes,
115                zerocopy::KnownLayout,
116                zerocopy::Immutable,
117                zerocopy::Unaligned,
118            )
119        )]
120        #[repr(transparent)]
121        pub(super) struct $optional_index<IndexType>(IndexType);
122
123        implement_generic_index!($index, $optional_index, __inner__);
124    };
125
126    (pub(in $index_visibility:path) $index:ident, pub(in $optional_index_visibility:path) $optional_index:ident) => {
127        #[cfg_attr(
128            feature = "zerocopy",
129            derive(
130                zerocopy::FromBytes,
131                zerocopy::IntoBytes,
132                zerocopy::KnownLayout,
133                zerocopy::Immutable,
134                zerocopy::Unaligned,
135            )
136        )]
137        #[repr(transparent)]
138        pub(in $index_visibility) struct $index<IndexType>(IndexType);
139
140        #[cfg_attr(
141            feature = "zerocopy",
142            derive(
143                zerocopy::FromBytes,
144                zerocopy::IntoBytes,
145                zerocopy::KnownLayout,
146                zerocopy::Immutable,
147                zerocopy::Unaligned,
148            )
149        )]
150        #[repr(transparent)]
151        pub(in $optional_index_visibility) struct $optional_index<IndexType>(IndexType);
152
153        implement_generic_index!($index, $optional_index, __inner__);
154    };
155
156    ($index:ident, $optional_index:ident, __inner__) => {
157        ///////////////////
158        ////// Index //////
159        ///////////////////
160
161        impl<IndexType> $index<IndexType> {
162            #[allow(dead_code)]
163            pub fn new(value: IndexType) -> Self
164            where
165                IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug,
166            {
167                assert_ne!(value, IndexType::max_value());
168                Self(value)
169            }
170
171            #[allow(dead_code)]
172            pub fn from_usize(value: usize) -> Self
173            where
174                IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug + TryFrom<usize>,
175            {
176                Self::new(
177                    value
178                        .try_into()
179                        .ok()
180                        .expect("index conversion from usize failed"),
181                )
182            }
183
184            #[allow(dead_code)]
185            pub fn into_usize(self) -> usize
186            where
187                IndexType: TryInto<usize>,
188            {
189                self.0
190                    .try_into()
191                    .ok()
192                    .expect("index conversion to usize failed")
193            }
194
195            #[allow(dead_code)]
196            pub fn from_raw(value: IndexType) -> Self
197            where
198                IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug,
199            {
200                Self::new(value)
201            }
202
203            #[allow(dead_code)]
204            pub fn into_raw(self) -> IndexType {
205                self.0
206            }
207        }
208
209        ////////////////////////////
210        ////// Optional Index //////
211        ////////////////////////////
212
213        impl<IndexType> $optional_index<IndexType> {
214            #[allow(dead_code)]
215            pub fn new_some(value: IndexType) -> Self
216            where
217                IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug,
218            {
219                assert_ne!(value, IndexType::max_value());
220                Self(value)
221            }
222
223            #[allow(dead_code)]
224            pub fn new_none() -> Self
225            where
226                IndexType: num_traits::bounds::UpperBounded,
227            {
228                Self(IndexType::max_value())
229            }
230
231            #[allow(dead_code)]
232            pub fn from_option(option: Option<$index<IndexType>>) -> Self
233            where
234                IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug,
235            {
236                Self::from(option)
237            }
238
239            #[allow(dead_code)]
240            pub fn into_option(self) -> Option<$index<IndexType>>
241            where
242                IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug,
243            {
244                self.into()
245            }
246
247            #[allow(dead_code)]
248            pub fn expect(self, message: &str) -> $index<IndexType>
249            where
250                IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug,
251            {
252                self.into_option().expect(message)
253            }
254
255            #[allow(dead_code)]
256            pub fn unwrap(self) -> $index<IndexType>
257            where
258                IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug,
259            {
260                self.into_option().unwrap()
261            }
262
263            #[allow(dead_code)]
264            pub fn unwrap_or(self, default: $index<IndexType>) -> $index<IndexType>
265            where
266                IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug,
267            {
268                self.into_option().unwrap_or(default)
269            }
270
271            #[allow(dead_code)]
272            pub fn unwrap_or_else(
273                self,
274                default: impl FnOnce() -> $index<IndexType>,
275            ) -> $index<IndexType>
276            where
277                IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug,
278            {
279                self.into_option().unwrap_or_else(default)
280            }
281
282            #[allow(dead_code)]
283            pub unsafe fn unwrap_unchecked(self) -> $index<IndexType>
284            where
285                IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug,
286            {
287                unsafe { self.into_option().unwrap_unchecked() }
288            }
289
290            #[allow(dead_code)]
291            pub fn from_usize(value: usize) -> Self
292            where
293                IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug + TryFrom<usize>,
294            {
295                Self::new_some(
296                    value
297                        .try_into()
298                        .ok()
299                        .expect("index conversion from usize failed"),
300                )
301            }
302
303            #[allow(dead_code)]
304            pub fn from_option_usize(value: Option<usize>) -> Self
305            where
306                IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug + TryFrom<usize>,
307            {
308                if let Some(value) = value {
309                    Self::new_some(
310                        value
311                            .try_into()
312                            .ok()
313                            .expect("index conversion from usize failed"),
314                    )
315                } else {
316                    Self::new_none()
317                }
318            }
319
320            #[allow(dead_code)]
321            pub fn into_usize(self) -> Option<usize>
322            where
323                IndexType: num_traits::bounds::UpperBounded + Eq + TryInto<usize>,
324            {
325                if self.is_some() {
326                    Some(
327                        self.0
328                            .try_into()
329                            .ok()
330                            .expect("index conversion to usize failed"),
331                    )
332                } else {
333                    None
334                }
335            }
336
337            #[allow(dead_code)]
338            pub fn from_raw(value: Option<IndexType>) -> Self
339            where
340                IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug,
341            {
342                if let Some(value) = value {
343                    Self::new_some(value)
344                } else {
345                    Self::new_none()
346                }
347            }
348
349            #[allow(dead_code)]
350            pub fn into_raw(self) -> Option<IndexType>
351            where
352                IndexType: num_traits::bounds::UpperBounded + Eq,
353            {
354                if self.is_some() { Some(self.0) } else { None }
355            }
356
357            #[allow(dead_code)]
358            pub fn is_some(&self) -> bool
359            where
360                IndexType: num_traits::bounds::UpperBounded + Eq,
361            {
362                self.0 != IndexType::max_value()
363            }
364
365            #[allow(dead_code)]
366            pub fn is_none(&self) -> bool
367            where
368                IndexType: num_traits::bounds::UpperBounded + Eq,
369            {
370                self.0 == IndexType::max_value()
371            }
372        }
373
374        /////////////////////////
375        ////// Conversions //////
376        /////////////////////////
377
378        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug>
379            From<Option<$index<IndexType>>> for $optional_index<IndexType>
380        {
381            fn from(index: Option<$index<IndexType>>) -> Self {
382                if let Some(index) = index {
383                    Self::new_some(index.0)
384                } else {
385                    Self::new_none()
386                }
387            }
388        }
389
390        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug>
391            From<$index<IndexType>> for $optional_index<IndexType>
392        {
393            fn from(index: $index<IndexType>) -> Self {
394                Self::new_some(index.0)
395            }
396        }
397
398        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug>
399            From<$optional_index<IndexType>> for Option<$index<IndexType>>
400        {
401            fn from(optional_index: $optional_index<IndexType>) -> Self {
402                if optional_index.is_some() {
403                    Some($index::new(optional_index.0))
404                } else {
405                    None
406                }
407            }
408        }
409
410        ////////////////////////////////////
411        ////// Conversions with usize //////
412        ////////////////////////////////////
413
414        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug + TryFrom<usize>>
415            From<usize> for $index<IndexType>
416        {
417            fn from(value: usize) -> Self {
418                Self::new(
419                    value
420                        .try_into()
421                        .ok()
422                        .expect("index conversion from usize failed"),
423                )
424            }
425        }
426
427        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug + TryFrom<usize>>
428            From<usize> for $optional_index<IndexType>
429        {
430            fn from(value: usize) -> Self {
431                Self::new_some(
432                    value
433                        .try_into()
434                        .ok()
435                        .expect("index conversion from usize failed"),
436                )
437            }
438        }
439
440        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug + TryFrom<usize>>
441            From<Option<usize>> for $optional_index<IndexType>
442        {
443            fn from(value: Option<usize>) -> Self {
444                if let Some(value) = value {
445                    Self::new_some(
446                        value
447                            .try_into()
448                            .ok()
449                            .expect("index conversion from usize failed"),
450                    )
451                } else {
452                    Self::new_none()
453                }
454            }
455        }
456
457        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug + TryInto<usize>>
458            From<$index<IndexType>> for usize
459        {
460            fn from(value: $index<IndexType>) -> Self {
461                value
462                    .0
463                    .try_into()
464                    .ok()
465                    .expect("index conversion from usize failed")
466            }
467        }
468
469        impl<IndexType: num_traits::bounds::UpperBounded + Eq + TryInto<usize>>
470            From<$optional_index<IndexType>> for Option<usize>
471        {
472            fn from(index: $optional_index<IndexType>) -> Self {
473                if index.is_some() {
474                    Some(
475                        index
476                            .0
477                            .try_into()
478                            .ok()
479                            .expect("index conversion to usize failed"),
480                    )
481                } else {
482                    None
483                }
484            }
485        }
486
487        ////////////////////////
488        ////// Formatting //////
489        ////////////////////////
490
491        impl<IndexType: std::fmt::Debug> std::fmt::Debug for $index<IndexType> {
492            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
493                write!(f, "{}({:?})", stringify!($index), self.0)
494            }
495        }
496
497        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug> std::fmt::Debug
498            for $optional_index<IndexType>
499        {
500            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
501                if self.is_some() {
502                    write!(f, "{}({:?})", stringify!($optional_index), self.0)
503                } else {
504                    write!(f, "{}(None)", stringify!($optional_index))
505                }
506            }
507        }
508
509        impl<IndexType: std::fmt::Display> std::fmt::Display for $index<IndexType> {
510            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
511                write!(f, "{}", self.0)
512            }
513        }
514
515        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Display> std::fmt::Display
516            for $optional_index<IndexType>
517        {
518            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
519                if self.is_some() {
520                    write!(f, "{}", self.0)
521                } else {
522                    write!(f, "None")
523                }
524            }
525        }
526
527        //////////////////////////
528        ////// Clone + Copy //////
529        //////////////////////////
530
531        impl<IndexType: Clone> Clone for $index<IndexType> {
532            fn clone(&self) -> Self {
533                Self(self.0.clone())
534            }
535        }
536
537        impl<IndexType: Clone> Clone for $optional_index<IndexType> {
538            fn clone(&self) -> Self {
539                Self(self.0.clone())
540            }
541        }
542
543        impl<IndexType: Copy> Copy for $index<IndexType> {}
544
545        impl<IndexType: Copy> Copy for $optional_index<IndexType> {}
546
547        //////////////////////
548        ////// Equality //////
549        //////////////////////
550
551        impl<IndexType: PartialEq> PartialEq for $index<IndexType> {
552            fn eq(&self, other: &Self) -> bool {
553                self.0.eq(&other.0)
554            }
555        }
556
557        impl<IndexType: PartialEq> PartialEq for $optional_index<IndexType> {
558            fn eq(&self, other: &Self) -> bool {
559                self.0.eq(&other.0)
560            }
561        }
562
563        impl<IndexType: Eq> Eq for $index<IndexType> {}
564
565        impl<IndexType: Eq> Eq for $optional_index<IndexType> {}
566
567        //////////////////////
568        ////// Ordering //////
569        //////////////////////
570
571        impl<IndexType: PartialOrd> PartialOrd for $index<IndexType> {
572            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
573                self.0.partial_cmp(&other.0)
574            }
575        }
576
577        impl<IndexType: PartialOrd> PartialOrd for $optional_index<IndexType> {
578            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
579                self.0.partial_cmp(&other.0)
580            }
581        }
582
583        impl<IndexType: Ord> Ord for $index<IndexType> {
584            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
585                self.0.cmp(&other.0)
586            }
587        }
588
589        impl<IndexType: Ord> Ord for $optional_index<IndexType> {
590            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
591                self.0.cmp(&other.0)
592            }
593        }
594
595        /////////////////////
596        ////// Hashing //////
597        /////////////////////
598
599        impl<IndexType: std::hash::Hash> std::hash::Hash for $index<IndexType> {
600            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
601                self.0.hash(state);
602            }
603        }
604
605        impl<IndexType: std::hash::Hash> std::hash::Hash for $optional_index<IndexType> {
606            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
607                self.0.hash(state);
608            }
609        }
610    };
611}
612
613#[macro_export]
614macro_rules! implement_fixed_index {
615    ($index:ident, $optional_index:ident, $index_type:ty) => {
616        #[cfg_attr(
617            feature = "zerocopy",
618            derive(
619                zerocopy::FromBytes,
620                zerocopy::IntoBytes,
621                zerocopy::KnownLayout,
622                zerocopy::Immutable,
623            )
624        )]
625        #[repr(transparent)]
626        struct $index($index_type);
627
628        #[cfg_attr(
629            feature = "zerocopy",
630            derive(
631                zerocopy::FromBytes,
632                zerocopy::IntoBytes,
633                zerocopy::KnownLayout,
634                zerocopy::Immutable,
635            )
636        )]
637        #[repr(transparent)]
638        struct $optional_index($index_type);
639
640        implement_fixed_index!($index, $optional_index, $index_type, __inner__);
641    };
642
643    (pub $index:ident, pub $optional_index:ident, $index_type:ty) => {
644        #[cfg_attr(
645            feature = "zerocopy",
646            derive(
647                zerocopy::FromBytes,
648                zerocopy::IntoBytes,
649                zerocopy::KnownLayout,
650                zerocopy::Immutable,
651            )
652        )]
653        pub struct $index($index_type);
654
655        #[cfg_attr(
656            feature = "zerocopy",
657            derive(
658                zerocopy::FromBytes,
659                zerocopy::IntoBytes,
660                zerocopy::KnownLayout,
661                zerocopy::Immutable,
662            )
663        )]
664        pub struct $optional_index($index_type);
665
666        implement_fixed_index!($index, $optional_index, $index_type, __inner__);
667    };
668
669    (pub(crate) $index:ident, pub(crate) $optional_index:ident, $index_type:ty) => {
670        #[cfg_attr(
671            feature = "zerocopy",
672            derive(
673                zerocopy::FromBytes,
674                zerocopy::IntoBytes,
675                zerocopy::KnownLayout,
676                zerocopy::Immutable,
677            )
678        )]
679        pub(crate) struct $index($index_type);
680
681        #[cfg_attr(
682            feature = "zerocopy",
683            derive(
684                zerocopy::FromBytes,
685                zerocopy::IntoBytes,
686                zerocopy::KnownLayout,
687                zerocopy::Immutable,
688            )
689        )]
690        pub(crate) struct $optional_index($index_type);
691
692        implement_fixed_index!($index, $optional_index, $index_type, __inner__);
693    };
694
695    (pub(super) $index:ident, pub(super) $optional_index:ident, $index_type:ty) => {
696        #[cfg_attr(
697            feature = "zerocopy",
698            derive(
699                zerocopy::FromBytes,
700                zerocopy::IntoBytes,
701                zerocopy::KnownLayout,
702                zerocopy::Immutable,
703            )
704        )]
705        pub(super) struct $index($index_type);
706
707        #[cfg_attr(
708            feature = "zerocopy",
709            derive(
710                zerocopy::FromBytes,
711                zerocopy::IntoBytes,
712                zerocopy::KnownLayout,
713                zerocopy::Immutable,
714            )
715        )]
716        pub(super) struct $optional_index($index_type);
717
718        implement_fixed_index!($index, $optional_index, $index_type, __inner__);
719    };
720
721    (pub(in $index_visibility:path) $index:ident, pub(in $optional_index_visibility:path) $optional_index:ident, $index_type:ty) => {
722        #[cfg_attr(
723            feature = "zerocopy",
724            derive(
725                zerocopy::FromBytes,
726                zerocopy::IntoBytes,
727                zerocopy::KnownLayout,
728                zerocopy::Immutable,
729            )
730        )]
731        pub(in $index_visibility) struct $index($index_type);
732
733        #[cfg_attr(
734            feature = "zerocopy",
735            derive(
736                zerocopy::FromBytes,
737                zerocopy::IntoBytes,
738                zerocopy::KnownLayout,
739                zerocopy::Immutable,
740            )
741        )]
742        pub(in $optional_index_visibility) struct $optional_index($index_type);
743
744        implement_fixed_index!($index, $optional_index, $index_type, __inner__);
745    };
746
747    ($index:ident, $optional_index:ident, $index_type:ty, __inner__) => {
748        ///////////////////
749        ////// Index //////
750        ///////////////////
751
752        impl $index {
753            #[allow(dead_code)]
754            pub fn new(value: $index_type) -> Self {
755                assert_ne!(value, num_traits::bounds::UpperBounded::max_value());
756                Self(value)
757            }
758
759            #[allow(dead_code)]
760            pub fn from_usize(value: usize) -> Self {
761                Self::new(
762                    value
763                        .try_into()
764                        .ok()
765                        .expect("index conversion from usize failed"),
766                )
767            }
768
769            #[allow(dead_code)]
770            pub fn into_usize(self) -> usize {
771                self.0
772                    .try_into()
773                    .ok()
774                    .expect("index conversion to usize failed")
775            }
776
777            #[allow(dead_code)]
778            pub fn from_raw(value: $index_type) -> Self {
779                Self::new(value)
780            }
781
782            #[allow(dead_code)]
783            pub fn into_raw(self) -> $index_type {
784                self.0
785            }
786        }
787
788        ////////////////////////////
789        ////// Optional Index //////
790        ////////////////////////////
791
792        impl $optional_index {
793            #[allow(dead_code)]
794            pub fn new_some(value: $index_type) -> Self {
795                assert_ne!(value, num_traits::bounds::UpperBounded::max_value());
796                Self(value)
797            }
798
799            #[allow(dead_code)]
800            pub fn new_none() -> Self {
801                Self(num_traits::bounds::UpperBounded::max_value())
802            }
803
804            #[allow(dead_code)]
805            pub fn from_option(option: Option<$index>) -> Self {
806                Self::from(option)
807            }
808
809            #[allow(dead_code)]
810            pub fn into_option(self) -> Option<$index> {
811                self.into()
812            }
813
814            #[allow(dead_code)]
815            pub fn expect(self, message: &str) -> $index {
816                self.into_option().expect(message)
817            }
818
819            #[allow(dead_code)]
820            pub fn unwrap(self) -> $index {
821                self.into_option().unwrap()
822            }
823
824            #[allow(dead_code)]
825            pub fn unwrap_or(self, default: $index) -> $index {
826                self.into_option().unwrap_or(default)
827            }
828
829            #[allow(dead_code)]
830            pub fn unwrap_or_else(self, default: impl FnOnce() -> $index) -> $index {
831                self.into_option().unwrap_or_else(default)
832            }
833
834            #[allow(dead_code)]
835            pub unsafe fn unwrap_unchecked(self) -> $index {
836                unsafe { self.into_option().unwrap_unchecked() }
837            }
838
839            #[allow(dead_code)]
840            pub fn from_usize(value: usize) -> Self {
841                Self::new_some(
842                    value
843                        .try_into()
844                        .ok()
845                        .expect("index conversion from usize failed"),
846                )
847            }
848
849            #[allow(dead_code)]
850            pub fn from_option_usize(value: Option<usize>) -> Self {
851                if let Some(value) = value {
852                    Self::new_some(
853                        value
854                            .try_into()
855                            .ok()
856                            .expect("index conversion from usize failed"),
857                    )
858                } else {
859                    Self::new_none()
860                }
861            }
862
863            #[allow(dead_code)]
864            pub fn into_usize(self) -> Option<usize> {
865                if self.is_some() {
866                    Some(
867                        self.0
868                            .try_into()
869                            .ok()
870                            .expect("index conversion to usize failed"),
871                    )
872                } else {
873                    None
874                }
875            }
876
877            #[allow(dead_code)]
878            pub fn from_raw(value: Option<$index_type>) -> Self {
879                if let Some(value) = value {
880                    Self::new_some(value)
881                } else {
882                    Self::new_none()
883                }
884            }
885
886            #[allow(dead_code)]
887            pub fn into_raw(self) -> Option<$index_type> {
888                if self.is_some() { Some(self.0) } else { None }
889            }
890
891            #[allow(dead_code)]
892            pub fn is_some(&self) -> bool {
893                self.0 != num_traits::bounds::UpperBounded::max_value()
894            }
895
896            #[allow(dead_code)]
897            pub fn is_none(&self) -> bool {
898                self.0 == num_traits::bounds::UpperBounded::max_value()
899            }
900        }
901
902        /////////////////////////
903        ////// Conversions //////
904        /////////////////////////
905
906        impl From<Option<$index>> for $optional_index {
907            fn from(index: Option<$index>) -> Self {
908                if let Some(index) = index {
909                    Self::new_some(index.0)
910                } else {
911                    Self::new_none()
912                }
913            }
914        }
915
916        impl From<$index> for $optional_index {
917            fn from(index: $index) -> Self {
918                Self::new_some(index.0)
919            }
920        }
921
922        impl From<$optional_index> for Option<$index> {
923            fn from(optional_index: $optional_index) -> Self {
924                if optional_index.is_some() {
925                    Some($index::new(optional_index.0))
926                } else {
927                    None
928                }
929            }
930        }
931
932        ////////////////////////////////////
933        ////// Conversions with usize //////
934        ////////////////////////////////////
935
936        impl From<usize> for $index {
937            fn from(value: usize) -> Self {
938                Self::new(
939                    value
940                        .try_into()
941                        .ok()
942                        .expect("index conversion from usize failed"),
943                )
944            }
945        }
946
947        impl From<usize> for $optional_index {
948            fn from(value: usize) -> Self {
949                Self::new_some(
950                    value
951                        .try_into()
952                        .ok()
953                        .expect("index conversion from usize failed"),
954                )
955            }
956        }
957
958        impl From<Option<usize>> for $optional_index {
959            fn from(value: Option<usize>) -> Self {
960                if let Some(value) = value {
961                    Self::new_some(
962                        value
963                            .try_into()
964                            .ok()
965                            .expect("index conversion from usize failed"),
966                    )
967                } else {
968                    Self::new_none()
969                }
970            }
971        }
972
973        impl From<$index> for usize {
974            fn from(index: $index) -> Self {
975                index
976                    .0
977                    .try_into()
978                    .ok()
979                    .expect("index conversion to usize failed")
980            }
981        }
982
983        impl From<$optional_index> for Option<usize> {
984            fn from(index: $optional_index) -> Self {
985                if index.is_some() {
986                    Some(
987                        index
988                            .0
989                            .try_into()
990                            .ok()
991                            .expect("index conversion to usize failed"),
992                    )
993                } else {
994                    None
995                }
996            }
997        }
998
999        ////////////////////////
1000        ////// Formatting //////
1001        ////////////////////////
1002
1003        impl std::fmt::Debug for $index {
1004            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1005                write!(f, "{}({:?})", stringify!($index), self.0)
1006            }
1007        }
1008
1009        impl std::fmt::Debug for $optional_index {
1010            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1011                if self.is_some() {
1012                    write!(f, "{}({:?})", stringify!($optional_index), self.0)
1013                } else {
1014                    write!(f, "{}(None)", stringify!($optional_index))
1015                }
1016            }
1017        }
1018
1019        impl std::fmt::Display for $index {
1020            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1021                write!(f, "{}", self.0)
1022            }
1023        }
1024
1025        impl std::fmt::Display for $optional_index {
1026            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1027                if self.is_some() {
1028                    write!(f, "{}", self.0)
1029                } else {
1030                    write!(f, "None")
1031                }
1032            }
1033        }
1034
1035        //////////////////////////
1036        ////// Clone + Copy //////
1037        //////////////////////////
1038
1039        impl Clone for $index {
1040            fn clone(&self) -> Self {
1041                *self
1042            }
1043        }
1044
1045        impl Clone for $optional_index {
1046            fn clone(&self) -> Self {
1047                *self
1048            }
1049        }
1050
1051        impl Copy for $index {}
1052
1053        impl Copy for $optional_index {}
1054
1055        //////////////////////
1056        ////// Equality //////
1057        //////////////////////
1058
1059        impl PartialEq for $index {
1060            fn eq(&self, other: &Self) -> bool {
1061                self.0.eq(&other.0)
1062            }
1063        }
1064
1065        impl PartialEq for $optional_index {
1066            fn eq(&self, other: &Self) -> bool {
1067                self.0.eq(&other.0)
1068            }
1069        }
1070
1071        impl Eq for $index {}
1072
1073        impl Eq for $optional_index {}
1074
1075        //////////////////////
1076        ////// Ordering //////
1077        //////////////////////
1078
1079        impl PartialOrd for $index {
1080            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1081                Some(self.cmp(other))
1082            }
1083        }
1084
1085        impl PartialOrd for $optional_index {
1086            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1087                Some(self.cmp(other))
1088            }
1089        }
1090
1091        impl Ord for $index {
1092            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1093                self.0.cmp(&other.0)
1094            }
1095        }
1096
1097        impl Ord for $optional_index {
1098            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1099                self.0.cmp(&other.0)
1100            }
1101        }
1102
1103        /////////////////////
1104        ////// Hashing //////
1105        /////////////////////
1106
1107        impl std::hash::Hash for $index {
1108            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1109                self.0.hash(state);
1110            }
1111        }
1112
1113        impl std::hash::Hash for $optional_index {
1114            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1115                self.0.hash(state);
1116            }
1117        }
1118    };
1119}