maycoon_core/tasks/
fetcher.rs1use crate::tasks::runner;
2use crate::tasks::task::Task;
3
4pub struct Fetcher<I: Send + 'static, O> {
14 task: Option<Box<dyn Task<I>>>,
15 factory: Box<dyn Fn(Option<I>) -> O>,
16 value: Option<O>,
17}
18
19impl<I: Send + 'static, O> Fetcher<I, O> {
20 #[inline(always)]
22 pub const fn new(
23 task: Box<dyn Task<I>>,
24 factory: Box<dyn Fn(Option<I>) -> O + 'static>,
25 ) -> Self {
26 Self {
27 task: Some(task),
28 factory,
29 value: None,
30 }
31 }
32
33 #[inline(always)]
38 pub fn spawn(
39 future: impl Future<Output = I> + Send + 'static,
40 factory: impl Fn(Option<I>) -> O + 'static,
41 ) -> Self {
42 let runner = runner();
43 let task = runner.spawn(future);
44
45 Self::new(task, Box::new(factory))
46 }
47
48 #[inline(always)]
53 #[cfg(native)]
54 pub fn spawn_blocking(
55 func: impl Fn() -> I + Send + 'static,
56 factory: impl Fn(Option<I>) -> O + 'static,
57 ) -> Self {
58 let runner = runner();
59 let task = runner.spawn_blocking(func);
60
61 Self::new(task, Box::new(factory))
62 }
63
64 #[inline(always)]
68 pub const fn value_mut(&mut self) -> Option<&mut O> {
69 self.value.as_mut()
70 }
71
72 #[inline(always)]
76 pub const fn value_ref(&self) -> Option<&O> {
77 self.value.as_ref()
78 }
79
80 #[inline(always)]
85 pub fn is_ready(&self) -> bool {
86 self.task.as_ref().map(|t| t.is_ready()).unwrap_or(false)
87 }
88
89 #[inline(always)]
91 pub const fn is_fetched(&self) -> bool {
92 self.task.is_none() && self.value.is_some()
93 }
94
95 #[inline(always)]
100 pub fn compute(&mut self) {
101 if self.is_ready() {
102 let mut task = self.task.take().unwrap();
103 let value = task.take().unwrap();
104
105 self.value = Some((self.factory)(Some(value)));
106 } else {
107 self.value = Some((self.factory)(None));
108 }
109 }
110
111 #[inline(always)]
117 pub fn fetch(&mut self) -> &mut O {
118 if !self.is_fetched() {
119 self.compute();
120 }
121
122 self.value_mut().unwrap()
123 }
124}
125
126#[cfg(all(test, feature = "test"))]
127mod tests {
128 use crate::tasks::fetcher::Fetcher;
129 use std::time::Duration;
130
131 #[test]
132 fn test_fetcher_spawn() {
133 init();
134
135 let mut fetcher = Fetcher::spawn(
136 async { tokio::time::sleep(Duration::from_millis(10)).await },
137 |_| 1,
138 );
139
140 std::thread::sleep(Duration::from_millis(20));
141
142 assert_eq!(fetcher.fetch(), &1);
143 }
144
145 #[test]
146 fn test_fetcher_spawn_blocking() {
147 init();
148
149 let mut fetcher =
150 Fetcher::spawn_blocking(|| std::thread::sleep(Duration::from_millis(10)), |_| 1);
151
152 std::thread::sleep(Duration::from_millis(20));
153
154 assert_eq!(fetcher.fetch(), &1);
155 }
156
157 fn init() {
158 crate::tasks::try_init(crate::tasks::TaskRunner::Tokio(
159 crate::tasks::runner::tokio::TaskRunner::new(
160 false, None, None, None, None, None, None, None,
161 ),
162 ));
163 }
164}