1#![doc = include_str!("../README.md")]
2
3pub trait Nullable {
5 const NULL: Self;
7
8 fn is_null(&self) -> bool;
10}
11
12impl<T> Nullable for Option<T> {
13 const NULL: Self = None;
14
15 #[inline]
16 fn is_null(&self) -> bool {
17 self.is_none()
18 }
19}
20
21impl<T> Nullable for *const T {
22 const NULL: Self = core::ptr::null();
23
24 #[inline]
25 fn is_null(&self) -> bool {
26 *self == Self::NULL
27 }
28}
29
30impl<T> Nullable for *mut T {
31 const NULL: Self = core::ptr::null_mut();
32
33 #[inline]
34 fn is_null(&self) -> bool {
35 *self == Self::NULL
36 }
37}
38
39#[cfg(feature = "nullable-core-floats")]
40impl Nullable for f32 {
41 const NULL: Self = f32::MAX;
42
43 #[inline]
44 fn is_null(&self) -> bool {
45 *self == f32::MAX
46 }
47}
48
49#[cfg(feature = "nullable-core-floats")]
50impl Nullable for f64 {
51 const NULL: Self = f64::MAX;
52
53 #[inline]
54 fn is_null(&self) -> bool {
55 *self == f64::MAX
56 }
57}
58
59#[cfg(feature = "nullable-core-ints")]
60impl Nullable for i8 {
61 const NULL: Self = i8::MAX;
62
63 #[inline]
64 fn is_null(&self) -> bool {
65 *self == i8::MAX
66 }
67}
68
69#[cfg(feature = "nullable-core-ints")]
70impl Nullable for i16 {
71 const NULL: Self = i16::MAX;
72
73 #[inline]
74 fn is_null(&self) -> bool {
75 *self == i16::MAX
76 }
77}
78
79#[cfg(feature = "nullable-core-ints")]
80impl Nullable for i32 {
81 const NULL: Self = i32::MAX;
82
83 #[inline]
84 fn is_null(&self) -> bool {
85 *self == i32::MAX
86 }
87}
88
89#[cfg(feature = "nullable-core-ints")]
90impl Nullable for i64 {
91 const NULL: Self = i64::MAX;
92
93 #[inline]
94 fn is_null(&self) -> bool {
95 *self == i64::MAX
96 }
97}
98
99#[cfg(feature = "nullable-core-ints")]
100impl Nullable for i128 {
101 const NULL: Self = i128::MAX;
102
103 #[inline]
104 fn is_null(&self) -> bool {
105 *self == i128::MAX
106 }
107}
108
109#[cfg(feature = "nullable-core-ints")]
110impl Nullable for isize {
111 const NULL: Self = isize::MAX;
112
113 #[inline]
114 fn is_null(&self) -> bool {
115 *self == isize::MAX
116 }
117}
118
119#[cfg(feature = "nullable-core-ints")]
120impl Nullable for u8 {
121 const NULL: Self = u8::MAX;
122
123 #[inline]
124 fn is_null(&self) -> bool {
125 *self == u8::MAX
126 }
127}
128
129#[cfg(feature = "nullable-core-ints")]
130impl Nullable for u16 {
131 const NULL: Self = u16::MAX;
132
133 #[inline]
134 fn is_null(&self) -> bool {
135 *self == u16::MAX
136 }
137}
138
139#[cfg(feature = "nullable-core-ints")]
140impl Nullable for u32 {
141 const NULL: Self = u32::MAX;
142
143 #[inline]
144 fn is_null(&self) -> bool {
145 *self == u32::MAX
146 }
147}
148
149#[cfg(feature = "nullable-core-ints")]
150impl Nullable for u64 {
151 const NULL: Self = u64::MAX;
152
153 #[inline]
154 fn is_null(&self) -> bool {
155 *self == u64::MAX
156 }
157}
158
159#[cfg(feature = "nullable-core-ints")]
160impl Nullable for u128 {
161 const NULL: Self = u128::MAX;
162
163 #[inline]
164 fn is_null(&self) -> bool {
165 *self == u128::MAX
166 }
167}
168
169#[cfg(feature = "nullable-core-ints")]
170impl Nullable for usize {
171 const NULL: Self = usize::MAX;
172
173 #[inline]
174 fn is_null(&self) -> bool {
175 *self == usize::MAX
176 }
177}
178
179#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)]
183#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
184#[repr(transparent)]
185pub struct IOption<T: Nullable>(T);
186
187impl<T: Nullable> Default for IOption<T> {
188 #[inline]
189 fn default() -> Self {
190 Self::new(T::NULL)
191 }
192}
193
194impl<T: Nullable> IOption<T> {
195 #[inline]
196 pub const fn new(value: T) -> Self {
197 Self(value)
198 }
199
200 #[inline]
201 pub const fn none() -> Self {
202 Self(T::NULL)
203 }
204
205 #[inline]
206 pub fn is_none(&self) -> bool {
207 self.0.is_null()
208 }
209
210 #[inline]
211 pub fn is_some(&self) -> bool {
212 !self.is_none()
213 }
214
215 #[inline]
216 pub fn into_inner(self) -> T {
217 self.0
218 }
219
220 #[inline]
221 pub fn as_ref(&self) -> Option<&T> {
222 if self.is_none() { None } else { Some(&self.0) }
223 }
224
225 #[inline]
226 pub fn as_mut(&mut self) -> Option<&mut T> {
227 if self.is_none() {
228 None
229 } else {
230 Some(&mut self.0)
231 }
232 }
233
234 #[inline]
235 pub fn map<U, F>(self, f: F) -> IOption<U>
236 where
237 U: Nullable,
238 F: FnOnce(T) -> U,
239 {
240 if self.is_none() {
241 IOption::new(U::NULL)
242 } else {
243 IOption::new(f(self.into_inner()))
244 }
245 }
246
247 #[inline]
248 pub fn map_or<U, F>(self, default: U, f: F) -> U
249 where
250 U: Nullable,
251 F: FnOnce(T) -> U,
252 {
253 if self.is_none() {
254 default
255 } else {
256 f(self.into_inner())
257 }
258 }
259
260 #[inline]
261 pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U
262 where
263 U: Nullable,
264 D: FnOnce() -> U,
265 F: FnOnce(T) -> U,
266 {
267 if self.is_none() {
268 default()
269 } else {
270 f(self.into_inner())
271 }
272 }
273
274 #[inline]
275 pub fn ok_or<E>(self, err: E) -> Result<T, E> {
276 if self.is_none() {
277 Err(err)
278 } else {
279 Ok(self.into_inner())
280 }
281 }
282
283 #[inline]
284 pub fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
285 where
286 F: FnOnce() -> E,
287 {
288 if self.is_none() {
289 Err(err())
290 } else {
291 Ok(self.into_inner())
292 }
293 }
294
295 #[inline]
296 pub fn and<U>(self, other: IOption<U>) -> IOption<U>
297 where
298 U: Nullable,
299 {
300 if self.is_none() {
301 IOption::new(U::NULL)
302 } else {
303 other
304 }
305 }
306
307 #[inline]
308 pub fn and_then<U, F>(self, f: F) -> IOption<U>
309 where
310 U: Nullable,
311 F: FnOnce(T) -> IOption<U>,
312 {
313 if self.is_none() {
314 IOption::new(U::NULL)
315 } else {
316 f(self.into_inner())
317 }
318 }
319
320 #[inline]
321 pub fn or(self, other: IOption<T>) -> IOption<T>
322 where
323 T: Nullable,
324 {
325 if self.is_none() { other } else { self }
326 }
327
328 #[inline]
329 pub fn or_else<F>(self, f: F) -> IOption<T>
330 where
331 T: Nullable,
332 F: FnOnce() -> IOption<T>,
333 {
334 if self.is_none() { f() } else { self }
335 }
336
337 #[inline]
338 #[track_caller]
339 pub fn unwrap(self) -> T {
340 if self.is_none() {
341 panic!("called `IOption::unwrap()` on a `None` value")
342 } else {
343 self.into_inner()
344 }
345 }
346
347 #[inline]
348 pub fn unwrap_or(self, default: T) -> T {
349 if self.is_none() {
350 default
351 } else {
352 self.into_inner()
353 }
354 }
355
356 #[inline]
357 pub fn unwrap_or_else<F>(self, f: F) -> T
358 where
359 F: FnOnce() -> T,
360 {
361 if self.is_none() {
362 f()
363 } else {
364 self.into_inner()
365 }
366 }
367
368 #[inline]
369 #[track_caller]
370 pub fn expect(self, msg: &str) -> T {
371 if self.is_none() {
372 panic!("{}", msg)
373 } else {
374 self.into_inner()
375 }
376 }
377
378 #[inline]
379 pub fn iter(&self) -> core::option::IntoIter<&T> {
380 self.as_ref().into_iter()
381 }
382
383 #[inline]
384 pub fn iter_mut(&mut self) -> core::option::IntoIter<&mut T> {
385 self.as_mut().into_iter()
386 }
387
388 #[inline]
389 pub fn filter<P>(self, predicate: P) -> IOption<T>
390 where
391 P: FnOnce(&T) -> bool,
392 {
393 let inner = self.into_inner();
394 if inner.is_null() || !predicate(&inner) {
395 IOption::new(T::NULL)
396 } else {
397 IOption::new(inner)
398 }
399 }
400
401 #[inline]
402 pub fn take(&mut self) -> IOption<T> {
403 core::mem::take(self)
404 }
405
406 #[inline]
407 pub fn replace(&mut self, value: T) -> IOption<T> {
408 core::mem::replace(self, IOption::new(value))
409 }
410
411 #[inline]
412 pub fn get_or_insert(&mut self, value: T) -> &mut T {
413 if self.is_none() {
414 *self = IOption::new(value);
415 }
416 self.as_mut().unwrap()
417 }
418
419 #[inline]
420 pub fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
421 where
422 F: FnOnce() -> T,
423 {
424 if self.is_none() {
425 *self = IOption::new(f());
426 }
427 self.as_mut().unwrap()
428 }
429
430 #[inline]
431 pub fn get_or_insert_default(&mut self) -> &mut T
432 where
433 T: Default,
434 {
435 if self.is_none() {
436 *self = IOption::new(T::default());
437 }
438 self.as_mut().unwrap()
439 }
440}
441
442impl<T: Nullable> From<Option<T>> for IOption<T> {
443 #[inline]
444 fn from(option: Option<T>) -> Self {
445 match option {
446 Some(value) => IOption::new(value),
447 None => IOption::new(T::NULL),
448 }
449 }
450}
451
452impl<T: Nullable> From<IOption<T>> for Option<T> {
453 #[inline]
454 fn from(ioption: IOption<T>) -> Self {
455 if ioption.is_none() {
456 None
457 } else {
458 Some(ioption.into_inner())
459 }
460 }
461}
462
463impl<T: Nullable> From<T> for IOption<T> {
464 #[inline]
465 fn from(value: T) -> Self {
466 IOption::new(value)
467 }
468}
469
470#[cfg(test)]
471mod tests {
472 use super::*;
473
474 #[cfg(not(feature = "nullable-core-ints"))]
475 impl Nullable for i32 {
476 const NULL: Self = i32::MAX;
477
478 fn is_null(&self) -> bool {
479 *self == i32::MAX
480 }
481 }
482
483 #[test]
484 fn test_nullable() {
485 assert_eq!(i32::NULL, i32::MAX);
486 assert!(i32::MAX.is_null());
487 assert!(!42.is_null());
488 }
489
490 #[test]
491 fn test_size() {
492 assert_eq!(
493 core::mem::size_of::<IOption<i32>>(),
494 core::mem::size_of::<i32>()
495 );
496 }
497
498 #[test]
499 fn test_new() {
500 let ioption = IOption::new(42);
501 assert_eq!(ioption.into_inner(), 42);
502 }
503
504 #[test]
505 fn test_is_none() {
506 let ioption = IOption::new(42);
507 assert!(!ioption.is_none());
508
509 let ioption = IOption::new(i32::NULL);
510 assert!(ioption.is_none());
511 }
512
513 #[test]
514 fn test_is_some() {
515 let ioption = IOption::new(42);
516 assert!(ioption.is_some());
517
518 let ioption = IOption::new(i32::NULL);
519 assert!(!ioption.is_some());
520 }
521
522 #[test]
523 fn test_into_inner() {
524 let ioption = IOption::new(42);
525 assert_eq!(ioption.into_inner(), 42);
526 }
527
528 #[test]
529 fn test_as_ref() {
530 let ioption = IOption::new(42);
531 assert_eq!(ioption.as_ref(), Some(&42));
532
533 let ioption = IOption::new(i32::NULL);
534 assert_eq!(ioption.as_ref(), None);
535 }
536
537 #[test]
538 fn test_as_mut() {
539 let mut ioption = IOption::new(42);
540 assert_eq!(ioption.as_mut(), Some(&mut 42));
541
542 let mut ioption = IOption::new(i32::NULL);
543 assert_eq!(ioption.as_mut(), None);
544 }
545
546 #[test]
547 fn test_map() {
548 let ioption = IOption::new(42);
549 let ioption = ioption.map(|value| value * 2);
550 assert_eq!(ioption.into_inner(), 84);
551
552 let ioption = IOption::new(i32::NULL);
553 let ioption = ioption.map(|value| value * 2);
554 assert_eq!(ioption.into_inner(), i32::NULL);
555 }
556
557 #[test]
558 fn test_map_or() {
559 let ioption = IOption::new(42);
560 let value = ioption.map_or(0, |value| value * 2);
561 assert_eq!(value, 84);
562
563 let ioption = IOption::new(i32::NULL);
564 let value = ioption.map_or(0, |value| value * 2);
565 assert_eq!(value, 0);
566 }
567
568 #[test]
569 fn test_map_or_else() {
570 let ioption = IOption::new(42);
571 let value = ioption.map_or_else(|| 0, |value| value * 2);
572 assert_eq!(value, 84);
573
574 let ioption = IOption::new(i32::NULL);
575 let value = ioption.map_or_else(|| 0, |value| value * 2);
576 assert_eq!(value, 0);
577 }
578
579 #[test]
580 fn test_ok_or() {
581 let ioption = IOption::new(42);
582 let result = ioption.ok_or("error");
583 assert_eq!(result, Ok(42));
584
585 let ioption = IOption::new(i32::NULL);
586 let result = ioption.ok_or("error");
587 assert_eq!(result, Err("error"));
588 }
589
590 #[test]
591 fn test_ok_or_else() {
592 let ioption = IOption::new(42);
593 let result = ioption.ok_or_else(|| "error");
594 assert_eq!(result, Ok(42));
595
596 let ioption = IOption::new(i32::NULL);
597 let result = ioption.ok_or_else(|| "error");
598 assert_eq!(result, Err("error"));
599 }
600
601 #[test]
602 fn test_and() {
603 let ioption = IOption::new(42);
604 let other = IOption::new(84);
605 let result = ioption.and(other);
606 assert_eq!(result.into_inner(), 84);
607
608 let ioption = IOption::new(i32::NULL);
609 let other = IOption::new(84);
610 let result = ioption.and(other);
611 assert_eq!(result.into_inner(), i32::NULL);
612 }
613
614 #[test]
615 fn test_and_then() {
616 let ioption = IOption::new(42);
617 let result = ioption.and_then(|value| IOption::new(value * 2));
618 assert_eq!(result.into_inner(), 84);
619
620 let ioption = IOption::new(i32::NULL);
621 let result = ioption.and_then(|value| IOption::new(value * 2));
622 assert_eq!(result.into_inner(), i32::NULL);
623 }
624
625 #[test]
626 fn test_or() {
627 let ioption = IOption::new(42);
628 let other = IOption::new(84);
629 let result = ioption.or(other);
630 assert_eq!(result.into_inner(), 42);
631
632 let ioption = IOption::new(i32::NULL);
633 let other = IOption::new(84);
634 let result = ioption.or(other);
635 assert_eq!(result.into_inner(), 84);
636 }
637
638 #[test]
639 fn test_or_else() {
640 let ioption = IOption::new(42);
641 let result = ioption.or_else(|| IOption::new(84));
642 assert_eq!(result.into_inner(), 42);
643
644 let ioption = IOption::new(i32::NULL);
645 let result = ioption.or_else(|| IOption::new(84));
646 assert_eq!(result.into_inner(), 84);
647 }
648
649 #[test]
650 fn test_unwrap() {
651 let ioption = IOption::new(42);
652 assert_eq!(ioption.unwrap(), 42);
653 }
654
655 #[test]
656 #[should_panic]
657 fn test_unwrap_panic() {
658 let ioption = IOption::new(i32::NULL);
659 ioption.unwrap();
660 }
661
662 #[test]
663 fn test_unwrap_or() {
664 let ioption = IOption::new(42);
665 assert_eq!(ioption.unwrap_or(0), 42);
666
667 let ioption = IOption::new(i32::NULL);
668 assert_eq!(ioption.unwrap_or(0), 0);
669 }
670
671 #[test]
672 fn test_unwrap_or_else() {
673 let ioption = IOption::new(42);
674 assert_eq!(ioption.unwrap_or_else(|| 0), 42);
675
676 let ioption = IOption::new(i32::NULL);
677 assert_eq!(ioption.unwrap_or_else(|| 0), 0);
678 }
679
680 #[test]
681 fn test_expect() {
682 let ioption = IOption::new(42);
683 assert_eq!(ioption.expect("error"), 42);
684 }
685
686 #[test]
687 #[should_panic]
688 fn test_expect_panic() {
689 let ioption = IOption::new(i32::NULL);
690 ioption.expect("error");
691 }
692
693 #[test]
694 fn test_iter() {
695 let ioption = IOption::new(42);
696 let mut iter = ioption.iter();
697 assert_eq!(iter.next(), Some(&42));
698 assert_eq!(iter.next(), None);
699 }
700
701 #[test]
702 fn test_iter_mut() {
703 let mut ioption = IOption::new(42);
704 let mut iter = ioption.iter_mut();
705 assert_eq!(iter.next(), Some(&mut 42));
706 assert_eq!(iter.next(), None);
707 }
708
709 #[test]
710 fn test_filter() {
711 let ioption = IOption::new(42);
712 let result = ioption.filter(|value| *value % 2 == 0);
713 assert_eq!(result.into_inner(), 42);
714
715 let ioption = IOption::new(43);
716 let result = ioption.filter(|value| *value % 2 == 0);
717 assert_eq!(result.into_inner(), i32::NULL);
718 }
719
720 #[test]
721 fn test_take() {
722 let mut ioption = IOption::new(42);
723 let result = ioption.take();
724 assert_eq!(result.into_inner(), 42);
725 assert!(ioption.is_none());
726 }
727
728 #[test]
729 fn test_replace() {
730 let mut ioption = IOption::new(42);
731 let result = ioption.replace(84);
732 assert_eq!(result.into_inner(), 42);
733 assert_eq!(ioption.into_inner(), 84);
734 }
735
736 #[test]
737 fn test_get_or_insert() {
738 let mut ioption = IOption::new(42);
739 let value = ioption.get_or_insert(84);
740 assert_eq!(value, &42);
741 assert_eq!(ioption.into_inner(), 42);
742
743 let mut ioption = IOption::new(i32::NULL);
744 let value = ioption.get_or_insert(84);
745 assert_eq!(value, &84);
746 assert_eq!(ioption.into_inner(), 84);
747 }
748
749 #[test]
750 fn test_get_or_insert_with() {
751 let mut ioption = IOption::new(42);
752 let value = ioption.get_or_insert_with(|| 84);
753 assert_eq!(value, &42);
754 assert_eq!(ioption.into_inner(), 42);
755
756 let mut ioption = IOption::new(i32::NULL);
757 let value = ioption.get_or_insert_with(|| 84);
758 assert_eq!(value, &84);
759 assert_eq!(ioption.into_inner(), 84);
760 }
761
762 #[test]
763 fn test_get_or_insert_default() {
764 let mut ioption = IOption::new(42);
765 let value = ioption.get_or_insert_default();
766 assert_eq!(value, &42);
767 assert_eq!(ioption.into_inner(), 42);
768
769 let mut ioption = IOption::new(i32::NULL);
770 let value = ioption.get_or_insert_default();
771 assert_eq!(value, &Default::default());
772 assert_eq!(ioption.into_inner(), Default::default());
773 }
774
775 #[test]
776 fn test_from_option() {
777 let option = Some(42);
778 let ioption = IOption::<i32>::from(option);
779 assert_eq!(ioption.into_inner(), 42);
780
781 let option = None;
782 let ioption = IOption::<i32>::from(option);
783 assert_eq!(ioption.into_inner(), i32::NULL);
784 }
785
786 #[test]
787 fn test_from_ioption() {
788 let ioption = IOption::new(42);
789 let option = Option::from(ioption);
790 assert_eq!(option, Some(42));
791
792 let ioption = IOption::new(i32::NULL);
793 let option = Option::<i32>::from(ioption);
794 assert_eq!(option, None);
795 }
796
797 #[test]
798 fn test_from_value() {
799 let value = 42;
800 let ioption = IOption::from(value);
801 assert_eq!(ioption.into_inner(), 42);
802 }
803
804 #[test]
805 fn test_default() {
806 let ioption = IOption::<i32>::default();
807 assert!(ioption.is_none());
808 }
809}