summaryrefslogtreecommitdiffstats
path: root/third_party/rust/cranelift-entity-0.41.0/src/packed_option.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/cranelift-entity-0.41.0/src/packed_option.rs')
-rw-r--r--third_party/rust/cranelift-entity-0.41.0/src/packed_option.rs157
1 files changed, 157 insertions, 0 deletions
diff --git a/third_party/rust/cranelift-entity-0.41.0/src/packed_option.rs b/third_party/rust/cranelift-entity-0.41.0/src/packed_option.rs
new file mode 100644
index 0000000000..0757e9e19b
--- /dev/null
+++ b/third_party/rust/cranelift-entity-0.41.0/src/packed_option.rs
@@ -0,0 +1,157 @@
+//! Compact representation of `Option<T>` for types with a reserved value.
+//!
+//! Small Cranelift types like the 32-bit entity references are often used in tables and linked
+//! lists where an `Option<T>` is needed. Unfortunately, that would double the size of the tables
+//! because `Option<T>` is twice as big as `T`.
+//!
+//! This module provides a `PackedOption<T>` for types that have a reserved value that can be used
+//! to represent `None`.
+
+use core::fmt;
+use core::mem;
+
+/// Types that have a reserved value which can't be created any other way.
+pub trait ReservedValue: Eq {
+ /// Create an instance of the reserved value.
+ fn reserved_value() -> Self;
+}
+
+/// Packed representation of `Option<T>`.
+#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
+pub struct PackedOption<T: ReservedValue>(T);
+
+impl<T: ReservedValue> PackedOption<T> {
+ /// Returns `true` if the packed option is a `None` value.
+ pub fn is_none(&self) -> bool {
+ self.0 == T::reserved_value()
+ }
+
+ /// Returns `true` if the packed option is a `Some` value.
+ pub fn is_some(&self) -> bool {
+ self.0 != T::reserved_value()
+ }
+
+ /// Expand the packed option into a normal `Option`.
+ pub fn expand(self) -> Option<T> {
+ if self.is_none() {
+ None
+ } else {
+ Some(self.0)
+ }
+ }
+
+ /// Maps a `PackedOption<T>` to `Option<U>` by applying a function to a contained value.
+ pub fn map<U, F>(self, f: F) -> Option<U>
+ where
+ F: FnOnce(T) -> U,
+ {
+ self.expand().map(f)
+ }
+
+ /// Unwrap a packed `Some` value or panic.
+ pub fn unwrap(self) -> T {
+ self.expand().unwrap()
+ }
+
+ /// Unwrap a packed `Some` value or panic.
+ pub fn expect(self, msg: &str) -> T {
+ self.expand().expect(msg)
+ }
+
+ /// Takes the value out of the packed option, leaving a `None` in its place.
+ pub fn take(&mut self) -> Option<T> {
+ mem::replace(self, None.into()).expand()
+ }
+}
+
+impl<T: ReservedValue> Default for PackedOption<T> {
+ /// Create a default packed option representing `None`.
+ fn default() -> Self {
+ PackedOption(T::reserved_value())
+ }
+}
+
+impl<T: ReservedValue> From<T> for PackedOption<T> {
+ /// Convert `t` into a packed `Some(x)`.
+ fn from(t: T) -> Self {
+ debug_assert!(
+ t != T::reserved_value(),
+ "Can't make a PackedOption from the reserved value."
+ );
+ PackedOption(t)
+ }
+}
+
+impl<T: ReservedValue> From<Option<T>> for PackedOption<T> {
+ /// Convert an option into its packed equivalent.
+ fn from(opt: Option<T>) -> Self {
+ match opt {
+ None => Self::default(),
+ Some(t) => t.into(),
+ }
+ }
+}
+
+impl<T: ReservedValue> Into<Option<T>> for PackedOption<T> {
+ fn into(self) -> Option<T> {
+ self.expand()
+ }
+}
+
+impl<T> fmt::Debug for PackedOption<T>
+where
+ T: ReservedValue + fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if self.is_none() {
+ write!(f, "None")
+ } else {
+ write!(f, "Some({:?})", self.0)
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ // Dummy entity class, with no Copy or Clone.
+ #[derive(Debug, PartialEq, Eq)]
+ struct NoC(u32);
+
+ impl ReservedValue for NoC {
+ fn reserved_value() -> Self {
+ NoC(13)
+ }
+ }
+
+ #[test]
+ fn moves() {
+ let x = NoC(3);
+ let somex: PackedOption<NoC> = x.into();
+ assert!(!somex.is_none());
+ assert_eq!(somex.expand(), Some(NoC(3)));
+
+ let none: PackedOption<NoC> = None.into();
+ assert!(none.is_none());
+ assert_eq!(none.expand(), None);
+ }
+
+ // Dummy entity class, with Copy.
+ #[derive(Clone, Copy, Debug, PartialEq, Eq)]
+ struct Ent(u32);
+
+ impl ReservedValue for Ent {
+ fn reserved_value() -> Self {
+ Ent(13)
+ }
+ }
+
+ #[test]
+ fn copies() {
+ let x = Ent(2);
+ let some: PackedOption<Ent> = x.into();
+ assert_eq!(some.expand(), x.into());
+ assert_eq!(some, x.into());
+ }
+}