1use std::alloc::Layout;
29
30pub trait Niche: Sized {
34 type Output;
48
49 fn none() -> Self::Output;
52
53 fn is_none(value: &Self::Output) -> bool;
55
56 fn into_some(value: Self) -> Self::Output;
59
60 fn from_some(value: Self::Output) -> Self;
63}
64
65#[repr(transparent)]
70pub struct ControlledOption<T>
71where
72 T: Niche,
73{
74 value: T::Output,
75}
76
77impl<T> ControlledOption<T>
78where
79 T: Niche,
80{
81 #[inline]
83 pub fn none() -> ControlledOption<T> {
84 let value = T::none();
85 debug_assert!(T::is_none(&value));
86 ControlledOption { value }
87 }
88
89 #[inline]
91 pub fn some(value: T) -> ControlledOption<T> {
92 let value = T::into_some(value);
93 debug_assert!(!T::is_none(&value));
94 ControlledOption { value }
95 }
96
97 #[inline]
99 pub fn is_none(&self) -> bool {
100 T::is_none(&self.value)
101 }
102
103 #[inline]
105 pub fn is_some(&self) -> bool {
106 !T::is_none(&self.value)
107 }
108
109 #[inline]
113 pub fn from_option(value: Option<T>) -> ControlledOption<T> {
114 value.into()
115 }
116
117 #[inline]
122 pub fn into_option(self) -> Option<T> {
123 self.into()
124 }
125}
126
127impl<T> Default for ControlledOption<T>
128where
129 T: Niche,
130{
131 #[inline]
132 fn default() -> ControlledOption<T> {
133 ControlledOption::none()
134 }
135}
136
137impl<T> From<T> for ControlledOption<T>
138where
139 T: Niche,
140{
141 #[inline]
142 fn from(value: T) -> ControlledOption<T> {
143 ControlledOption::some(value)
144 }
145}
146
147impl<T> From<Option<T>> for ControlledOption<T>
148where
149 T: Niche,
150{
151 #[inline]
152 fn from(value: Option<T>) -> ControlledOption<T> {
153 match value {
154 Some(value) => ControlledOption::some(value),
155 None => ControlledOption::none(),
156 }
157 }
158}
159
160impl<T> Into<Option<T>> for ControlledOption<T>
161where
162 T: Niche,
163{
164 #[inline]
165 fn into(self) -> Option<T> {
166 if T::is_none(&self.value) {
167 None
168 } else {
169 Some(T::from_some(self.value))
170 }
171 }
172}
173
174impl<T> Clone for ControlledOption<T>
179where
180 T: Niche,
181 T::Output: Clone,
182{
183 fn clone(&self) -> Self {
184 ControlledOption {
185 value: self.value.clone(),
186 }
187 }
188}
189
190impl<T> Copy for ControlledOption<T>
191where
192 T: Niche,
193 T::Output: Copy,
194{
195}
196
197impl<T> std::fmt::Debug for ControlledOption<T>
198where
199 T: std::fmt::Debug + Niche,
200 T::Output: Clone,
201{
202 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
203 if self.is_none() {
204 write!(f, "ControlledOption::None")
205 } else {
206 f.debug_tuple("ControlledOption::Some")
207 .field(&T::from_some(self.value.clone()))
208 .finish()
209 }
210 }
211}
212
213impl<T> PartialEq for ControlledOption<T>
214where
215 T: Niche,
216 T::Output: PartialEq,
217{
218 fn eq(&self, other: &Self) -> bool {
219 self.value.eq(&other.value)
220 }
221
222 fn ne(&self, other: &Self) -> bool {
223 self.value.ne(&other.value)
224 }
225}
226
227impl<T> Eq for ControlledOption<T>
228where
229 T: Niche,
230 T::Output: Eq,
231{
232}
233
234impl<T> PartialOrd for ControlledOption<T>
235where
236 T: Niche,
237 T::Output: PartialOrd,
238{
239 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
240 self.value.partial_cmp(&other.value)
241 }
242
243 fn lt(&self, other: &Self) -> bool {
244 self.value.lt(&other.value)
245 }
246
247 fn le(&self, other: &Self) -> bool {
248 self.value.le(&other.value)
249 }
250
251 fn gt(&self, other: &Self) -> bool {
252 self.value.gt(&other.value)
253 }
254
255 fn ge(&self, other: &Self) -> bool {
256 self.value.ge(&other.value)
257 }
258}
259
260impl<T> Ord for ControlledOption<T>
261where
262 T: Niche,
263 T::Output: Ord,
264{
265 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
266 self.value.cmp(&other.value)
267 }
268
269 fn max(self, other: Self) -> Self {
270 ControlledOption {
271 value: self.value.max(other.value),
272 }
273 }
274
275 fn min(self, other: Self) -> Self {
276 ControlledOption {
277 value: self.value.min(other.value),
278 }
279 }
280
281 fn clamp(self, min: Self, max: Self) -> Self {
282 ControlledOption {
283 value: self.value.clamp(min.value, max.value),
284 }
285 }
286}
287
288impl<T> std::hash::Hash for ControlledOption<T>
289where
290 T: Niche,
291 T::Output: std::hash::Hash,
292{
293 fn hash<H>(&self, state: &mut H)
294 where
295 H: std::hash::Hasher,
296 {
297 self.value.hash(state)
298 }
299}
300
301pub use controlled_option_macros::Niche;
316
317#[doc(hidden)]
318pub fn fill_struct_field_with_none<T>(field: *mut T)
319where
320 T: Niche,
321{
322 debug_assert!(Layout::new::<T>() == Layout::new::<T::Output>());
323 let repr = field as *mut T::Output;
324 unsafe { repr.write(T::none()) };
325}
326
327#[doc(hidden)]
328pub fn struct_field_is_none<T>(field: *const T) -> bool
329where
330 T: Niche,
331{
332 debug_assert!(Layout::new::<T>() == Layout::new::<T::Output>());
333 let repr = field as *const T::Output;
334 T::is_none(unsafe { &*repr })
335}
336
337impl<'a, T> Niche for &'a T {
341 type Output = *const T;
342
343 #[inline]
344 fn none() -> Self::Output {
345 std::ptr::null()
346 }
347
348 #[inline]
349 fn is_none(value: &Self::Output) -> bool {
350 value.is_null()
351 }
352
353 #[inline]
354 fn into_some(value: Self) -> Self::Output {
355 value
356 }
357
358 #[inline]
359 fn from_some(value: Self::Output) -> Self {
360 unsafe { &*value }
361 }
362}
363
364impl<'a, T> Niche for &'a mut T {
365 type Output = *mut T;
366
367 #[inline]
368 fn none() -> Self::Output {
369 std::ptr::null_mut()
370 }
371
372 #[inline]
373 fn is_none(value: &Self::Output) -> bool {
374 value.is_null()
375 }
376
377 #[inline]
378 fn into_some(value: Self) -> Self::Output {
379 value
380 }
381
382 #[inline]
383 fn from_some(value: Self::Output) -> Self {
384 unsafe { &mut *value }
385 }
386}
387
388impl Niche for std::num::NonZeroI8 {
392 type Output = i8;
393
394 #[inline]
395 fn none() -> Self::Output {
396 0
397 }
398
399 #[inline]
400 fn is_none(value: &Self::Output) -> bool {
401 *value == 0
402 }
403
404 #[inline]
405 fn into_some(value: Self) -> Self::Output {
406 value.get()
407 }
408
409 #[inline]
410 fn from_some(value: Self::Output) -> Self {
411 unsafe { Self::new_unchecked(value) }
412 }
413}
414
415impl Niche for std::num::NonZeroI16 {
416 type Output = i16;
417
418 #[inline]
419 fn none() -> Self::Output {
420 0
421 }
422
423 #[inline]
424 fn is_none(value: &Self::Output) -> bool {
425 *value == 0
426 }
427
428 #[inline]
429 fn into_some(value: Self) -> Self::Output {
430 value.get()
431 }
432
433 #[inline]
434 fn from_some(value: Self::Output) -> Self {
435 unsafe { Self::new_unchecked(value) }
436 }
437}
438
439impl Niche for std::num::NonZeroI32 {
440 type Output = i32;
441
442 #[inline]
443 fn none() -> Self::Output {
444 0
445 }
446
447 #[inline]
448 fn is_none(value: &Self::Output) -> bool {
449 *value == 0
450 }
451
452 #[inline]
453 fn into_some(value: Self) -> Self::Output {
454 value.get()
455 }
456
457 #[inline]
458 fn from_some(value: Self::Output) -> Self {
459 unsafe { Self::new_unchecked(value) }
460 }
461}
462
463impl Niche for std::num::NonZeroI64 {
464 type Output = i64;
465
466 #[inline]
467 fn none() -> Self::Output {
468 0
469 }
470
471 #[inline]
472 fn is_none(value: &Self::Output) -> bool {
473 *value == 0
474 }
475
476 #[inline]
477 fn into_some(value: Self) -> Self::Output {
478 value.get()
479 }
480
481 #[inline]
482 fn from_some(value: Self::Output) -> Self {
483 unsafe { Self::new_unchecked(value) }
484 }
485}
486
487impl Niche for std::num::NonZeroIsize {
488 type Output = isize;
489
490 #[inline]
491 fn none() -> Self::Output {
492 0
493 }
494
495 #[inline]
496 fn is_none(value: &Self::Output) -> bool {
497 *value == 0
498 }
499
500 #[inline]
501 fn into_some(value: Self) -> Self::Output {
502 value.get()
503 }
504
505 #[inline]
506 fn from_some(value: Self::Output) -> Self {
507 unsafe { Self::new_unchecked(value) }
508 }
509}
510
511impl Niche for std::num::NonZeroU8 {
512 type Output = u8;
513
514 #[inline]
515 fn none() -> Self::Output {
516 0
517 }
518
519 #[inline]
520 fn is_none(value: &Self::Output) -> bool {
521 *value == 0
522 }
523
524 #[inline]
525 fn into_some(value: Self) -> Self::Output {
526 value.get()
527 }
528
529 #[inline]
530 fn from_some(value: Self::Output) -> Self {
531 unsafe { Self::new_unchecked(value) }
532 }
533}
534
535impl Niche for std::num::NonZeroU16 {
536 type Output = u16;
537
538 #[inline]
539 fn none() -> Self::Output {
540 0
541 }
542
543 #[inline]
544 fn is_none(value: &Self::Output) -> bool {
545 *value == 0
546 }
547
548 #[inline]
549 fn into_some(value: Self) -> Self::Output {
550 value.get()
551 }
552
553 #[inline]
554 fn from_some(value: Self::Output) -> Self {
555 unsafe { Self::new_unchecked(value) }
556 }
557}
558
559impl Niche for std::num::NonZeroU32 {
560 type Output = u32;
561
562 #[inline]
563 fn none() -> Self::Output {
564 0
565 }
566
567 #[inline]
568 fn is_none(value: &Self::Output) -> bool {
569 *value == 0
570 }
571
572 #[inline]
573 fn into_some(value: Self) -> Self::Output {
574 value.get()
575 }
576
577 #[inline]
578 fn from_some(value: Self::Output) -> Self {
579 unsafe { Self::new_unchecked(value) }
580 }
581}
582
583impl Niche for std::num::NonZeroU64 {
584 type Output = u64;
585
586 #[inline]
587 fn none() -> Self::Output {
588 0
589 }
590
591 #[inline]
592 fn is_none(value: &Self::Output) -> bool {
593 *value == 0
594 }
595
596 #[inline]
597 fn into_some(value: Self) -> Self::Output {
598 value.get()
599 }
600
601 #[inline]
602 fn from_some(value: Self::Output) -> Self {
603 unsafe { Self::new_unchecked(value) }
604 }
605}
606
607impl Niche for std::num::NonZeroUsize {
608 type Output = usize;
609
610 #[inline]
611 fn none() -> Self::Output {
612 0
613 }
614
615 #[inline]
616 fn is_none(value: &Self::Output) -> bool {
617 *value == 0
618 }
619
620 #[inline]
621 fn into_some(value: Self) -> Self::Output {
622 value.get()
623 }
624
625 #[inline]
626 fn from_some(value: Self::Output) -> Self {
627 unsafe { Self::new_unchecked(value) }
628 }
629}