1#![warn(missing_docs)]
9#![cfg_attr(not(feature = "std"), no_std)]
10#![cfg_attr(not(feature = "__unstable"), forbid(unstable_features))]
11#![cfg_attr(feature = "try_trait", feature(try_trait_v2))]
12
13#[cfg(feature = "try_trait")]
14mod try_trait;
15
16use self::NullableResult::*;
17#[cfg(doc)]
18use core::convert::TryInto;
19use core::{
20 convert::TryFrom,
21 fmt::Debug,
22 iter::{FilterMap, FromIterator, FusedIterator},
23 ops::Deref,
24};
25
26#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
83#[must_use]
84pub enum NullableResult<T, E> {
85 Ok(T),
87 Err(E),
89 Null,
91}
92
93impl<T, E> Default for NullableResult<T, E> {
94 fn default() -> Self {
96 Null
97 }
98}
99
100impl<T, E: Debug> NullableResult<T, E> {
101 #[inline]
103 pub fn unwrap(self) -> T {
104 match self {
105 NullableResult::Ok(item) => item,
106 NullableResult::Err(err) => panic!(
107 "tried to unwrap a nullable result containing Err: {:?}",
108 err
109 ),
110 NullableResult::Null => {
111 panic!("tried to unwrap a nullable result containing `Null`")
112 }
113 }
114 }
115}
116
117impl<T: Default, E> NullableResult<T, E> {
118 #[inline]
121 pub fn unwrap_or_default(self) -> T {
122 match self {
123 Ok(item) => item,
124 _ => T::default(),
125 }
126 }
127}
128
129impl<T: Copy, E> NullableResult<&'_ T, E> {
130 #[inline]
132 pub fn copied(self) -> NullableResult<T, E> {
133 self.map(|&item| item)
134 }
135}
136
137impl<T: Copy, E> NullableResult<&'_ mut T, E> {
138 #[inline]
140 pub fn copied(self) -> NullableResult<T, E> {
141 self.map(|&mut item| item)
142 }
143}
144
145impl<T: Clone, E> NullableResult<&'_ T, E> {
146 #[inline]
148 pub fn cloned(self) -> NullableResult<T, E> {
149 self.map(|item| item.clone())
150 }
151}
152
153impl<T: Clone, E> NullableResult<&'_ mut T, E> {
154 #[inline]
156 pub fn cloned(self) -> NullableResult<T, E> {
157 self.map(|item| item.clone())
158 }
159}
160
161impl<T: Deref, E> NullableResult<T, E> {
162 #[inline]
165 pub fn as_deref(&self) -> NullableResult<&T::Target, &E> {
166 match self {
167 Ok(item) => Ok(item.deref()),
168 Err(err) => Err(err),
169 Null => Null,
170 }
171 }
172}
173
174impl<T, E> NullableResult<T, E> {
175 #[inline]
177 #[must_use]
178 pub fn is_ok(&self) -> bool {
179 matches!(self, Ok(_))
180 }
181
182 #[inline]
184 #[must_use]
185 pub fn is_err(&self) -> bool {
186 matches!(self, Err(_))
187 }
188
189 #[inline]
191 #[must_use]
192 pub fn is_null(&self) -> bool {
193 matches!(self, Null)
194 }
195
196 #[inline]
201 #[track_caller]
202 pub fn expect(self, msg: &str) -> T {
203 match self {
204 Ok(item) => item,
205 _ => panic!("{}", msg),
206 }
207 }
208
209 #[inline]
211 pub fn unwrap_or(self, item: T) -> T {
212 match self {
213 Ok(item) => item,
214 _ => item,
215 }
216 }
217
218 #[inline]
221 pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
222 match self {
223 Ok(item) => item,
224 _ => f(),
225 }
226 }
227
228 #[inline]
231 pub fn option(self) -> Option<T> {
232 match self {
233 Ok(item) => Some(item),
234 Err(_) | Null => None,
235 }
236 }
237
238 #[inline]
240 pub fn optional_result(self) -> Option<Result<T, E>> {
241 self.into()
242 }
243
244 #[inline]
246 pub fn resulting_option(self) -> Result<Option<T>, E> {
247 self.into()
248 }
249
250 #[inline]
253 pub fn result(self, err: E) -> Result<T, E> {
254 match self {
255 Ok(item) => Result::Ok(item),
256 Err(err) => Result::Err(err),
257 Null => Result::Err(err),
258 }
259 }
260
261 #[inline]
264 pub fn result_with<F: FnOnce() -> E>(self, f: F) -> Result<T, E> {
265 match self {
266 Ok(item) => Result::Ok(item),
267 Err(err) => Result::Err(err),
268 Null => Result::Err(f()),
269 }
270 }
271
272 #[inline]
274 pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> NullableResult<U, E> {
275 match self {
276 Ok(item) => Ok(f(item)),
277 Err(err) => Err(err),
278 Null => Null,
279 }
280 }
281
282 #[inline]
284 pub fn map_err<U, F: FnOnce(E) -> U>(self, f: F) -> NullableResult<T, U> {
285 match self {
286 Ok(item) => NullableResult::Ok(item),
287 Err(err) => NullableResult::Err(f(err)),
288 Null => NullableResult::Null,
289 }
290 }
291
292 #[inline]
294 pub fn result_optional_err(self) -> Result<T, Option<E>> {
295 match self {
296 Ok(item) => Result::Ok(item),
297 Err(err) => Result::Err(Some(err)),
298 Null => Result::Err(None),
299 }
300 }
301
302 #[inline]
305 pub fn as_ref(&self) -> NullableResult<&T, &E> {
306 use NullableResult::*;
307 match self {
308 Ok(item) => Ok(item),
309 Err(err) => Err(err),
310 Null => Null,
311 }
312 }
313
314 #[inline]
317 pub fn as_mut(&mut self) -> NullableResult<&mut T, &mut E> {
318 use NullableResult::*;
319 match self {
320 Ok(item) => Ok(item),
321 Err(err) => Err(err),
322 Null => Null,
323 }
324 }
325
326 #[inline]
329 pub fn and<U>(self, res: NullableResult<U, E>) -> NullableResult<U, E> {
330 match self {
331 Ok(_) => res,
332 Err(err) => Err(err),
333 Null => Null,
334 }
335 }
336
337 #[inline]
340 pub fn and_then<U, F>(self, op: F) -> NullableResult<U, E>
341 where
342 F: FnOnce(T) -> NullableResult<U, E>,
343 {
344 match self {
345 Ok(item) => op(item),
346 Err(err) => Err(err),
347 Null => Null,
348 }
349 }
350}
351
352impl<T, E> NullableResult<NullableResult<T, E>, E> {
353 #[inline]
356 pub fn flatten(self) -> NullableResult<T, E> {
357 match self {
358 Ok(Ok(item)) => Ok(item),
359 Ok(Err(err)) | Err(err) => Err(err),
360 Ok(Null) | Null => Null,
361 }
362 }
363}
364
365impl<T, E> From<Result<Option<T>, E>> for NullableResult<T, E> {
366 #[inline]
367 fn from(res: Result<Option<T>, E>) -> Self {
368 match res {
369 Result::Ok(Option::Some(item)) => Ok(item),
370 Result::Ok(None) => Null,
371 Result::Err(err) => Err(err),
372 }
373 }
374}
375
376impl<T, E> From<NullableResult<T, E>> for Result<Option<T>, E> {
377 #[inline]
378 fn from(nr: NullableResult<T, E>) -> Self {
379 match nr {
380 Ok(item) => Result::Ok(Some(item)),
381 Err(err) => Result::Err(err),
382 Null => Result::Ok(None),
383 }
384 }
385}
386
387impl<T, E> From<Result<T, E>> for NullableResult<T, E> {
388 #[inline]
389 fn from(res: Result<T, E>) -> Self {
390 match res {
391 Result::Ok(item) => Ok(item),
392 Result::Err(err) => Err(err),
393 }
394 }
395}
396
397impl<T, E> From<Option<Result<T, E>>> for NullableResult<T, E> {
398 #[inline]
399 fn from(opt: Option<Result<T, E>>) -> Self {
400 match opt {
401 None => Null,
402 Some(Result::Ok(item)) => Ok(item),
403 Some(Result::Err(err)) => Err(err),
404 }
405 }
406}
407
408impl<T, E> From<NullableResult<T, E>> for Option<Result<T, E>> {
409 #[inline]
410 fn from(nr: NullableResult<T, E>) -> Self {
411 match nr {
412 Ok(item) => Some(Result::Ok(item)),
413 Err(err) => Some(Result::Err(err)),
414 Null => None,
415 }
416 }
417}
418
419impl<T, E> From<Option<T>> for NullableResult<T, E> {
420 #[inline]
421 fn from(opt: Option<T>) -> Self {
422 match opt {
423 Some(item) => Ok(item),
424 None => Null,
425 }
426 }
427}
428
429impl<T, E> From<Result<T, Option<E>>> for NullableResult<T, E> {
430 #[inline]
431 fn from(res: Result<T, Option<E>>) -> Self {
432 match res {
433 Result::Ok(item) => Ok(item),
434 Result::Err(Some(err)) => Err(err),
435 Result::Err(None) => Null,
436 }
437 }
438}
439
440impl<T, E, C> FromIterator<NullableResult<T, E>> for NullableResult<C, E>
441where
442 C: FromIterator<T>,
443{
444 fn from_iter<I: IntoIterator<Item = NullableResult<T, E>>>(
445 iter: I,
446 ) -> Self {
447 let result = iter
448 .into_iter()
449 .map(NullableResult::result_optional_err)
450 .collect::<Result<_, _>>();
451
452 NullableResult::from(result)
453 }
454}
455
456#[macro_export]
488macro_rules! extract {
489 ($nr:expr) => {
490 extract!($nr, _)
491 };
492 ($nr:expr, $err:ty) => {{
493 let nr = $crate::NullableResult::<_, $err>::from($nr);
494 match nr {
495 $crate::NullableResult::Ok(item) => item,
496 $crate::NullableResult::Err(err) => {
497 return $crate::NullableResult::Err(err.into());
498 }
499 $crate::NullableResult::Null => {
500 return $crate::NullableResult::Null;
501 }
502 }
503 }};
504}
505
506pub trait GeneralIterExt: Iterator {
508 fn try_find<E, P>(self, pred: P) -> NullableResult<Self::Item, E>
511 where
512 P: FnMut(&Self::Item) -> Result<bool, E>;
513
514 fn try_find_map<T, E, F>(self, f: F) -> NullableResult<T, E>
517 where
518 F: FnMut(Self::Item) -> NullableResult<T, E>;
519
520 fn maybe_try_fold<T, E, Op>(
523 &mut self,
524 init: T,
525 op: Op,
526 ) -> NullableResult<T, E>
527 where
528 Op: FnMut(T, Self::Item) -> NullableResult<T, E>;
529}
530
531impl<I: Iterator> GeneralIterExt for I {
532 #[inline]
533 fn try_find<E, P>(self, mut pred: P) -> NullableResult<Self::Item, E>
534 where
535 P: FnMut(&Self::Item) -> Result<bool, E>,
536 {
537 for item in self {
538 return match pred(&item) {
539 Result::Err(err) => Err(err),
540 Result::Ok(true) => Ok(item),
541 Result::Ok(false) => continue,
542 };
543 }
544 Null
545 }
546
547 #[inline]
548 fn try_find_map<T, E, F>(self, mut f: F) -> NullableResult<T, E>
549 where
550 F: FnMut(Self::Item) -> NullableResult<T, E>,
551 {
552 for item in self {
553 return match f(item) {
554 Ok(item) => Ok(item),
555 Err(err) => Err(err),
556 Null => continue,
557 };
558 }
559 Null
560 }
561
562 #[inline]
563 fn maybe_try_fold<T, E, Op>(
564 &mut self,
565 init: T,
566 mut op: Op,
567 ) -> NullableResult<T, E>
568 where
569 Op: FnMut(T, Self::Item) -> NullableResult<T, E>,
570 {
571 self.try_fold(init, |prev, curr| op(prev, curr).result_optional_err())
572 .into()
573 }
574}
575
576pub trait IterExt<T, E>: Iterator<Item = NullableResult<T, E>>
578where
579 Self: Sized,
580{
581 #[inline]
583 fn filter_nulls(self) -> FilterNulls<Self, T, E> {
584 self.filter_map(Option::from)
585 }
586
587 #[inline]
589 fn extract_and_find<P>(self, mut pred: P) -> NullableResult<T, E>
590 where
591 P: FnMut(&T) -> Result<bool, E>,
592 {
593 self.try_find_map(|item| {
594 let item = extract!(item);
595 match pred(&item) {
596 Result::Err(err) => Err(err),
597 Result::Ok(true) => Ok(item),
598 Result::Ok(false) => Null,
599 }
600 })
601 }
602
603 #[inline]
606 fn extract_and_find_map<F, U>(self, mut f: F) -> NullableResult<U, E>
607 where
608 F: FnMut(T) -> NullableResult<U, E>,
609 {
610 self.try_find_map(|item| f(extract!(item)))
611 }
612
613 #[inline]
616 fn try_filter<P>(self, pred: P) -> TryFilter<Self, P, T, E>
617 where
618 P: FnMut(&T) -> bool,
619 {
620 TryFilter { inner: self, pred }
621 }
622
623 fn try_filter_map<F, U>(self, f: F) -> TryFilterMap<Self, F, T, U, E>
625 where
626 F: FnMut(T) -> Option<NullableResult<U, E>>,
627 {
628 TryFilterMap { inner: self, f }
629 }
630}
631
632impl<I, T, E> IterExt<T, E> for I where I: Iterator<Item = NullableResult<T, E>> {}
633
634type FilterNulls<I, T, E> =
635 FilterMap<I, fn(NullableResult<T, E>) -> Option<Result<T, E>>>;
636
637pub struct TryFilter<I, P, T, E>
639where
640 I: Iterator<Item = NullableResult<T, E>>,
641 P: FnMut(&T) -> bool,
642{
643 inner: I,
644 pred: P,
645}
646
647impl<I, P, T, E> Iterator for TryFilter<I, P, T, E>
648where
649 I: Iterator<Item = NullableResult<T, E>>,
650 P: FnMut(&T) -> bool,
651{
652 type Item = NullableResult<T, E>;
653
654 #[inline]
655 fn next(&mut self) -> Option<Self::Item> {
656 match self.inner.next() {
657 None => None,
658 Some(Null) => Some(Null),
659 Some(Err(err)) => Some(Err(err)),
660 Some(Ok(item)) if (self.pred)(&item) => Some(Ok(item)),
661 Some(Ok(_)) => self.next(),
662 }
663 }
664}
665
666impl<I, P, T, E> FusedIterator for TryFilter<I, P, T, E>
667where
668 I: FusedIterator<Item = NullableResult<T, E>>,
669 P: FnMut(&T) -> bool,
670{
671}
672
673pub struct TryFilterMap<I, F, T, U, E>
675where
676 I: Iterator<Item = NullableResult<T, E>>,
677 F: FnMut(T) -> Option<NullableResult<U, E>>,
678{
679 inner: I,
680 f: F,
681}
682
683impl<I, F, T, U, E> Iterator for TryFilterMap<I, F, T, U, E>
684where
685 I: Iterator<Item = NullableResult<T, E>>,
686 F: FnMut(T) -> Option<NullableResult<U, E>>,
687{
688 type Item = NullableResult<U, E>;
689
690 #[inline]
691 fn next(&mut self) -> Option<Self::Item> {
692 match self.inner.next() {
693 None => None,
694 Some(Null) => Some(Null),
695 Some(Err(err)) => Some(Err(err)),
696 Some(Ok(item)) => (self.f)(item),
697 }
698 }
699}
700
701impl<I, F, T, U, E> FusedIterator for TryFilterMap<I, F, T, U, E>
702where
703 I: FusedIterator<Item = NullableResult<T, E>>,
704 F: FnMut(T) -> Option<NullableResult<U, E>>,
705{
706}
707
708pub trait MaybeTryFrom<T>: Sized {
710 type Error;
712
713 fn maybe_try_from(item: T) -> NullableResult<Self, Self::Error>;
715}
716
717pub trait MaybeTryInto<T>: Sized {
719 type Error;
721
722 fn maybe_try_into(self) -> NullableResult<T, Self::Error>;
724}
725
726impl<T, U: TryFrom<T>> MaybeTryFrom<T> for U {
727 type Error = U::Error;
728
729 #[inline]
730 fn maybe_try_from(item: T) -> NullableResult<Self, Self::Error> {
731 U::try_from(item).into()
732 }
733}
734
735impl<T, U: MaybeTryFrom<T>> MaybeTryInto<U> for T {
736 type Error = U::Error;
737
738 #[inline]
739 fn maybe_try_into(self) -> NullableResult<U, Self::Error> {
740 U::maybe_try_from(self)
741 }
742}