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