static_graph/
index.rs

1// this file is copied and modified from rustc
2
3pub trait Idx: Sized + Copy + 'static {
4    fn new(idx: usize) -> Self;
5
6    fn index(self) -> usize;
7
8    fn inc_one(&mut self) -> Self {
9        let old = *self;
10        *self = self.plus(1);
11        old
12    }
13
14    fn increment_by(&mut self, amount: usize) {
15        *self = self.plus(amount);
16    }
17
18    fn plus(self, amount: usize) -> Self {
19        Self::new(self.index() + amount)
20    }
21}
22
23#[macro_export]
24macro_rules! newtype_index {
25    // ---- public rules ----
26
27    // Use default constants
28    ($(#[$attrs:meta])* $v:vis struct $name:ident { .. }) => (
29        $crate::newtype_index!(
30            // Leave out derives marker so we can use its absence to ensure it comes first
31            @attrs        [$(#[$attrs])*]
32            @type         [$name]
33            // shave off 256 indices at the end to allow space for packing these indices into enums
34            @max          [0xFFFF_FF00]
35            @vis          [$v]
36            @debug_format ["{}"]);
37    );
38
39    // Define any constants
40    ($(#[$attrs:meta])* $v:vis struct $name:ident { $($tokens:tt)+ }) => (
41        $crate::newtype_index!(
42            // Leave out derives marker so we can use its absence to ensure it comes first
43            @attrs        [$(#[$attrs])*]
44            @type         [$name]
45            // shave off 256 indices at the end to allow space for packing these indices into enums
46            @max          [0xFFFF_FF00]
47            @vis          [$v]
48            @debug_format ["{}"]
49                          $($tokens)+);
50    );
51
52    // ---- private rules ----
53
54    // Base case, user-defined constants (if any) have already been defined
55    (@derives      [$($derives:ident,)*]
56     @attrs        [$(#[$attrs:meta])*]
57     @type         [$type:ident]
58     @max          [$max:expr]
59     @vis          [$v:vis]
60     @debug_format [$debug_format:tt]) => (
61        $(#[$attrs])*
62        #[derive(Copy, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)]
63        $v struct $type {
64            private: u32
65        }
66
67        impl Clone for $type {
68            #[inline]
69            fn clone(&self) -> Self {
70                *self
71            }
72        }
73
74        impl $type {
75            /// Maximum value the index can take, as a `u32`.
76            $v const MAX_AS_U32: u32 = $max;
77
78            /// Maximum value the index can take.
79            $v const MAX: Self = Self::from_u32($max);
80
81            /// Creates a new index from a given `usize`.
82            ///
83            /// # Panics
84            ///
85            /// Will panic if `value` exceeds `MAX`.
86            #[inline]
87            $v const fn from_usize(value: usize) -> Self {
88                assert!(value <= ($max as usize));
89                // SAFETY: We just checked that `value <= max`.
90                unsafe {
91                    Self::from_u32_unchecked(value as u32)
92                }
93            }
94
95            /// Creates a new index from a given `u32`.
96            ///
97            /// # Panics
98            ///
99            /// Will panic if `value` exceeds `MAX`.
100            #[inline]
101            $v const fn from_u32(value: u32) -> Self {
102                assert!(value <= $max);
103                // SAFETY: We just checked that `value <= max`.
104                unsafe {
105                    Self::from_u32_unchecked(value)
106                }
107            }
108
109            /// Creates a new index from a given `u32`.
110            ///
111            /// # Safety
112            ///
113            /// The provided value must be less than or equal to the maximum value for the newtype.
114            /// Providing a value outside this range is undefined due to layout restrictions.
115            ///
116            /// Prefer using `from_u32`.
117            #[inline]
118            $v const unsafe fn from_u32_unchecked(value: u32) -> Self {
119                Self { private: value }
120            }
121
122            /// Extracts the value of this index as a `usize`.
123            #[inline]
124            $v const fn index(self) -> usize {
125                self.as_usize()
126            }
127
128            /// Extracts the value of this index as a `u32`.
129            #[inline]
130            $v const fn as_u32(self) -> u32 {
131                self.private
132            }
133
134            /// Extracts the value of this index as a `usize`.
135            #[inline]
136            $v const fn as_usize(self) -> usize {
137                self.as_u32() as usize
138            }
139        }
140
141        impl std::ops::Add<usize> for $type {
142            type Output = Self;
143
144            fn add(self, other: usize) -> Self {
145                Self::from_usize(self.index() + other)
146            }
147        }
148
149        impl $crate::index::Idx for $type {
150            #[inline]
151            fn new(value: usize) -> Self {
152                Self::from_usize(value)
153            }
154
155            #[inline]
156            fn index(self) -> usize {
157                self.as_usize()
158            }
159        }
160
161
162        impl From<$type> for u32 {
163            #[inline]
164            fn from(v: $type) -> u32 {
165                v.as_u32()
166            }
167        }
168
169        impl From<$type> for usize {
170            #[inline]
171            fn from(v: $type) -> usize {
172                v.as_usize()
173            }
174        }
175
176        impl From<usize> for $type {
177            #[inline]
178            fn from(value: usize) -> Self {
179                Self::from_usize(value)
180            }
181        }
182
183        impl From<u32> for $type {
184            #[inline]
185            fn from(value: u32) -> Self {
186                Self::from_u32(value)
187            }
188        }
189
190        $crate::newtype_index!(
191            @handle_debug
192            @derives      [$($derives,)*]
193            @type         [$type]
194            @debug_format [$debug_format]);
195    );
196
197    // base case for handle_debug where format is custom. No Debug implementation is emitted.
198    (@handle_debug
199     @derives      [$($_derives:ident,)*]
200     @type         [$type:ident]
201     @debug_format [custom]) => ();
202
203    // base case for handle_debug, no debug overrides found, so use default
204    (@handle_debug
205     @derives      []
206     @type         [$type:ident]
207     @debug_format [$debug_format:tt]) => (
208        impl ::std::fmt::Debug for $type {
209            fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
210                write!(fmt, $debug_format, self.as_u32())
211            }
212        }
213    );
214
215    // It's not Debug, so just pop it off the front of the derives stack and check the rest.
216    (@handle_debug
217     @derives      [$_derive:ident, $($derives:ident,)*]
218     @type         [$type:ident]
219     @debug_format [$debug_format:tt]) => (
220        $crate::newtype_index!(
221            @handle_debug
222            @derives      [$($derives,)*]
223            @type         [$type]
224            @debug_format [$debug_format]);
225    );
226
227
228
229    (@attrs        [$(#[$attrs:meta])*]
230     @type         [$type:ident]
231     @max          [$max:expr]
232     @vis          [$v:vis]
233     @debug_format [$debug_format:tt]
234                   $($tokens:tt)*) => (
235        $crate::newtype_index!(
236            @derives      []
237            @attrs        [$(#[$attrs])*]
238            @type         [$type]
239            @max          [$max]
240            @vis          [$v]
241            @debug_format [$debug_format]
242                          $($tokens)*);
243    );
244}
245
246impl Idx for usize {
247    fn new(idx: usize) -> Self {
248        idx
249    }
250
251    fn index(self) -> usize {
252        self
253    }
254}
255
256impl Idx for u32 {
257    fn new(idx: usize) -> Self {
258        idx as u32
259    }
260
261    fn index(self) -> usize {
262        self as usize
263    }
264}