overture_core/pipe.rs
1// Forward composition of functions.
2// Equivalent to Swift's pipe functions
3
4/// Forward composition of two functions.
5/// Equivalent to Swift's pipe<A, B, C>(_ f: @escaping (A) -> B, _ g: @escaping (B) -> C) -> (A) -> C
6pub fn pipe<A, B, C>(
7 f: impl Fn(A) -> B + 'static,
8 g: impl Fn(B) -> C + 'static,
9) -> impl Fn(A) -> C {
10 move |a| g(f(a))
11}
12
13// Helper function for pipe2 (since we don't have it in the API)
14pub fn pipe2<A, B, C, F, G>(f: F, g: G) -> impl Fn(A) -> C
15where
16 F: Fn(A) -> B + 'static,
17 G: Fn(B) -> C + 'static,
18{
19 move |a| g(f(a))
20}
21
22/// Forward composition of three functions.
23/// Equivalent to Swift's pipe<A, B, C, D>(_ f: @escaping (A) -> B, _ g: @escaping (B) -> C, _ h: @escaping (C) -> D) -> (A) -> D
24pub fn pipe3<A, B, C, D>(
25 f: impl Fn(A) -> B + 'static,
26 g: impl Fn(B) -> C + 'static,
27 h: impl Fn(C) -> D + 'static,
28) -> impl Fn(A) -> D {
29 move |a| h(g(f(a)))
30}
31
32/// Forward composition of four functions.
33/// Equivalent to Swift's pipe<A, B, C, D, E>(_ f: @escaping (A) -> B, _ g: @escaping (B) -> C, _ h: @escaping (C) -> D, _ i: @escaping (D) -> E) -> (A) -> E
34pub fn pipe4<A, B, C, D, E>(
35 f: impl Fn(A) -> B + 'static,
36 g: impl Fn(B) -> C + 'static,
37 h: impl Fn(C) -> D + 'static,
38 i: impl Fn(D) -> E + 'static,
39) -> impl Fn(A) -> E {
40 move |a| i(h(g(f(a))))
41}
42
43/// Forward composition of five functions.
44/// Equivalent to Swift's pipe<A, B, C, D, E, F>(_ f: @escaping (A) -> B, _ g: @escaping (B) -> C, _ h: @escaping (C) -> D, _ i: @escaping (D) -> E, _ j: @escaping (E) -> F) -> (A) -> F
45pub fn pipe5<A, B, C, D, E, F>(
46 f: impl Fn(A) -> B + 'static,
47 g: impl Fn(B) -> C + 'static,
48 h: impl Fn(C) -> D + 'static,
49 i: impl Fn(D) -> E + 'static,
50 j: impl Fn(E) -> F + 'static,
51) -> impl Fn(A) -> F {
52 move |a| j(i(h(g(f(a)))))
53}
54
55/// Forward composition of six functions.
56/// Equivalent to Swift's pipe<A, B, C, D, E, F, G>(_ f: @escaping (A) -> B, _ g: @escaping (B) -> C, _ h: @escaping (C) -> D, _ i: @escaping (D) -> E, _ j: @escaping (E) -> F, _ k: @escaping (F) -> G) -> (A) -> G
57pub fn pipe6<A, B, C, D, E, F, G>(
58 f: impl Fn(A) -> B + 'static,
59 g: impl Fn(B) -> C + 'static,
60 h: impl Fn(C) -> D + 'static,
61 i: impl Fn(D) -> E + 'static,
62 j: impl Fn(E) -> F + 'static,
63 k: impl Fn(F) -> G + 'static,
64) -> impl Fn(A) -> G {
65 move |a| k(j(i(h(g(f(a))))))
66}
67
68// Throwing variants (using Result for error handling)
69
70/// Forward composition of two throwing functions.
71/// Equivalent to Swift's pipe<A, B, C>(_ f: @escaping (A) throws -> B, _ g: @escaping (B) throws -> C) -> (A) throws -> C
72pub fn pipe_throwing<A, B, C, E>(
73 f: impl Fn(A) -> Result<B, E> + 'static,
74 g: impl Fn(B) -> Result<C, E> + 'static,
75) -> impl Fn(A) -> Result<C, E> {
76 move |a| f(a).and_then(|b| g(b))
77}
78
79/// Forward composition of three throwing functions.
80/// Equivalent to Swift's pipe<A, B, C, D>(_ f: @escaping (A) throws -> B, _ g: @escaping (B) throws -> C, _ h: @escaping (C) throws -> D) -> (A) throws -> D
81pub fn pipe3_throwing<A, B, C, D, E>(
82 f: impl Fn(A) -> Result<B, E> + 'static,
83 g: impl Fn(B) -> Result<C, E> + 'static,
84 h: impl Fn(C) -> Result<D, E> + 'static,
85) -> impl Fn(A) -> Result<D, E> {
86 move |a| f(a).and_then(|b| g(b)).and_then(|c| h(c))
87}
88
89/// Forward composition of four throwing functions.
90/// Equivalent to Swift's pipe<A, B, C, D, E>(_ f: @escaping (A) throws -> B, _ g: @escaping (B) throws -> C, _ h: @escaping (C) throws -> D, _ i: @escaping (D) throws -> E) -> (A) throws -> E
91pub fn pipe4_throwing<A, B, C, D, E, F>(
92 f: impl Fn(A) -> Result<B, F> + 'static,
93 g: impl Fn(B) -> Result<C, F> + 'static,
94 h: impl Fn(C) -> Result<D, F> + 'static,
95 i: impl Fn(D) -> Result<E, F> + 'static,
96) -> impl Fn(A) -> Result<E, F> {
97 move |a| {
98 f(a).and_then(|b| g(b))
99 .and_then(|c| h(c))
100 .and_then(|d| i(d))
101 }
102}
103
104/// Forward composition of five throwing functions.
105/// Equivalent to Swift's pipe<A, B, C, D, E, F>(_ f: @escaping (A) throws -> B, _ g: @escaping (B) throws -> C, _ h: @escaping (C) throws -> D, _ i: @escaping (D) throws -> E, _ j: @escaping (E) throws -> F) -> (A) throws -> F
106pub fn pipe5_throwing<A, B, C, D, E, F, G>(
107 f: impl Fn(A) -> Result<B, G> + 'static,
108 g: impl Fn(B) -> Result<C, G> + 'static,
109 h: impl Fn(C) -> Result<D, G> + 'static,
110 i: impl Fn(D) -> Result<E, G> + 'static,
111 j: impl Fn(E) -> Result<F, G> + 'static,
112) -> impl Fn(A) -> Result<F, G> {
113 move |a| {
114 f(a).and_then(|b| g(b))
115 .and_then(|c| h(c))
116 .and_then(|d| i(d))
117 .and_then(|e| j(e))
118 }
119}
120
121/// Forward composition of six throwing functions.
122/// Equivalent to Swift's pipe<A, B, C, D, E, F, G>(_ f: @escaping (A) throws -> B, _ g: @escaping (B) throws -> C, _ h: @escaping (C) throws -> D, _ i: @escaping (D) throws -> E, _ j: @escaping (E) throws -> F, _ k: @escaping (F) throws -> G) -> (A) throws -> G
123pub fn pipe6_throwing<A, B, C, D, E, F, G, H>(
124 f: impl Fn(A) -> Result<B, H> + 'static,
125 g: impl Fn(B) -> Result<C, H> + 'static,
126 h: impl Fn(C) -> Result<D, H> + 'static,
127 i: impl Fn(D) -> Result<E, H> + 'static,
128 j: impl Fn(E) -> Result<F, H> + 'static,
129 k: impl Fn(F) -> Result<G, H> + 'static,
130) -> impl Fn(A) -> Result<G, H> {
131 move |a| {
132 f(a).and_then(|b| g(b))
133 .and_then(|c| h(c))
134 .and_then(|d| i(d))
135 .and_then(|e| j(e))
136 .and_then(|f| k(f))
137 }
138}
139
140// Legacy aliases for backward compatibility
141pub use pipe_throwing as pipe_result;
142pub use pipe3_throwing as pipe_result3;
143
144// #[macro_export]
145// macro_rules! pipe_macro {
146// ($f:expr, $g:expr) => {
147// crate::pipe::pipe($f, $g)
148// };
149// ($f:expr, $g:expr, $h:expr) => {
150// crate::pipe::pipe3($f, $g, $h)
151// };
152// ($f:expr, $g:expr, $h:expr, $i:expr) => {
153// crate::pipe::pipe4($f, $g, $h, $i)
154// };
155// ($f:expr, $g:expr, $h:expr, $i:expr, $j:expr) => {
156// crate::pipe::pipe5($f, $g, $h, $i, $j)
157// };
158// ($f:expr, $g:expr, $h:expr, $i:expr, $j:expr, $k:expr) => {
159// crate::pipe::pipe6($f, $g, $h, $i, $j, $k)
160// };
161// }
162
163// #[macro_export]
164// macro_rules! pipe_result {
165// ($f:expr, $g:expr) => {
166// crate::pipe::pipe_result($f, $g)
167// };
168// ($f:expr, $g:expr, $h:expr) => {
169// crate::pipe::pipe_result3($f, $g, $h)
170// };
171// }