graphitepdf_utils/
compose.rs1use std::future::Future;
2use std::pin::Pin;
3
4pub fn compose<F, G, A, B, C>(f: F, g: G) -> impl Fn(A) -> C
5where
6 F: Fn(B) -> C,
7 G: Fn(A) -> B,
8{
9 move |input| f(g(input))
10}
11
12pub fn async_compose<F, G, FutF, FutG, A, B, C>(
13 f: F,
14 g: G,
15) -> impl Fn(A) -> Pin<Box<dyn Future<Output = C>>>
16where
17 F: Fn(B) -> FutF + Copy + 'static,
18 G: Fn(A) -> FutG + Copy + 'static,
19 FutF: Future<Output = C> + 'static,
20 FutG: Future<Output = B> + 'static,
21 A: 'static,
22{
23 move |input| {
24 Box::pin(async move {
25 let intermediate = g(input).await;
26 f(intermediate).await
27 })
28 }
29}
30
31#[cfg(test)]
32mod tests {
33 use super::*;
34 use std::future::{Ready, ready};
35
36 #[test]
37 fn composes_sync_functions_right_to_left() {
38 let add_one = |value| value + 1;
39 let double = |value| value * 2;
40
41 let function = compose(double, add_one);
42
43 assert_eq!(function(5), 12);
44 }
45
46 #[test]
47 fn composes_async_functions_right_to_left() {
48 let add_async = |value| ready(value + 1);
49 let double_async = |value| -> Ready<i32> { ready(value * 2) };
50
51 let function = async_compose(double_async, add_async);
52
53 assert_eq!(pollster(function(5)), 12);
54 }
55
56 fn pollster<F>(future: F) -> F::Output
57 where
58 F: Future,
59 {
60 use std::task::{Context, Poll, Waker};
61
62 let waker = Waker::noop();
63 let mut context = Context::from_waker(waker);
64 let mut future = std::pin::pin!(future);
65
66 match future.as_mut().poll(&mut context) {
67 Poll::Ready(output) => output,
68 Poll::Pending => panic!("expected test future to complete immediately"),
69 }
70 }
71}