summaryrefslogtreecommitdiffstats
path: root/third_party/rust/thunderdome/src/generation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/thunderdome/src/generation.rs')
-rw-r--r--third_party/rust/thunderdome/src/generation.rs61
1 files changed, 61 insertions, 0 deletions
diff --git a/third_party/rust/thunderdome/src/generation.rs b/third_party/rust/thunderdome/src/generation.rs
new file mode 100644
index 0000000000..e6982c383c
--- /dev/null
+++ b/third_party/rust/thunderdome/src/generation.rs
@@ -0,0 +1,61 @@
+use std::num::NonZeroU32;
+
+/// Tracks the generation of an entry in an arena. Encapsulates NonZeroU32 to
+/// reduce the number of redundant checks needed, as well as enforcing checked
+/// arithmetic on advancing a generation.
+///
+/// Uses NonZeroU32 to help `Index` stay the same size when put inside an
+/// `Option`.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
+#[repr(transparent)]
+pub(crate) struct Generation(NonZeroU32);
+
+impl Generation {
+ #[must_use]
+ pub(crate) fn first() -> Self {
+ // This is safe because 1 is not zero.
+ Generation(unsafe { NonZeroU32::new_unchecked(1) })
+ }
+
+ #[must_use]
+ pub(crate) fn next(self) -> Self {
+ let last_generation = self.0.get();
+ let next_generation = last_generation.checked_add(1).unwrap_or(1);
+
+ // This is safe because value that would overflow is instead made 1.
+ Generation(unsafe { NonZeroU32::new_unchecked(next_generation) })
+ }
+
+ pub(crate) fn to_u32(self) -> u32 {
+ self.0.get()
+ }
+
+ pub(crate) fn from_u32(gen: u32) -> Self {
+ Generation(NonZeroU32::new(gen).expect("generation IDs must be nonzero!"))
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::Generation;
+
+ use std::num::NonZeroU32;
+
+ #[test]
+ fn first_and_next() {
+ let first = Generation::first();
+ assert_eq!(first.0.get(), 1);
+
+ let second = first.next();
+ assert_eq!(second.0.get(), 2);
+ }
+
+ #[test]
+ fn wrap_on_overflow() {
+ let max = Generation(NonZeroU32::new(std::u32::MAX).unwrap());
+ assert_eq!(max.0.get(), std::u32::MAX);
+
+ let next = max.next();
+ assert_eq!(next.0.get(), 1);
+ }
+}