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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}