apply_conditionally/lib.rs
1//! # Apply Conditionally
2//!
3//! *Chain and apply methods on objects conditionally.*
4
5#![no_std]
6
7use either::IntoEither;
8
9/// Provides methods for conditionally applying methods on a type `Self`,
10/// whose size is constant and known at compile-time.
11///
12/// The [`ApplyConditionally::apply`] method always applies `f` on `self`.
13///
14/// The [`ApplyConditionally::apply_if`] method takes a [`bool`] to determine
15/// whether to apply `f` on `self` or not.
16///
17/// The [`ApplyConditionally::apply_or_else`] method takes a [`bool`] to
18/// determine whether to apply `f` or `g` on `self`.
19pub trait ApplyConditionally: Sized {
20 /// Applies `f` on `self`.
21 ///
22 /// # Examples
23 ///
24 /// ```
25 /// use apply_conditionally::ApplyConditionally;
26 ///
27 /// fn add2(x: u32) -> u32 {
28 /// x + 2
29 /// }
30 ///
31 /// fn mul2(x: u32) -> u32 {
32 /// x * 2
33 /// }
34 ///
35 /// let x = 2;
36 /// assert_eq!(x.apply(add2).apply(mul2), 8);
37 /// ```
38 ///
39 /// is the same as doing:
40 ///
41 /// ```
42 /// use apply_conditionally::ApplyConditionally;
43 ///
44 /// fn add2(x: u32) -> u32 {
45 /// x + 2
46 /// }
47 ///
48 /// fn mul2(x: u32) -> u32 {
49 /// x * 2
50 /// }
51 ///
52 /// let x = 2;
53 /// assert_eq!(mul2(add2(x)), 8);
54 /// ```
55 #[inline]
56 fn apply<T, F>(self, f: F) -> T
57 where
58 F: FnOnce(Self) -> T,
59 {
60 f(self)
61 }
62
63 /// Applies `f` on `self` if and only if `condition` is `true`.
64 /// Does nothing otherwise.
65 ///
66 /// # Examples
67 ///
68 /// ```
69 /// use apply_conditionally::ApplyConditionally;
70 ///
71 /// fn u8_to_bools(value: u8, rtl: bool) -> [bool; 8] {
72 /// let mut result = [false; 8];
73 /// result
74 /// .iter_mut()
75 /// .apply_if(rtl, Iterator::rev)
76 /// .enumerate()
77 /// .for_each(|(i, b)| *b = ((value >> i) & 1) == 1);
78 ///
79 /// result
80 /// }
81 ///
82 /// assert_eq!(
83 /// u8_to_bools(0b00101101, false),
84 /// [true, false, true, true, false, true, false, false]
85 /// );
86 /// assert_eq!(
87 /// u8_to_bools(0b00101101, true),
88 /// [false, false, true, false, true, true, false, true]
89 /// );
90 /// ```
91 ///
92 /// is the same as doing:
93 ///
94 /// ```
95 /// fn u8_to_bools(value: u8, rtl: bool) -> [bool; 8] {
96 /// let mut result = [false; 8];
97 /// if rtl {
98 /// result
99 /// .iter_mut()
100 /// .rev()
101 /// .enumerate()
102 /// .for_each(|(i, b)| *b = ((value >> i) & 1) == 1);
103 /// } else {
104 /// result
105 /// .iter_mut()
106 /// .enumerate()
107 /// .for_each(|(i, b)| *b = ((value >> i) & 1) == 1);
108 /// }
109 ///
110 /// result
111 /// }
112 ///
113 /// assert_eq!(
114 /// u8_to_bools(0b00101101, false),
115 /// [true, false, true, true, false, true, false, false]
116 /// );
117 /// assert_eq!(
118 /// u8_to_bools(0b00101101, true),
119 /// [false, false, true, false, true, true, false, true]
120 /// );
121 /// ```
122 #[inline]
123 fn apply_if<T, F>(self, condition: bool, f: F) -> either::Either<T, Self>
124 where
125 F: FnOnce(Self) -> T,
126 {
127 self.into_either(condition).map_left(f)
128 }
129
130 /// Applies `f` on `self` if `condition` is `true`.
131 /// Applies `g` otherwise.
132 ///
133 /// # Examples
134 ///
135 /// ```
136 /// use apply_conditionally::ApplyConditionally;
137 ///
138 /// fn get_pairs(bytes: &[u8], overlap: bool) -> Vec<(u8, u8)> {
139 /// bytes
140 /// .apply_or_else(overlap, |bytes| bytes.windows(2), |bytes| bytes.chunks(2))
141 /// .map(|w| (w[0], w[1]))
142 /// .collect()
143 /// }
144 ///
145 /// assert_eq!(get_pairs(b"abcd", false), vec![(b'a', b'b'), (b'c', b'd')]);
146 /// assert_eq!(
147 /// get_pairs(b"abcd", true),
148 /// vec![(b'a', b'b'), (b'b', b'c'), (b'c', b'd')]
149 /// );
150 /// ```
151 ///
152 /// is the same as doing:
153 ///
154 /// ```
155 /// fn get_pairs(bytes: &[u8], overlap: bool) -> Vec<(u8, u8)> {
156 /// if overlap {
157 /// bytes.windows(2).map(|w| (w[0], w[1])).collect()
158 /// } else {
159 /// bytes.chunks(2).map(|w| (w[0], w[1])).collect()
160 /// }
161 /// }
162 ///
163 /// assert_eq!(get_pairs(b"abcd", false), vec![(b'a', b'b'), (b'c', b'd')]);
164 /// assert_eq!(
165 /// get_pairs(b"abcd", true),
166 /// vec![(b'a', b'b'), (b'b', b'c'), (b'c', b'd')]
167 /// );
168 /// ```
169 #[inline]
170 fn apply_or_else<L, R, F, G>(self, condition: bool, f: F, g: G) -> either::Either<L, R>
171 where
172 F: FnOnce(Self) -> L,
173 G: FnOnce(Self) -> R,
174 {
175 self.into_either(condition).map_either(f, g)
176 }
177}
178
179impl<T> ApplyConditionally for T {}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 fn add2(x: usize) -> usize {
186 x + 2
187 }
188
189 fn mul2(x: usize) -> usize {
190 x * 2
191 }
192
193 #[test]
194 fn test_apply() {
195 let x = 2;
196
197 assert_eq!(x.apply(add2), add2(x));
198 assert_eq!(x.apply(add2).apply(|x| mul2(x)), mul2(add2(x)));
199 }
200
201 #[test]
202 fn test_apply_if() {
203 let x = 2;
204
205 assert_eq!(
206 x.apply_if(true, |x| x.apply(add2).apply(mul2)),
207 either::Either::Left(x.apply(add2).apply(mul2))
208 );
209 assert_eq!(
210 x.apply_if(false, |x| x.apply(add2).apply(mul2)),
211 either::Either::Right(x)
212 );
213 }
214
215 #[test]
216 fn test_apply_or_else() {
217 let x = 2;
218
219 assert_eq!(
220 x.apply_or_else(
221 true,
222 |x| x.apply(add2).apply(mul2),
223 |x| x.apply(mul2).apply(add2)
224 ),
225 either::Either::Left(x.apply(add2).apply(mul2))
226 );
227 assert_eq!(
228 x.apply_or_else(
229 false,
230 |x| x.apply(add2).apply(mul2),
231 |x| x.apply(mul2).apply(add2)
232 ),
233 either::Either::Right(x.apply(mul2).apply(add2))
234 );
235 }
236}