1use std::collections::HashMap;
2use std::hash::Hash;
3use std::ops::Deref;
4
5pub fn pipe<T>(value: T, fns: Vec<fn(T) -> T>) -> T {
6 fns.into_iter().fold(value, |v, f| f(v))
7}
8
9pub fn compose<A, B, C>(f: impl Fn(B) -> C, g: impl Fn(A) -> B) -> impl Fn(A) -> C {
10 move |x| f(g(x))
11}
12
13pub fn tap<T>(value: T, f: impl FnOnce(&T)) -> T {
14 f(&value);
15 value
16}
17
18pub fn apply<T, U>(value: T, f: impl FnOnce(T) -> U) -> U {
19 f(value)
20}
21
22pub fn or_default<T: Default>(opt: Option<T>) -> T {
23 opt.unwrap_or_default()
24}
25
26pub fn retry<T, E>(times: usize, f: impl FnMut() -> Result<T, E>) -> Result<T, E> {
27 let mut f = f;
28 let mut last_err = None;
29 for _ in 0..times {
30 match f() {
31 ok @ Ok(_) => return ok,
32 Err(e) => last_err = Some(e),
33 }
34 }
35 Err(last_err.unwrap())
36}
37
38#[cfg(feature = "random")]
39pub fn shuffle<T: Clone>(arr: &[T]) -> Vec<T> {
40 use rand::seq::SliceRandom;
41 let mut rng = rand::thread_rng();
42 let mut out: Vec<T> = arr.to_vec();
43 out.shuffle(&mut rng);
44 out
45}
46
47#[derive(Debug)]
48pub struct Lazy<T, F = fn() -> T> {
49 cell: once_cell::sync::Lazy<T, F>,
50}
51
52impl<T, F: FnOnce() -> T> Lazy<T, F> {
53 pub fn new(init: F) -> Self {
54 Self {
55 cell: once_cell::sync::Lazy::new(init),
56 }
57 }
58
59 pub fn get(&self) -> &T {
60 Deref::deref(&self.cell)
61 }
62}
63
64unsafe impl<T, F: FnOnce() -> T + Send + Sync> Send for Lazy<T, F> {}
65unsafe impl<T, F: FnOnce() -> T + Send + Sync> Sync for Lazy<T, F> {}
66
67pub fn memoize<K, R>(f: impl Fn(K) -> R) -> impl Fn(K) -> R
68where
69 K: Hash + Eq + Clone,
70 R: Clone,
71{
72 let cache = std::cell::RefCell::new(HashMap::<K, R>::new());
73 move |arg: K| {
74 let arg = arg.clone();
75 if let Some(result) = cache.borrow().get(&arg) {
76 return result.clone();
77 }
78 let result = f(arg.clone());
79 cache.borrow_mut().insert(arg, result.clone());
80 result
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn test_pipe() {
90 let result = pipe(1, vec![|x| x + 1, |x| x * 2]);
91 assert_eq!(result, 4);
92 }
93
94 #[test]
95 fn test_compose() {
96 let f = compose(|x: i32| x + 1, |x: i32| x * 2);
97 assert_eq!(f(3), 7);
98 }
99
100 #[test]
101 fn test_tap() {
102 let mut seen = false;
103 let _ = tap(42, |v| seen = *v == 42);
104 assert!(seen);
105 }
106
107 #[test]
108 fn test_apply() {
109 let result = apply(5, |x| x * 2);
110 assert_eq!(result, 10);
111 }
112
113 #[test]
114 fn test_or_default() {
115 assert_eq!(or_default(Some(42)), 42);
116 assert_eq!(or_default(None::<i32>), 0);
117 }
118
119 #[test]
120 fn test_retry_success() {
121 let result = retry(3, || Ok::<i32, i32>(42));
122 assert_eq!(result.unwrap(), 42);
123 }
124
125 #[test]
126 fn test_retry_eventual() {
127 let mut attempts = 0;
128 let result = retry(3, &mut || {
129 attempts += 1;
130 if attempts < 3 {
131 Err(1)
132 } else {
133 Ok(42)
134 }
135 });
136 assert_eq!(result.unwrap(), 42);
137 assert_eq!(attempts, 3);
138 }
139
140 #[test]
141 fn test_retry_failure() {
142 let result = retry(2, || Err::<i32, i32>(42));
143 assert!(result.is_err());
144 }
145
146 #[test]
147 fn test_lazy() {
148 let lazy: Lazy<i32, fn() -> i32> = Lazy::new(|| 42);
149 assert_eq!(*lazy.get(), 42);
150 assert_eq!(*lazy.get(), 42);
151 }
152
153 #[test]
154 fn test_memoize() {
155 let count_ptr = std::cell::Cell::new(0);
156 let memoized = memoize(move |x: i32| {
157 count_ptr.set(count_ptr.get() + 1);
158 x * 2
159 });
160 assert_eq!(memoized(5), 10);
161 assert_eq!(memoized(5), 10);
162 let _ = count_ptr;
163 }
164}