cranelift_entity/
packed_option.rs1use core::{fmt, mem};
11use wasmtime_core::{alloc::TryClone, error::OutOfMemory};
12
13#[cfg(feature = "enable-serde")]
14use serde_derive::{Deserialize, Serialize};
15
16pub trait ReservedValue {
18 fn reserved_value() -> Self;
20 fn is_reserved_value(&self) -> bool;
22}
23
24#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
29#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
30#[repr(transparent)]
31pub struct PackedOption<T: ReservedValue>(T);
32
33impl<T> TryClone for PackedOption<T>
34where
35 T: ReservedValue + TryClone,
36{
37 fn try_clone(&self) -> Result<Self, OutOfMemory> {
38 Ok(Self(self.0.try_clone()?))
39 }
40}
41
42impl<T: ReservedValue> PackedOption<T> {
43 pub fn is_none(&self) -> bool {
45 self.0.is_reserved_value()
46 }
47
48 pub fn is_some(&self) -> bool {
50 !self.0.is_reserved_value()
51 }
52
53 pub fn expand(self) -> Option<T> {
55 if self.is_none() { None } else { Some(self.0) }
56 }
57
58 pub fn map<U, F>(self, f: F) -> Option<U>
60 where
61 F: FnOnce(T) -> U,
62 {
63 self.expand().map(f)
64 }
65
66 #[track_caller]
68 pub fn unwrap(self) -> T {
69 self.expand().unwrap()
70 }
71
72 #[track_caller]
74 pub fn expect(self, msg: &str) -> T {
75 self.expand().expect(msg)
76 }
77
78 pub fn take(&mut self) -> Option<T> {
80 mem::replace(self, None.into()).expand()
81 }
82}
83
84impl<T: ReservedValue> Default for PackedOption<T> {
85 fn default() -> Self {
87 Self(T::reserved_value())
88 }
89}
90
91impl<T: ReservedValue> From<T> for PackedOption<T> {
92 fn from(t: T) -> Self {
94 debug_assert!(
95 !t.is_reserved_value(),
96 "Can't make a PackedOption from the reserved value."
97 );
98 Self(t)
99 }
100}
101
102impl<T: ReservedValue> From<Option<T>> for PackedOption<T> {
103 fn from(opt: Option<T>) -> Self {
105 match opt {
106 None => Self::default(),
107 Some(t) => t.into(),
108 }
109 }
110}
111
112impl<T: ReservedValue> From<PackedOption<T>> for Option<T> {
113 fn from(packed: PackedOption<T>) -> Option<T> {
114 packed.expand()
115 }
116}
117
118impl<T> fmt::Debug for PackedOption<T>
119where
120 T: ReservedValue + fmt::Debug,
121{
122 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
123 if self.is_none() {
124 write!(f, "None")
125 } else {
126 write!(f, "Some({:?})", self.0)
127 }
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[derive(Debug, PartialEq, Eq)]
137 struct NoC(u32);
138
139 impl ReservedValue for NoC {
140 fn reserved_value() -> Self {
141 NoC(13)
142 }
143
144 fn is_reserved_value(&self) -> bool {
145 self.0 == 13
146 }
147 }
148
149 #[test]
150 fn moves() {
151 let x = NoC(3);
152 let somex: PackedOption<NoC> = x.into();
153 assert!(!somex.is_none());
154 assert_eq!(somex.expand(), Some(NoC(3)));
155
156 let none: PackedOption<NoC> = None.into();
157 assert!(none.is_none());
158 assert_eq!(none.expand(), None);
159 }
160
161 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
163 struct Ent(u32);
164
165 impl ReservedValue for Ent {
166 fn reserved_value() -> Self {
167 Ent(13)
168 }
169
170 fn is_reserved_value(&self) -> bool {
171 self.0 == 13
172 }
173 }
174
175 #[test]
176 fn copies() {
177 let x = Ent(2);
178 let some: PackedOption<Ent> = x.into();
179 assert_eq!(some.expand(), x.into());
180 assert_eq!(some, x.into());
181 }
182}