solar_data_structures/
index.rs1use std::fmt;
4
5pub use index_vec::{
6 Idx, IdxRangeBounds, IdxSliceIndex, IndexBox, IndexSlice, IndexVec, index_box, index_vec,
7};
8
9#[macro_export]
11macro_rules! newtype_index {
12 () => {};
13 ($(#[$attr:meta])* $vis:vis struct $name:ident; $($rest:tt)*) => {
14 $(#[$attr])*
15 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16 #[repr(transparent)]
17 $vis struct $name($crate::index::BaseIndex32);
18
19 impl std::fmt::Debug for $name {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 write!(f, "{}({:?})", stringify!($name), self.get())
22 }
23 }
24
25 impl $crate::index::Idx for $name {
26 #[inline(always)]
27 fn from_usize(value: usize) -> Self {
28 Self::from_usize(value)
29 }
30
31 #[inline(always)]
32 fn index(self) -> usize {
33 self.index()
34 }
35 }
36
37 impl $name {
38 $vis const MAX: Self = Self($crate::index::BaseIndex32::MAX);
40
41 #[doc = "Creates a new `"]
42 #[doc = stringify!($name)]
43 #[doc = "` from the given `value`."]
44 #[inline(always)]
49 #[must_use]
50 $vis const fn new(value: u32) -> Self {
51 Self($crate::index::BaseIndex32::new(value))
52 }
53
54 #[doc = "Creates a new `"]
55 #[doc = stringify!($name)]
56 #[doc = "` from the given `value`."]
57 #[inline(always)]
62 #[must_use]
63 $vis const unsafe fn new_unchecked(value: u32) -> Self {
64 Self($crate::index::BaseIndex32::new_unchecked(value))
65 }
66
67 #[doc = "Creates a new `"]
68 #[doc = stringify!($name)]
69 #[doc = "` from the given `value`."]
70 #[inline(always)]
73 #[must_use]
74 $vis const fn try_new(value: u32) -> Option<Self> {
75 match $crate::index::BaseIndex32::try_new(value) {
76 Some(value) => Some(Self(value)),
77 None => None,
78 }
79 }
80
81 #[doc = "Creates a new `"]
82 #[doc = stringify!($name)]
83 #[doc = "` from the given `value`."]
84 #[inline(always)]
89 #[must_use]
90 $vis const fn from_usize(value: usize) -> Self {
91 Self($crate::index::BaseIndex32::from_usize(value))
92 }
93
94 #[doc = "Creates a new `"]
95 #[doc = stringify!($name)]
96 #[doc = "` from the given `value`."]
97 #[inline(always)]
102 #[must_use]
103 $vis const unsafe fn from_usize_unchecked(value: usize) -> Self {
104 Self($crate::index::BaseIndex32::from_usize_unchecked(value))
105 }
106
107 #[doc = "Creates a new `"]
108 #[doc = stringify!($name)]
109 #[doc = "` from the given `value`."]
110 #[inline(always)]
113 #[must_use]
114 $vis const fn try_from_usize(value: usize) -> Option<Self> {
115 match $crate::index::BaseIndex32::try_from_usize(value) {
116 Some(value) => Some(Self(value)),
117 None => None,
118 }
119 }
120
121 #[inline(always)]
123 #[must_use]
124 $vis const fn get(self) -> u32 {
125 self.0.get()
126 }
127
128 #[inline(always)]
130 #[must_use]
131 $vis const fn index(self) -> usize {
132 self.0.index()
133 }
134 }
135
136 $crate::newtype_index!($($rest)*);
137 };
138}
139
140macro_rules! base_index {
142 ($(#[$attr:meta])* $name:ident($primitive:ident <= $max:literal)) => {
143 $(#[$attr])*
146 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
147 #[cfg_attr(feature = "nightly", rustc_layout_scalar_valid_range_end($max))]
148 #[cfg_attr(feature = "nightly", rustc_nonnull_optimization_guaranteed)]
149 #[cfg_attr(feature = "nightly", rustc_pass_by_value)]
150 #[repr(transparent)]
151 pub struct $name {
152 #[cfg(feature = "nightly")]
154 value: $primitive,
155 #[cfg(not(feature = "nightly"))]
156 value: std::num::NonZero<$primitive>,
157 }
158
159 impl fmt::Debug for $name {
160 #[inline]
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 self.get().fmt(f)
163 }
164 }
165
166 impl Idx for $name {
167 #[inline(always)]
168 fn from_usize(value: usize) -> Self {
169 Self::from_usize(value)
170 }
171
172 #[inline(always)]
173 fn index(self) -> usize {
174 self.index()
175 }
176 }
177
178 impl $name {
179 pub const MAX_AS: $primitive = $max;
181
182 pub const MAX: Self = Self::new(Self::MAX_AS);
184
185 #[doc = "Creates a new `"]
186 #[doc = stringify!($name)]
187 #[doc = "` from the given `value`."]
188 #[inline(always)]
193 #[must_use]
194 #[cfg_attr(debug_assertions, track_caller)]
195 pub const fn new(value: $primitive) -> Self {
196 match Self::try_new(value) {
197 Some(value) => value,
198 None => index_overflow(),
199 }
200 }
201
202 #[doc = "Creates a new `"]
203 #[doc = stringify!($name)]
204 #[doc = "` from the given `value`."]
205 #[inline(always)]
208 #[must_use]
209 pub const fn try_new(value: $primitive) -> Option<Self> {
210 if value > Self::MAX_AS {
211 None
212 } else {
213 Some(unsafe { Self::new_unchecked(value) })
215 }
216 }
217
218 #[doc = "Creates a new `"]
219 #[doc = stringify!($name)]
220 #[doc = "` from the given `value`."]
221 #[inline(always)]
226 #[must_use]
227 #[cfg_attr(debug_assertions, track_caller)]
228 pub const fn from_usize(value: usize) -> Self {
229 match Self::try_from_usize(value) {
230 Some(value) => value,
231 None => index_overflow(),
232 }
233 }
234
235 #[doc = "Creates a new `"]
236 #[doc = stringify!($name)]
237 #[doc = "` from the given `value`."]
238 #[inline(always)]
241 #[must_use]
242 pub const fn try_from_usize(value: usize) -> Option<Self> {
243 if value > Self::MAX_AS as usize {
244 None
245 } else {
246 Some(unsafe { Self::new_unchecked(value as $primitive) })
248 }
249 }
250
251 #[doc = "Creates a new `"]
252 #[doc = stringify!($name)]
253 #[doc = "` from the given `value`, without checking for overflow."]
254 #[inline(always)]
259 #[must_use]
260 pub const unsafe fn new_unchecked(value: $primitive) -> Self {
261 debug_assert!(value <= Self::MAX_AS);
262
263 #[cfg(feature = "nightly")]
265 return unsafe { std::intrinsics::transmute_unchecked(value) };
266
267 #[cfg(not(feature = "nightly"))]
268 return unsafe { Self { value: std::num::NonZero::new_unchecked(value.unchecked_add(1)) } };
269 }
270
271
272 #[doc = "Creates a new `"]
273 #[doc = stringify!($name)]
274 #[doc = "` from the given `value`, without checking for overflow."]
275 #[inline(always)]
280 #[must_use]
281 pub const unsafe fn from_usize_unchecked(value: usize) -> Self {
282 debug_assert!(value <= Self::MAX_AS as usize);
283 unsafe { Self::new_unchecked(value as $primitive) }
284 }
285
286 #[inline(always)]
288 #[must_use]
289 pub const fn get(self) -> $primitive {
290 #[cfg(feature = "nightly")]
296 return unsafe { std::intrinsics::transmute_unchecked(self) };
297
298 #[cfg(not(feature = "nightly"))]
300 return unsafe { self.value.get().unchecked_sub(1) };
301 }
302
303 #[inline(always)]
305 #[must_use]
306 pub const fn index(self) -> usize {
307 self.get() as usize
308 }
309 }
310 };
311}
312
313base_index!(BaseIndex32(u32 <= 0xFFFF_FF00));
314
315#[inline(never)]
316#[cold]
317const fn index_overflow() -> ! {
318 panic!("index overflowed")
319}
320
321#[cfg(test)]
322mod tests {
323 use super::*;
324
325 #[test]
326 fn base_index() {
327 assert_eq!(BaseIndex32::new(0).get(), 0);
328 assert_eq!(BaseIndex32::new(1).get(), 1);
329 assert_eq!(BaseIndex32::MAX.get(), BaseIndex32::MAX_AS);
330 assert_eq!(BaseIndex32::MAX.get(), 0xFFFF_FF00);
331 assert_eq!(BaseIndex32::new(0xFFFF_FF00).get(), 0xFFFF_FF00);
332 }
333}