ext/no_std/functions/ext.rs
1use crate::no_std::pipelines::{pipe::Pipe, tap::Tap};
2use core::{cell::{Cell, RefCell}, ops::{BitXorAssign, Not}, str::Utf8Error};
3use alloc::{boxed::Box, format, rc::Rc, str, string::String, sync::Arc, vec::Vec, borrow::Cow};
4use itertools::Itertools;
5use super::fam::{Applicative, Maybe, Either, Vector};
6
7/// This trait is to implement some extension functions,
8/// which need a generic return type, for any sized type.
9pub trait AnyExt1<R>: Sized {
10 /// The Y Combinator
11 ///
12 /// # Examples
13 ///
14 /// ```
15 /// use aoko::no_std::functions::ext::*;
16 ///
17 /// fn factorial(n: u8) -> u8 {
18 /// n.y(|f, n| match n {
19 /// 0 => 1,
20 /// n => n * f(n - 1),
21 /// })
22 /// }
23 /// assert_eq!(factorial(5), 5 * 4 * 3 * 2 * 1);
24 ///
25 /// fn fibonacci(n: u8) -> u8 {
26 /// n.y(|f, n| match n {
27 /// 0 => 0,
28 /// 1 => 1,
29 /// n => f(n - 1) + f(n - 2),
30 /// })
31 /// }
32 /// assert_eq!(fibonacci(10), 55);
33 /// ```
34 fn y(self, f: impl Copy + Fn(&dyn Fn(Self) -> R, Self) -> R) -> R {
35 // The Y Combinator
36 fn y<T, R>(f: impl Copy + Fn(&dyn Fn(T) -> R, T) -> R) -> impl Fn(T) -> R {
37 move |a| f(&y(f), a)
38 }
39 // Chainable
40 y(f)(self)
41 }
42
43 /// Returns `Some(f())` if it satisfies the given predicate function,
44 /// or `None` if it doesn't.
45 ///
46 /// # Examples
47 ///
48 /// ```
49 /// use aoko::no_std::functions::ext::*;
50 ///
51 /// assert_eq!("Hello World".to_string().into_some(), "Hello".if_then(|s| s.starts_with("Hel"), |s| format!("{} World", s)));
52 /// assert_eq!(None, "Hello".if_then(|s| s.starts_with("Wor"), |_| ()));
53 /// ```
54 fn if_then(self, r#if: impl FnOnce(&Self) -> bool, then: impl FnOnce(Self) -> R) -> Option<R> {
55 if r#if(&self) { then(self).into_some() } else { None }
56 }
57
58 /// Returns `Some(f())` if it doesn't satisfy the given predicate function,
59 /// or `None` if it does.
60 ///
61 /// # Examples
62 ///
63 /// ```
64 /// use aoko::no_std::functions::ext::*;
65 ///
66 /// assert_eq!(None, "Hello".if_not_then(|s| s.starts_with("Hel"), |_| ()));
67 /// assert_eq!("Hello World".to_string().into_some(), "Hello".if_not_then(|s| s.starts_with("Wor"), |s| format!("{} World", s)));
68 /// ```
69 fn if_not_then(self, unless: impl FnOnce(&Self) -> bool, then: impl FnOnce(Self) -> R) -> Option<R> {
70 self.if_then(|x| Not::not.compose(unless)(x), then)
71 }
72}
73
74impl<T, R> AnyExt1<R> for T {}
75
76/// This trait is to implement some extension functions for any sized type.
77pub trait AnyExt: Sized {
78 /// Chainable `drop`
79 fn drop(self) {}
80
81 /// Convert `value` to `Some(value)`
82 fn into_some(self) -> Option<Self> {
83 self.pipe(Maybe::pure)
84 }
85
86 /// Convert `value` to `Ok(value)`
87 fn into_ok<B>(self) -> Result<Self, B> {
88 self.pipe(Either::pure)
89 }
90
91 /// Convert `value` to `Err(value)`
92 fn into_err<A>(self) -> Result<A, Self> {
93 Result::from(Err(self))
94 }
95
96 /// Convert `value` to `Box::new(value)`
97 fn into_box(self) -> Box<Self> {
98 self.pipe(Box::new)
99 }
100
101 /// Convert `value` to `Cell::new(value)`
102 fn into_cell(self) -> Cell<Self> {
103 self.pipe(Cell::new)
104 }
105
106 /// Convert `value` to `RefCell::new(value)`
107 fn into_refcell(self) -> RefCell<Self> {
108 self.pipe(RefCell::new)
109 }
110
111 /// Convert `value` to `Rc::new(value)`
112 fn into_rc(self) -> Rc<Self> {
113 self.pipe(Rc::new)
114 }
115
116 /// Convert `value` to `Rc::new(Cell::new(value))`
117 fn into_rc_cell(self) -> Rc<Cell<Self>> {
118 Rc::new.compose(Cell::new)(self)
119 }
120
121 /// Convert `value` to `Rc::new(RefCell::new(value))`
122 fn into_rc_refcell(self) -> Rc<RefCell<Self>> {
123 Rc::new.compose(RefCell::new)(self)
124 }
125
126 /// Convert `value` to `Arc::new(value)`
127 fn into_arc(self) -> Arc<Self> {
128 self.pipe(Arc::new)
129 }
130
131 /// Consumes `self`,
132 /// returns the name of its type as a string slice and the receiver `self`.
133 ///
134 /// # Examples
135 ///
136 /// ```
137 /// use aoko::no_std::functions::ext::*;
138 ///
139 /// assert_eq!("".type_name(), "&str");
140 /// assert_eq!((&"").type_name(), "&&str");
141 /// ```
142 fn type_name(self) -> &'static str {
143 core::any::type_name::<Self>()
144 }
145
146 /// Consumes `self`,
147 /// returns the size of its type in number and the receiver `self`.
148 ///
149 /// # Examples
150 ///
151 /// ```
152 /// use aoko::no_std::functions::ext::*;
153 ///
154 /// assert_eq!(().type_size(), 0);
155 /// assert_eq!((&()).type_size(), 8);
156 /// assert_eq!([(), ()].type_size(), 0);
157 /// ```
158 fn type_size(self) -> usize {
159 core::mem::size_of::<Self>()
160 }
161
162 /// Consumes `self`,
163 /// returns the name of its type as a string slice and the receiver `self`.
164 ///
165 /// # Examples
166 ///
167 /// ```
168 /// use aoko::no_std::functions::ext::*;
169 ///
170 /// assert_eq!("".type_name_with_value().0, "&str");
171 /// assert_eq!("s".type_name_with_value().1, "s");
172 /// assert_eq!((&"").type_name_with_value().0, "&&str");
173 /// ```
174 fn type_name_with_value(self) -> (&'static str, Self) {
175 (core::any::type_name::<Self>(), self)
176 }
177
178 /// Consumes `self`,
179 /// returns the size of its type in number and the receiver `self`.
180 ///
181 /// # Examples
182 ///
183 /// ```
184 /// use aoko::no_std::functions::ext::*;
185 ///
186 /// assert_eq!(().type_size_with_value().0, 0);
187 /// assert_eq!(().type_size_with_value().1, ());
188 /// assert_eq!((&()).type_size_with_value().0, 8);
189 /// assert_eq!([(), ()].type_size_with_value().0, 0);
190 /// ```
191 fn type_size_with_value(self) -> (usize, Self) {
192 (core::mem::size_of::<Self>(), self)
193 }
194
195 /// Returns `Some(self)` if it satisfies the given predicate function,
196 /// or `None` if it doesn't.
197 ///
198 /// # Examples
199 ///
200 /// ```
201 /// use aoko::no_std::functions::ext::*;
202 ///
203 /// assert_eq!(Some("Hello"), "Hello".if_take(|s| s.starts_with("Hel")));
204 /// assert_eq!(None, "Hello".if_take(|s| s.starts_with("Wor")));
205 /// ```
206 fn if_take(self, f: impl FnOnce(&Self) -> bool) -> Option<Self> {
207 self.if_not_then(|x| Not::not.compose(f)(x), |s| s)
208 }
209
210 /// Returns `Some(self)` if it doesn't satisfy the given predicate function,
211 /// or `None` if it does.
212 ///
213 /// # Examples
214 ///
215 /// ```
216 /// use aoko::no_std::functions::ext::*;
217 ///
218 /// assert_eq!(None, "Hello".if_not_take(|s| s.starts_with("Hel")));
219 /// assert_eq!(Some("Hello"), "Hello".if_not_take(|s| s.starts_with("Wor")));
220 /// ```
221 fn if_not_take(self, f: impl FnOnce(&Self) -> bool) -> Option<Self> {
222 self.if_take(|x| Not::not.compose(f)(x))
223 }
224}
225
226impl<T> AnyExt for T {}
227
228/// This trait is to implement some extension functions for `bool` type.
229pub trait BoolExt<R> {
230 fn if_true(self, value: R) -> Option<R>;
231 fn if_false(self, value: R) -> Option<R>;
232 fn then_false(self, f: impl FnOnce() -> R) -> Option<R>;
233}
234
235impl<R> BoolExt<R> for bool {
236 /// Chainable `if`, returns `Some(value)` when the condition is `true`
237 ///
238 /// # Examples
239 ///
240 /// ```
241 /// use aoko::no_std::functions::ext::*;
242 ///
243 /// let s = "Hello World";
244 /// assert_eq!(Some("lo Wo"), s.starts_with("Hel").if_true(&s[3..8]));
245 /// assert_eq!(None, s.starts_with("Wor").if_true(&s[3..8]));
246 /// ```
247 fn if_true(self, value: R) -> Option<R> {
248 self.if_not_then(|s| s.not(), |_| value)
249 }
250
251 /// Chainable `if`, returns `Some(value)` when the condition is `false`
252 ///
253 /// # Examples
254 ///
255 /// ```
256 /// use aoko::no_std::functions::ext::*;
257 ///
258 /// let s = "Hello World";
259 /// assert_eq!(None, s.starts_with("Hel").if_false(&s[3..8]));
260 /// assert_eq!(Some("lo Wo"), s.starts_with("Wor").if_false(&s[3..8]));
261 /// ```
262 fn if_false(self, value: R) -> Option<R> {
263 self.if_not_then(|s| *s, |_| value)
264 }
265
266 /// Returns `Some(f())` if the receiver is `false`, or `None` otherwise
267 ///
268 /// # Examples
269 ///
270 /// ```
271 /// use aoko::no_std::functions::ext::*;
272 ///
273 /// let s = "Hello World";
274 ///
275 /// // then:
276 /// assert_eq!(Some("lo Wo"), s.starts_with("Hel").then(|| &s[3..8]));
277 /// assert_eq!(None, s.starts_with("Wor").then(|| &s[3..8]));
278 ///
279 /// // then_false:
280 /// assert_eq!(None, s.starts_with("Hel").then_false(|| &s[3..8]));
281 /// assert_eq!(Some("lo Wo"), s.starts_with("Wor").then_false(|| &s[3..8]));
282 /// ```
283 fn then_false(self, f: impl FnOnce() -> R) -> Option<R> {
284 self.if_not_then(|s| *s, |_| f())
285 }
286}
287
288/// This trait is to implement some extension functions for `[T]` type.
289pub trait ArrExt {
290 fn swap_xor(self, i: usize, j: usize) -> Self;
291}
292
293impl<T> ArrExt for &mut [T] where T: BitXorAssign<T> + Copy {
294 /// Swaps two elements in a slice.
295 ///
296 /// # Parameters
297 ///
298 /// * i - The index of the first element
299 /// * j - The index of the second element
300 ///
301 /// # Panics
302 ///
303 /// Panics if `i` or `j` are out of bounds.
304 ///
305 /// # Examples
306 ///
307 /// ```
308 /// use aoko::no_std::functions::ext::*;
309 ///
310 /// let mut v = [0, 1, 2, 3, 4];
311 /// v.swap_xor(1, 3);
312 /// assert!(v == [0, 3, 2, 1, 4]);
313 /// ```
314 ///
315 /// # Principles
316 ///
317 /// * a = 甲, b = 乙
318 ///
319 /// * a = a ^ b => a = 甲 ^ 乙, b = 乙
320 /// * b = a ^ b => a = 甲 ^ 乙, b = 甲 ^ (乙 ^ 乙) = 甲 ^ 0 = 甲
321 /// * a = a ^ b => a = 甲 ^ 乙 ^ 甲 = 甲 ^ 甲 ^ 乙 = 0 ^ 乙 = 乙
322 fn swap_xor(self, i: usize, j: usize) -> Self {
323 self.tap_mut(|s| if i != j {
324 s[i] ^= s[j];
325 s[j] ^= s[i];
326 s[i] ^= s[j];
327 })
328 }
329}
330
331pub trait StrExt {
332 fn split_not_empty_and_join(self, split: &str, join: &str) -> String;
333 fn wildcard_match(self, pattern_text: &str) -> bool;
334}
335
336impl StrExt for &str {
337 fn split_not_empty_and_join(self, split: &str, join: &str) -> String {
338 self.split(split).filter(|s| s.bytes().next().is_some()).join(join)
339 }
340
341 /// https://gist.github.com/mo-xiaoming/9fb87da16d6ef459e1b94c16055b9978
342 ///
343 /// # Examples
344 ///
345 /// ```
346 /// use std::ops::Not;
347 /// use aoko::{asserts, no_std::functions::ext::*};
348 ///
349 /// asserts! {
350 /// "abc".wildcard_match("abc");
351 /// "a0c".wildcard_match("abc*").not();
352 /// "mississippi".wildcard_match("mississipp**");
353 /// "mississippi".wildcard_match("mississippi*");
354 /// "mississippi.river".wildcard_match("*.*");
355 /// "mississippi.river".wildcard_match("*ip*");
356 /// "mississippi.river".wildcard_match("m*i*.*r");
357 /// "mississippi.river".wildcard_match("m*x*.*r").not();
358 /// }
359 /// ```
360 fn wildcard_match(self, pattern: &str) -> bool {
361 struct AfterWildcard {
362 plain_idx: usize,
363 pattern_idx: usize,
364 }
365 // it is None if there are no prev wildcard
366 // if there were, then `plain_idx` stores *next* index in plain text that wildcard supposes to match
367 // `pattern_idx` stores *next* index right after the wildcard
368 // when they first assigned
369 // latter they become to be the next possible non matches
370 // anything pre these two considered match
371 let mut after_wildcard: Option<AfterWildcard> = None;
372
373 // current indices moving in two strings
374 let mut cur_pos_plain_text = 0_usize;
375 let mut cur_pos_pattern_text = 0_usize;
376
377 loop {
378 // current chars in two strings
379 let plain_c = self.chars().nth(cur_pos_plain_text);
380 let pattern_c = pattern.chars().nth(cur_pos_pattern_text);
381
382 if plain_c.is_none() {
383 // plain text ends
384 match pattern_c {
385 None => return true, // pattern text ends as well, happy ending
386 Some('*') => // since we make wildcard matches non-eager
387 // go back to use `after_wildcard` only make it less possible to match
388 // matches if pattern only have '*' till the end
389 return pattern[cur_pos_pattern_text..].chars().all(|e| e == '*'),
390
391 Some(w) => {
392 // go back to last wildcard and try next possible char in plain text
393 let Some(AfterWildcard { ref mut plain_idx, pattern_idx }) = after_wildcard else {
394 // if no prev wildcard exists, then that's it, no match
395 return false;
396 };
397 // move `plain_idx` in `after_wildcard` to the next position of `w` in plain text
398 // any positions before that is impossible to match the pattern text
399 let Some(i) = self[*plain_idx..].chars().position(|c| c == w) else {
400 // if `w` doesn't even exists in plain text, then give up
401 return false;
402 };
403 *plain_idx = i;
404 cur_pos_plain_text = *plain_idx;
405 cur_pos_pattern_text = pattern_idx;
406 continue;
407 }
408 }
409 } else if plain_c != pattern_c {
410 if pattern_c == Some('*') {
411 // skip '*'s, one is as good as many
412 let Some(i) = pattern[cur_pos_pattern_text..].chars().position(|e| e != '*') else {
413 // even better, pattern text ends with a '*', which matches everything
414 return true;
415 };
416 cur_pos_pattern_text += i;
417
418 // pattern text doesn't end with this '*', then find next non '*' char
419 let w = pattern.chars().nth(cur_pos_pattern_text).unwrap();
420 // char in pattern text does exist in plain text
421 let Some(i) = self[cur_pos_plain_text..].chars().position(|c| c == w) else {
422 // otherwise, we cannot match
423 return false;
424 };
425 // update both positions
426 after_wildcard.replace(AfterWildcard {
427 plain_idx: i,
428 pattern_idx: cur_pos_pattern_text,
429 });
430 continue;
431 }
432 let Some(AfterWildcard { pattern_idx, .. }) = after_wildcard else {
433 return false;
434 };
435 // go back to last wildcard
436 if pattern_idx != cur_pos_pattern_text {
437 cur_pos_pattern_text = pattern_idx;
438 // matches this char, move pattern idx forward
439 if pattern.chars().nth(cur_pos_pattern_text) == plain_c {
440 cur_pos_pattern_text += 1;
441 }
442 }
443 // try next plain text char anyway, current one gets swallowed by '*'
444 // or by a matching char in pattern text
445 cur_pos_plain_text += 1;
446 continue;
447 } else {
448 cur_pos_plain_text += 1;
449 cur_pos_pattern_text += 1;
450 }
451 }
452 }
453}
454
455/// This trait is to implement some extension functions for `&[u8]` and `Vec<u8>` type.
456pub trait Utf8Ext {
457 fn to_str(&self) -> Result<&str, Utf8Error>;
458 fn to_str_lossy(&self) -> Cow<str>;
459}
460
461impl Utf8Ext for [u8] {
462 /// Converts a slice of bytes to a string slice.
463 ///
464 /// # Examples
465 ///
466 /// ```
467 /// use aoko::no_std::functions::ext::*;
468 ///
469 /// assert_eq!("💖", [240, 159, 146, 150].to_str().unwrap());
470 /// ```
471 fn to_str(&self) -> Result<&str, Utf8Error> {
472 str::from_utf8(self)
473 }
474
475 /// Converts a slice of bytes to a string, including invalid characters.
476 ///
477 /// # Examples
478 ///
479 /// ```
480 /// use aoko::{assert_eqs, no_std::functions::ext::*};
481 ///
482 /// assert_eqs! {
483 /// "💖", [240, 159, 146, 150].to_str_lossy();
484 /// "Hello �World", b"Hello \xF0\x90\x80World".to_str_lossy();
485 /// }
486 ///
487 /// ```
488 fn to_str_lossy(&self) -> Cow<str> {
489 String::from_utf8_lossy(self)
490 }
491}
492
493/// This trait is to implement some extension functions for `u128` type.
494pub trait U128Ext {
495 fn fmt_size_from(self, unit: char) -> String;
496}
497
498impl U128Ext for u128 {
499 /// Human readable storage unit.
500 ///
501 /// # Examples
502 ///
503 /// ```
504 /// use aoko::no_std::functions::ext::*;
505 ///
506 /// assert_eq!(String::from("32.0 G"), 33554432.fmt_size_from('K'));
507 /// ```
508 fn fmt_size_from(self, unit: char) -> String {
509 let units = ['B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z'];
510 let mut size = self as f64;
511 let mut counter = 0;
512
513 while size >= 1024.0 {
514 size /= 1024.0;
515 counter += 1;
516 }
517
518 for (i, &c) in units.iter().enumerate() {
519 if c == unit {
520 counter += i;
521 break;
522 }
523 }
524
525 format!("{:.1} {}", size, units.get(counter).unwrap_or_else(|| panic!("memory unit out of bounds")))
526 }
527}
528
529/// This trait is to implement some extension functions for `Option<T>` type.
530pub trait OptionExt<T> {
531 fn or_else_some(self, f: impl FnOnce() -> T) -> Self;
532 fn apply<R>(self, f: Option<impl FnMut(T) -> R>) -> Option<R>;
533}
534
535impl<T> OptionExt<T> for Option<T> {
536 /// This function is similar to `or_else`,
537 /// but convert closure result to `Some` automatically.
538 ///
539 /// # Examples
540 ///
541 /// ``` rust
542 /// use aoko::no_std::functions::ext::*;
543 ///
544 /// assert_eq!(Some(0), None::<u8>.or_else_some(|| 0));
545 /// ```
546 fn or_else_some(self, f: impl FnOnce() -> T) -> Self {
547 match self {
548 Some(_) => self,
549 None => f().into_some()
550 }
551 }
552
553 /// # Examples
554 ///
555 /// ```
556 /// use std::ops::Not;
557 /// use aoko::{assert_eqs, no_std::functions::{fun::s, ext::*}};
558 ///
559 /// assert_eqs! {
560 /// Some(1), Some(0).apply(Some(|x| x + 1));
561 /// Some(true), Some(false).apply(Some(|x: bool| x.not()));
562 /// Some(s("abcd")), Some(s("ab")).apply(Some(|x| x + "cd"));
563 /// }
564 /// ```
565 fn apply<R>(self, f: Option<impl FnMut(T) -> R>) -> Option<R> {
566 Maybe::apply(self, f)
567 }
568}
569
570/// This trait is to implement some extension functions for `Result<T, E>` type.
571pub trait ResultExt<T, E> {
572 fn zip<U>(self, other: Result<U, E>) -> Result<(T, U), E>;
573 fn apply<U>(self, f: Result<impl FnMut(T) -> U, E>) -> Result<U, E>;
574}
575
576impl<T, E> ResultExt<T, E> for Result<T, E> {
577 /// Zips `self` with another `Result`.
578 ///
579 /// If `self` is `Ok(s)` and `other` is `Ok(o)`, this method returns `Ok((s, o))`.
580 /// Otherwise, `Err` is returned.
581 ///
582 /// # Examples
583 ///
584 /// ```
585 /// use aoko::{assert_eqs, no_std::functions::ext::*};
586 ///
587 /// let x = Ok(1);
588 /// let y = Ok("hi");
589 /// let z = Err::<u8, _>(());
590 ///
591 /// assert_eqs! {
592 /// x.zip(y), Ok((1, "hi"));
593 /// x.zip(z), Err(());
594 /// }
595 /// ```
596 fn zip<U>(self, other: Result<U, E>) -> Result<(T, U), E> {
597 match (self, other) {
598 (Ok(a), Ok(b)) => (a, b).into_ok(),
599 (Err(e), _) | (_, Err(e)) => e.into_err(),
600 }
601 }
602
603 /// # Examples
604 ///
605 /// ```
606 /// use std::ops::Not;
607 /// use aoko::{assert_eqs, no_std::functions::{fun::s, ext::*}};
608 ///
609 /// let mut f = Ok(|x| x + "cd");
610 /// f = Err(());
611 ///
612 /// assert_eqs! {
613 /// Ok::<_, ()>(0), Ok(0).apply(Ok(|x| x / 1));
614 /// Err(-1), Err(-1).apply(Ok(|x: bool| x.not()));
615 /// Err(()), Ok(s("ab")).apply(f);
616 /// }
617 /// ```
618 fn apply<U>(self, f: Result<impl FnMut(T) -> U, E>) -> Result<U, E> {
619 Either::apply(self, f)
620 }
621}
622
623pub trait VecExt<T> {
624 fn apply<U>(self, f: Vec<impl FnMut(T) -> U>) -> Vec<U>;
625}
626
627impl<T> VecExt<T> for Vec<T> {
628 /// Applies the function to the element.
629 ///
630 /// # Examples
631 ///
632 /// ```
633 /// use aoko::no_std::functions::ext::*;
634 ///
635 /// let v = vec![2, 4, 6];
636 /// let f = Vec::from([|x| x + 1, |y| y * 2, |z| z / 3]);
637 ///
638 /// assert_eq!(v.apply(f), vec![3, 8, 2]);
639 /// ```
640 fn apply<U>(self, f: Vec<impl FnMut(T) -> U>) -> Vec<U> {
641 Vector::apply(self, f)
642 }
643}
644
645/// This trait is to implement some extension functions with currying two parameters.
646pub trait Curry<'a, P1, P2, R> {
647 fn curryl(self) -> impl FnOnce(P1) -> Box<dyn FnOnce(P2) -> R + 'a>;
648 fn curryr(self) -> impl FnOnce(P2) -> Box<dyn FnOnce(P1) -> R + 'a>;
649}
650
651impl<'a, P1: 'a, P2: 'a, R, F> Curry<'a, P1, P2, R> for F where F: FnOnce(P1, P2) -> R + 'a {
652 /// Two parameters, currying from left to right.
653 ///
654 /// # Examples
655 ///
656 /// ```
657 /// use aoko::no_std::functions::ext::*;
658 ///
659 /// fn sub(a: u8, b: u8) -> u8 { a - b }
660 /// let c1 = sub.curryl();
661 /// assert_eq!(c1(3)(2), 1);
662 /// ```
663 fn curryl(self) -> impl FnOnce(P1) -> Box<dyn FnOnce(P2) -> R + 'a> {
664 |p1| (|p2| self(p1, p2)).into_box()
665 }
666
667 /// Two parameters, currying from right to left.
668 ///
669 /// # Examples
670 ///
671 /// ```
672 /// use aoko::no_std::functions::ext::*;
673 ///
674 /// fn sub(a: u8, b: u8) -> u8 { a - b }
675 /// let cu = sub.curryr();
676 /// assert_eq!(cu(2)(3), 1);
677 /// ```
678 fn curryr(self) -> impl FnOnce(P2) -> Box<dyn FnOnce(P1) -> R + 'a> {
679 |p2| (|p1| self(p1, p2)).into_box()
680 }
681}
682
683/// This trait is to implement some extension functions whose type is `FnOnce`.
684pub trait FnOnceExt<T, U, R> {
685 fn combine(self, g: impl FnOnce(U) -> R) -> impl FnOnce(T) -> R;
686 fn compose(self, g: impl FnOnce(R) -> T) -> impl FnOnce(R) -> U;
687}
688
689impl<T, U, R, F> FnOnceExt<T, U, R> for F where F: FnOnce(T) -> U {
690 /// Combining two functions.
691 ///
692 /// # Examples
693 ///
694 /// ```
695 /// use aoko::no_std::functions::{ext::*, fun::s};
696 ///
697 /// fn inc(arr: &[u8]) -> Vec<u8> { arr.iter().map(|byte| byte + 1).collect() }
698 /// fn sum(v: Vec<u8>) -> u8 { v.iter().sum() }
699 /// fn to_string(x: u8) -> String { x.to_string() }
700 ///
701 /// let func = inc.combine(sum).combine(to_string);
702 /// assert_eq!(s("45"), func(&[0, 1, 2, 3, 4, 5, 6, 7, 8]));
703 /// ```
704 fn combine(self, g: impl FnOnce(U) -> R) -> impl FnOnce(T) -> R {
705 |x| x.pipe(self).pipe(g) // |x| g(self(x))
706 }
707
708 /// Combining two functions in reverse order.
709 ///
710 /// # Examples
711 ///
712 /// ```
713 /// use aoko::no_std::functions::{ext::*, fun::s};
714 ///
715 /// fn inc(arr: &[u8]) -> Vec<u8> { arr.iter().map(|byte| byte + 1).collect() }
716 /// fn sum(v: Vec<u8>) -> u8 { v.iter().sum() }
717 /// fn to_string(x: u8) -> String { x.to_string() }
718 ///
719 /// let func = to_string.compose(sum).compose(inc);
720 /// assert_eq!(s("45"), func(&[0, 1, 2, 3, 4, 5, 6, 7, 8]));
721 /// ```
722 fn compose(self, g: impl FnOnce(R) -> T) -> impl FnOnce(R) -> U {
723 g.combine(self) // |x| self(g(x))
724 }
725}