1use std::{mem::ManuallyDrop, ops::{Deref, DerefMut}};
42
43pub struct ConstOption<T, const IS_SOME: bool>(ConstOptionInner<T, IS_SOME>);
57
58union ConstOptionInner<T, const IS_SOME: bool> {
59 none: (),
60 some: ManuallyDrop<T>,
61}
62
63impl<T> ConstOption<T, false> {
64 pub fn new() -> Self {
65 ConstOption(ConstOptionInner { none: () })
66 }
67}
68
69impl<T> ConstOption<T, true> {
70 pub fn new(val: T) -> Self {
71 ConstOption(ConstOptionInner { some: ManuallyDrop::new(val) })
72 }
73
74 pub fn into_inner(mut self) -> T {
75 unsafe { ManuallyDrop::take(&mut self.0.some) }
76 }
77}
78
79impl<T, const IS_SOME: bool> Drop for ConstOption<T, IS_SOME> {
80 fn drop(&mut self) {
81 unsafe {
82 if IS_SOME {
83 drop(ManuallyDrop::take(&mut self.0.some))
84 }
85 }
86 }
87}
88
89impl<T> AsRef<T> for ConstOption<T, true> {
90 fn as_ref(&self) -> &T {
91 unsafe { &self.0.some }
92 }
93}
94
95impl<T> AsMut<T> for ConstOption<T, true> {
96 fn as_mut(&mut self) -> &mut T {
97 unsafe { &mut self.0.some }
98 }
99}
100
101impl<T> Deref for ConstOption<T, true> {
102 type Target = T;
103
104 fn deref(&self) -> &Self::Target {
105 self.as_ref()
106 }
107}
108
109impl<T> DerefMut for ConstOption<T, true> {
110 fn deref_mut(&mut self) -> &mut Self::Target {
111 self.as_mut()
112 }
113}
114
115pub struct ConstEither<L, R, const IS_RIGHT: bool>(ConstEitherInner<L, R, IS_RIGHT>);
146
147union ConstEitherInner<L, R, const IS_RIGHT: bool> {
148 left: ManuallyDrop<L>,
149 right: ManuallyDrop<R>,
150}
151
152
153impl<L, R> ConstEither<L, R, false> {
154 pub fn new(left: L) -> Self {
155 ConstEither(ConstEitherInner { left: ManuallyDrop::new(left) })
156 }
157
158 pub fn into_inner(mut self) -> L {
159 unsafe { ManuallyDrop::take(&mut self.0.left) }
160 }
161
162 pub fn flip(self) -> ConstEither<R, L, true> {
163 let val = self.into_inner();
164 ConstEither::<R, L, true>::new(val)
165 }
166}
167
168impl<L, R> ConstEither<L, R, true> {
169 pub fn new(right: R) -> Self {
170 ConstEither(ConstEitherInner { right: ManuallyDrop::new(right) })
171 }
172
173 pub fn into_inner(mut self) -> R {
174 unsafe { ManuallyDrop::take(&mut self.0.right) }
175 }
176
177 pub fn flip(self) -> ConstEither<R, L, false> {
178 let val = self.into_inner();
179 ConstEither::<R, L, false>::new(val)
180 }
181}
182
183impl<L, R> AsRef<L> for ConstEither<L, R, false> {
184 fn as_ref(&self) -> &L {
185 unsafe { &self.0.left }
186 }
187}
188
189impl<L, R> AsRef<R> for ConstEither<L, R, true> {
190 fn as_ref(&self) -> &R {
191 unsafe { &self.0.right }
192 }
193}
194
195impl<L, R> AsMut<L> for ConstEither<L, R, false> {
196 fn as_mut(&mut self) -> &mut L {
197 unsafe { &mut self.0.left }
198 }
199}
200
201impl<L, R> AsMut<R> for ConstEither<L, R, true> {
202 fn as_mut(&mut self) -> &mut R {
203 unsafe { &mut self.0.right }
204 }
205}
206
207impl<L, R> Deref for ConstEither<L, R, false> {
208 type Target = L;
209
210 fn deref(&self) -> &Self::Target {
211 self.as_ref()
212 }
213}
214
215impl<L, R> Deref for ConstEither<L, R, true> {
216 type Target = R;
217
218 fn deref(&self) -> &Self::Target {
219 self.as_ref()
220 }
221}
222
223impl<L, R> DerefMut for ConstEither<L, R, false> {
224 fn deref_mut(&mut self) -> &mut Self::Target {
225 self.as_mut()
226 }
227}
228
229impl<L, R> DerefMut for ConstEither<L, R, true> {
230 fn deref_mut(&mut self) -> &mut Self::Target {
231 self.as_mut()
232 }
233}
234
235impl<L, R, const IS_RIGHT: bool> Drop for ConstEither<L, R, IS_RIGHT> {
236 fn drop(&mut self) {
237 unsafe {
238 if IS_RIGHT {
239 drop(ManuallyDrop::take(&mut self.0.right));
240 } else {
241 drop(ManuallyDrop::take(&mut self.0.left));
242 }
243 }
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use std::convert::Infallible;
250
251 use super::*;
252
253 #[test]
254 fn nothing() {
255 let _none = ConstOption::<Infallible, false>::new();
256 let mut right = ConstEither::<Infallible, usize, true>::new(1234);
257
258 assert_eq!(*right, 1234);
259 *right = 456;
260 assert_eq!(right.into_inner(), 456);
261 }
262
263 #[test]
264 fn something() {
265 let some = ConstOption::<String, true>::new("Hello, world".to_string());
266 assert_eq!(*some, "Hello, world");
267 }
268}