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
274        /////////////////////////
275        ////// Conversions //////
276        /////////////////////////
277
278        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug>
279            From<Option<$index<IndexType>>> for $optional_index<IndexType>
280        {
281            fn from(index: Option<$index<IndexType>>) -> Self {
282                if let Some(index) = index {
283                    Self::new_some(index.0)
284                } else {
285                    Self::new_none()
286                }
287            }
288        }
289
290        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug>
291            From<$index<IndexType>> for $optional_index<IndexType>
292        {
293            fn from(index: $index<IndexType>) -> Self {
294                Self::new_some(index.0)
295            }
296        }
297
298        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug>
299            From<$optional_index<IndexType>> for Option<$index<IndexType>>
300        {
301            fn from(optional_index: $optional_index<IndexType>) -> Self {
302                if optional_index.is_some() {
303                    Some($index::new(optional_index.0))
304                } else {
305                    None
306                }
307            }
308        }
309
310        ////////////////////////////////////
311        ////// Conversions with usize //////
312        ////////////////////////////////////
313
314        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug + TryFrom<usize>>
315            From<usize> for $index<IndexType>
316        {
317            fn from(value: usize) -> Self {
318                Self::new(
319                    value
320                        .try_into()
321                        .ok()
322                        .expect("index conversion from usize failed"),
323                )
324            }
325        }
326
327        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug + TryFrom<usize>>
328            From<usize> for $optional_index<IndexType>
329        {
330            fn from(value: usize) -> Self {
331                Self::new_some(
332                    value
333                        .try_into()
334                        .ok()
335                        .expect("index conversion from usize failed"),
336                )
337            }
338        }
339
340        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug + TryFrom<usize>>
341            From<Option<usize>> for $optional_index<IndexType>
342        {
343            fn from(value: Option<usize>) -> Self {
344                if let Some(value) = value {
345                    Self::new_some(
346                        value
347                            .try_into()
348                            .ok()
349                            .expect("index conversion from usize failed"),
350                    )
351                } else {
352                    Self::new_none()
353                }
354            }
355        }
356
357        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug + TryInto<usize>>
358            From<$index<IndexType>> for usize
359        {
360            fn from(value: $index<IndexType>) -> Self {
361                value
362                    .0
363                    .try_into()
364                    .ok()
365                    .expect("index conversion from usize failed")
366            }
367        }
368
369        impl<IndexType: num_traits::bounds::UpperBounded + Eq + TryInto<usize>>
370            From<$optional_index<IndexType>> for Option<usize>
371        {
372            fn from(index: $optional_index<IndexType>) -> Self {
373                if index.is_some() {
374                    Some(
375                        index
376                            .0
377                            .try_into()
378                            .ok()
379                            .expect("index conversion to usize failed"),
380                    )
381                } else {
382                    None
383                }
384            }
385        }
386
387        ////////////////////////
388        ////// Formatting //////
389        ////////////////////////
390
391        impl<IndexType: std::fmt::Debug> std::fmt::Debug for $index<IndexType> {
392            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
393                write!(f, "{}({:?})", stringify!($index), self.0)
394            }
395        }
396
397        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Debug> std::fmt::Debug
398            for $optional_index<IndexType>
399        {
400            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
401                if self.is_some() {
402                    write!(f, "{}({:?})", stringify!($optional_index), self.0)
403                } else {
404                    write!(f, "{}(None)", stringify!($optional_index))
405                }
406            }
407        }
408
409        impl<IndexType: std::fmt::Display> std::fmt::Display for $index<IndexType> {
410            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
411                write!(f, "{}", self.0)
412            }
413        }
414
415        impl<IndexType: num_traits::bounds::UpperBounded + Eq + std::fmt::Display> std::fmt::Display
416            for $optional_index<IndexType>
417        {
418            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
419                if self.is_some() {
420                    write!(f, "{}", self.0)
421                } else {
422                    write!(f, "None")
423                }
424            }
425        }
426
427        //////////////////////////
428        ////// Clone + Copy //////
429        //////////////////////////
430
431        impl<IndexType: Clone> Clone for $index<IndexType> {
432            fn clone(&self) -> Self {
433                Self(self.0.clone())
434            }
435        }
436
437        impl<IndexType: Clone> Clone for $optional_index<IndexType> {
438            fn clone(&self) -> Self {
439                Self(self.0.clone())
440            }
441        }
442
443        impl<IndexType: Copy> Copy for $index<IndexType> {}
444
445        impl<IndexType: Copy> Copy for $optional_index<IndexType> {}
446
447        //////////////////////
448        ////// Equality //////
449        //////////////////////
450
451        impl<IndexType: PartialEq> PartialEq for $index<IndexType> {
452            fn eq(&self, other: &Self) -> bool {
453                self.0.eq(&other.0)
454            }
455        }
456
457        impl<IndexType: PartialEq> PartialEq for $optional_index<IndexType> {
458            fn eq(&self, other: &Self) -> bool {
459                self.0.eq(&other.0)
460            }
461        }
462
463        impl<IndexType: Eq> Eq for $index<IndexType> {}
464
465        impl<IndexType: Eq> Eq for $optional_index<IndexType> {}
466
467        //////////////////////
468        ////// Ordering //////
469        //////////////////////
470
471        impl<IndexType: PartialOrd> PartialOrd for $index<IndexType> {
472            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
473                self.0.partial_cmp(&other.0)
474            }
475        }
476
477        impl<IndexType: PartialOrd> PartialOrd for $optional_index<IndexType> {
478            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
479                self.0.partial_cmp(&other.0)
480            }
481        }
482
483        impl<IndexType: Ord> Ord for $index<IndexType> {
484            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
485                self.0.cmp(&other.0)
486            }
487        }
488
489        impl<IndexType: Ord> Ord for $optional_index<IndexType> {
490            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
491                self.0.cmp(&other.0)
492            }
493        }
494
495        /////////////////////
496        ////// Hashing //////
497        /////////////////////
498
499        impl<IndexType: std::hash::Hash> std::hash::Hash for $index<IndexType> {
500            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
501                self.0.hash(state);
502            }
503        }
504
505        impl<IndexType: std::hash::Hash> std::hash::Hash for $optional_index<IndexType> {
506            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
507                self.0.hash(state);
508            }
509        }
510    };
511}
512
513#[macro_export]
514macro_rules! implement_fixed_index {
515    ($index:ident, $optional_index:ident, $index_type:ty) => {
516        #[repr(transparent)]
517        struct $index($index_type);
518
519        #[repr(transparent)]
520        struct $optional_index($index_type);
521
522        implement_fixed_index!($index, $optional_index, $index_type, __inner__);
523    };
524
525    (pub $index:ident, pub $optional_index:ident, $index_type:ty) => {
526        pub struct $index($index_type);
527
528        pub struct $optional_index($index_type);
529
530        implement_fixed_index!($index, $optional_index, $index_type, __inner__);
531    };
532
533    (pub(crate) $index:ident, pub(crate) $optional_index:ident, $index_type:ty) => {
534        pub(crate) struct $index($index_type);
535
536        pub(crate) struct $optional_index($index_type);
537
538        implement_fixed_index!($index, $optional_index, $index_type, __inner__);
539    };
540
541    (pub(super) $index:ident, pub(super) $optional_index:ident, $index_type:ty) => {
542        pub(super) struct $index($index_type);
543
544        pub(super) struct $optional_index($index_type);
545
546        implement_fixed_index!($index, $optional_index, $index_type, __inner__);
547    };
548
549    (pub(in $index_visibility:path) $index:ident, pub(in $optional_index_visibility:path) $optional_index:ident, $index_type:ty) => {
550        pub(in $index_visibility) struct $index($index_type);
551
552        pub(in $optional_index_visibility) struct $optional_index($index_type);
553
554        implement_fixed_index!($index, $optional_index, $index_type, __inner__);
555    };
556
557    ($index:ident, $optional_index:ident, $index_type:ty, __inner__) => {
558        ///////////////////
559        ////// Index //////
560        ///////////////////
561
562        impl $index {
563            #[allow(dead_code)]
564            pub fn new(value: $index_type) -> Self {
565                assert_ne!(value, num_traits::bounds::UpperBounded::max_value());
566                Self(value)
567            }
568
569            #[allow(dead_code)]
570            pub fn from_usize(value: usize) -> Self {
571                Self::new(
572                    value
573                        .try_into()
574                        .ok()
575                        .expect("index conversion from usize failed"),
576                )
577            }
578
579            #[allow(dead_code)]
580            pub fn into_usize(self) -> usize {
581                self.0
582                    .try_into()
583                    .ok()
584                    .expect("index conversion to usize failed")
585            }
586
587            #[allow(dead_code)]
588            pub fn from_raw(value: $index_type) -> Self {
589                Self::new(value)
590            }
591
592            #[allow(dead_code)]
593            pub fn into_raw(self) -> $index_type {
594                self.0
595            }
596        }
597
598        ////////////////////////////
599        ////// Optional Index //////
600        ////////////////////////////
601
602        impl $optional_index {
603            #[allow(dead_code)]
604            pub fn new_some(value: $index_type) -> Self {
605                assert_ne!(value, num_traits::bounds::UpperBounded::max_value());
606                Self(value)
607            }
608
609            #[allow(dead_code)]
610            pub fn new_none() -> Self {
611                Self(num_traits::bounds::UpperBounded::max_value())
612            }
613
614            #[allow(dead_code)]
615            pub fn from_option(option: Option<$index>) -> Self {
616                Self::from(option)
617            }
618
619            #[allow(dead_code)]
620            pub fn into_option(self) -> Option<$index> {
621                self.into()
622            }
623
624            #[allow(dead_code)]
625            pub fn expect(self, message: &str) -> $index {
626                self.into_option().expect(message)
627            }
628
629            #[allow(dead_code)]
630            pub fn unwrap(self) -> $index {
631                self.into_option().unwrap()
632            }
633
634            #[allow(dead_code)]
635            pub fn unwrap_or(self, default: $index) -> $index {
636                self.into_option().unwrap_or(default)
637            }
638
639            #[allow(dead_code)]
640            pub fn unwrap_or_else(self, default: impl FnOnce() -> $index) -> $index {
641                self.into_option().unwrap_or_else(default)
642            }
643
644            #[allow(dead_code)]
645            pub unsafe fn unwrap_unchecked(self) -> $index {
646                unsafe { self.into_option().unwrap_unchecked() }
647            }
648
649            #[allow(dead_code)]
650            pub fn from_usize(value: usize) -> Self {
651                Self::new_some(
652                    value
653                        .try_into()
654                        .ok()
655                        .expect("index conversion from usize failed"),
656                )
657            }
658
659            #[allow(dead_code)]
660            pub fn from_option_usize(value: Option<usize>) -> Self {
661                if let Some(value) = value {
662                    Self::new_some(
663                        value
664                            .try_into()
665                            .ok()
666                            .expect("index conversion from usize failed"),
667                    )
668                } else {
669                    Self::new_none()
670                }
671            }
672
673            #[allow(dead_code)]
674            pub fn into_usize(self) -> Option<usize> {
675                if self.is_some() {
676                    Some(
677                        self.0
678                            .try_into()
679                            .ok()
680                            .expect("index conversion to usize failed"),
681                    )
682                } else {
683                    None
684                }
685            }
686
687            #[allow(dead_code)]
688            pub fn from_raw(value: Option<$index_type>) -> Self {
689                if let Some(value) = value {
690                    Self::new_some(value)
691                } else {
692                    Self::new_none()
693                }
694            }
695
696            #[allow(dead_code)]
697            pub fn into_raw(self) -> Option<$index_type> {
698                if self.is_some() { Some(self.0) } else { None }
699            }
700
701            #[allow(dead_code)]
702            pub fn is_some(&self) -> bool {
703                self.0 != num_traits::bounds::UpperBounded::max_value()
704            }
705
706            #[allow(dead_code)]
707            pub fn is_none(&self) -> bool {
708                self.0 == num_traits::bounds::UpperBounded::max_value()
709            }
710        }
711
712        /////////////////////////
713        ////// Conversions //////
714        /////////////////////////
715
716        impl From<Option<$index>> for $optional_index {
717            fn from(index: Option<$index>) -> Self {
718                if let Some(index) = index {
719                    Self::new_some(index.0)
720                } else {
721                    Self::new_none()
722                }
723            }
724        }
725
726        impl From<$index> for $optional_index {
727            fn from(index: $index) -> Self {
728                Self::new_some(index.0)
729            }
730        }
731
732        impl From<$optional_index> for Option<$index> {
733            fn from(optional_index: $optional_index) -> Self {
734                if optional_index.is_some() {
735                    Some($index::new(optional_index.0))
736                } else {
737                    None
738                }
739            }
740        }
741
742        ////////////////////////////////////
743        ////// Conversions with usize //////
744        ////////////////////////////////////
745
746        impl From<usize> for $index {
747            fn from(value: usize) -> Self {
748                Self::new(
749                    value
750                        .try_into()
751                        .ok()
752                        .expect("index conversion from usize failed"),
753                )
754            }
755        }
756
757        impl From<usize> for $optional_index {
758            fn from(value: usize) -> Self {
759                Self::new_some(
760                    value
761                        .try_into()
762                        .ok()
763                        .expect("index conversion from usize failed"),
764                )
765            }
766        }
767
768        impl From<Option<usize>> for $optional_index {
769            fn from(value: Option<usize>) -> Self {
770                if let Some(value) = value {
771                    Self::new_some(
772                        value
773                            .try_into()
774                            .ok()
775                            .expect("index conversion from usize failed"),
776                    )
777                } else {
778                    Self::new_none()
779                }
780            }
781        }
782
783        impl From<$index> for usize {
784            fn from(index: $index) -> Self {
785                index
786                    .0
787                    .try_into()
788                    .ok()
789                    .expect("index conversion to usize failed")
790            }
791        }
792
793        impl From<$optional_index> for Option<usize> {
794            fn from(index: $optional_index) -> Self {
795                if index.is_some() {
796                    Some(
797                        index
798                            .0
799                            .try_into()
800                            .ok()
801                            .expect("index conversion to usize failed"),
802                    )
803                } else {
804                    None
805                }
806            }
807        }
808
809        ////////////////////////
810        ////// Formatting //////
811        ////////////////////////
812
813        impl std::fmt::Debug for $index {
814            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
815                write!(f, "{}({:?})", stringify!($index), self.0)
816            }
817        }
818
819        impl std::fmt::Debug for $optional_index {
820            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
821                if self.is_some() {
822                    write!(f, "{}({:?})", stringify!($optional_index), self.0)
823                } else {
824                    write!(f, "{}(None)", stringify!($optional_index))
825                }
826            }
827        }
828
829        impl std::fmt::Display for $index {
830            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
831                write!(f, "{}", self.0)
832            }
833        }
834
835        impl std::fmt::Display for $optional_index {
836            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
837                if self.is_some() {
838                    write!(f, "{}", self.0)
839                } else {
840                    write!(f, "None")
841                }
842            }
843        }
844
845        //////////////////////////
846        ////// Clone + Copy //////
847        //////////////////////////
848
849        impl Clone for $index {
850            fn clone(&self) -> Self {
851                *self
852            }
853        }
854
855        impl Clone for $optional_index {
856            fn clone(&self) -> Self {
857                *self
858            }
859        }
860
861        impl Copy for $index {}
862
863        impl Copy for $optional_index {}
864
865        //////////////////////
866        ////// Equality //////
867        //////////////////////
868
869        impl PartialEq for $index {
870            fn eq(&self, other: &Self) -> bool {
871                self.0.eq(&other.0)
872            }
873        }
874
875        impl PartialEq for $optional_index {
876            fn eq(&self, other: &Self) -> bool {
877                self.0.eq(&other.0)
878            }
879        }
880
881        impl Eq for $index {}
882
883        impl Eq for $optional_index {}
884
885        //////////////////////
886        ////// Ordering //////
887        //////////////////////
888
889        impl PartialOrd for $index {
890            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
891                Some(self.cmp(other))
892            }
893        }
894
895        impl PartialOrd for $optional_index {
896            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
897                Some(self.cmp(other))
898            }
899        }
900
901        impl Ord for $index {
902            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
903                self.0.cmp(&other.0)
904            }
905        }
906
907        impl Ord for $optional_index {
908            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
909                self.0.cmp(&other.0)
910            }
911        }
912
913        /////////////////////
914        ////// Hashing //////
915        /////////////////////
916
917        impl std::hash::Hash for $index {
918            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
919                self.0.hash(state);
920            }
921        }
922
923        impl std::hash::Hash for $optional_index {
924            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
925                self.0.hash(state);
926            }
927        }
928    };
929}