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}