somok/
lib.rs

1#![deny(missing_docs)]
2//! # Somok - postfix Result/Option wrapping
3//!
4//! ## Usage:
5//! Add following to your cargo toml:
6//! ```toml
7//! somok = "1.0"
8//! ```
9//! Then use postfix wrapping as follows:
10//! ```rust
11//! use somok::Somok;
12//!
13//! fn foo() -> Result<Option<String>> {
14//!     String::from("Foobar").some().okay()
15//! }
16//! ```
17
18/// Postfix wrapping in Result and Option
19/// ### Usage:
20/// ```rust
21/// fn foo() -> Result<Option<String>> {
22///     String::from("Foobar").some().okay()
23/// }
24/// ```
25pub trait Somok: Sized {
26    /// Returns self wrapped in Ok
27    fn okay<E>(self) -> Result<Self, E> {
28        Ok(self)
29    }
30    /// Returns self wrapped in Err
31    fn error<T>(self) -> Result<T, Self> {
32        Err(self)
33    }
34    /// Returns self wrapped in Some
35    fn some(self) -> Option<Self> {
36        Some(self)
37    }
38    /// Returns boxed self
39    fn boxed(self) -> Box<Self> {
40        Box::new(self)
41    }
42    /// Returns self wrapped in `Either::Left`
43    fn left<R>(self) -> Either<Self, R> {
44        Either::Left(self)
45    }
46    /// Returns self wrapped in `Either::Right`
47    fn right<L>(self) -> Either<L, Self> {
48        Either::Right(self)
49    }
50}
51impl<T: Sized> Somok for T {}
52
53/// Postfix notation for leaking the box
54pub trait Leaksome<T: ?Sized> {
55    /// Leaks the box
56    fn leak(self) -> &'static mut T;
57}
58impl<T: ?Sized> Leaksome<T> for Box<T> {
59    fn leak(self) -> &'static mut T {
60        Box::leak(self)
61    }
62}
63
64/// Fallible `remove()` alternative for Vec
65pub trait TryRemove {
66    /// Type of collection item
67    type Item;
68    /// Attempts to `remove` item at index
69    fn try_remove(&mut self, i: usize) -> Option<Self::Item>;
70}
71impl<T> TryRemove for Vec<T> {
72    type Item = T;
73
74    fn try_remove(&mut self, i: usize) -> Option<Self::Item> {
75        if i < self.len() {
76            self.remove(i).some()
77        } else {
78            None
79        }
80    }
81}
82
83/// Convinience method for conditionally popping from a collection
84pub trait CondPop {
85    /// Type of collection item
86    type Item;
87    /// Conditionally pops off an item from collection
88    fn cond_pop<F>(&mut self, cond: F) -> Option<Self::Item>
89    where
90        F: Fn(&Self::Item) -> bool;
91}
92impl<T> CondPop for Vec<T> {
93    type Item = T;
94
95    fn cond_pop<F>(&mut self, cond: F) -> Option<Self::Item>
96    where
97        F: Fn(&Self::Item) -> bool,
98    {
99        if let Some(last) = self.last() {
100            cond(last).then(|| self.pop()).flatten()
101        } else {
102            None
103        }
104    }
105}
106
107/// Enum representing either of two options
108#[derive(Debug, Clone, Copy)]
109pub enum Either<L, R> {
110    /// Left variant
111    Left(L),
112    /// Right variant
113    Right(R),
114}
115
116/// Enum representing partitioning choice in `PartitionThree`
117pub enum Ternary {
118    /// Variant representing first partition option
119    First,
120    /// Variant representing second partition option
121    Second,
122    /// Variant representing third partition option
123    Third,
124}
125
126/// Trait providing method analogous to `Iterator::partition`
127/// but resulting in three distinct groupings
128pub trait PartitionThree: Iterator {
129    /// Consumes an iterator, creating three collections from it.
130    /// The predicate passed to partition() can return `First`, `Second`, or `Third`. partition() returns a triple,
131    /// all of the elements for which it returned `First`, all of the elements for which it returned `Second`, and all of the elements for which it returned `Third`.
132    fn partition_three<C, F>(self, f: F) -> (C, C, C)
133    where
134        Self: Sized,
135        C: Default + Extend<<Self as Iterator>::Item>,
136        F: FnMut(&<Self as Iterator>::Item) -> Ternary,
137    {
138        #[inline]
139        fn extend<'a, T, C: Extend<T>>(
140            mut f: impl FnMut(&T) -> Ternary + 'a,
141            first: &'a mut C,
142            second: &'a mut C,
143            third: &'a mut C,
144        ) -> impl FnMut((), T) + 'a {
145            move |(), x| match f(&x) {
146                Ternary::First => first.extend([x]),
147                Ternary::Second => second.extend([x]),
148                Ternary::Third => third.extend([x]),
149            }
150        }
151
152        let mut first = C::default();
153        let mut second = C::default();
154        let mut third = C::default();
155
156        self.fold((), extend(f, &mut first, &mut second, &mut third));
157        (first, second, third)
158    }
159}
160
161impl<T: Iterator> PartitionThree for T {}