beekeeper/bee/stock/
thunk.rs1use crate::bee::{ApplyError, Context, Worker, WorkerResult};
2use crate::boxed::BoxedFnOnce;
3use crate::panic::Panic;
4use derive_more::Debug;
5use std::marker::PhantomData;
6use std::{any, fmt};
7
8#[derive(Debug)]
10#[debug("ThunkWorker<{}>", any::type_name::<T>())]
11pub struct ThunkWorker<T>(PhantomData<T>);
12
13impl<T> Default for ThunkWorker<T> {
14 fn default() -> Self {
15 Self(PhantomData)
16 }
17}
18
19impl<T> Clone for ThunkWorker<T> {
20 fn clone(&self) -> Self {
21 Self::default()
22 }
23}
24
25impl<T: Send + fmt::Debug + 'static> Worker for ThunkWorker<T> {
26 type Input = Thunk<T>;
27 type Output = T;
28 type Error = ();
29
30 #[inline]
31 fn apply(&mut self, f: Self::Input, _: &Context<Self::Input>) -> WorkerResult<Self> {
32 Ok(f.0.call_box())
33 }
34}
35
36#[derive(Debug)]
38#[debug("FunkWorker<{}, {}>", any::type_name::<T>(), any::type_name::<E>())]
39pub struct FunkWorker<T, E>(PhantomData<T>, PhantomData<E>);
40
41impl<T, E> Default for FunkWorker<T, E> {
42 fn default() -> Self {
43 Self(PhantomData, PhantomData)
44 }
45}
46
47impl<T, E> Clone for FunkWorker<T, E> {
48 fn clone(&self) -> Self {
49 Self::default()
50 }
51}
52
53impl<T, E> Worker for FunkWorker<T, E>
54where
55 T: Send + fmt::Debug + 'static,
56 E: Send + fmt::Debug + 'static,
57{
58 type Input = Thunk<Result<T, E>>;
59 type Output = T;
60 type Error = E;
61
62 #[inline]
63 fn apply(&mut self, f: Self::Input, _: &Context<Self::Input>) -> WorkerResult<Self> {
64 f.0.call_box()
65 .map_err(|error| ApplyError::Fatal { error, input: None })
66 }
67}
68
69#[derive(Debug)]
72#[debug("PunkWorker<{}>", any::type_name::<T>())]
73pub struct PunkWorker<T>(PhantomData<T>);
74
75impl<T> Default for PunkWorker<T> {
76 fn default() -> Self {
77 Self(PhantomData)
78 }
79}
80
81impl<T> Clone for PunkWorker<T> {
82 fn clone(&self) -> Self {
83 Self::default()
84 }
85}
86
87impl<T: Send + fmt::Debug + 'static> Worker for PunkWorker<T> {
88 type Input = Thunk<T>;
89 type Output = T;
90 type Error = ();
91
92 fn apply(&mut self, f: Self::Input, _: &Context<Self::Input>) -> WorkerResult<Self> {
93 Panic::try_call_boxed(None, f.0).map_err(|payload| ApplyError::Panic {
94 input: None,
95 payload,
96 })
97 }
98}
99
100#[derive(Debug)]
102#[debug("Thunk<{}>", any::type_name::<T>())]
103pub struct Thunk<T>(Box<dyn BoxedFnOnce<Output = T> + Send>);
104
105impl<T, F: FnOnce() -> T + Send + 'static> From<F> for Thunk<T> {
106 fn from(f: F) -> Self {
107 Self(Box::new(f))
108 }
109}
110
111impl<T, E> Thunk<Result<T, E>> {
112 pub fn fallible<F: FnOnce() -> Result<T, E> + Send + 'static>(f: F) -> Self {
113 Self(Box::new(f))
114 }
115}
116
117#[cfg(test)]
118#[cfg_attr(coverage_nightly, coverage(off))]
119mod tests {
120 use super::*;
121 use crate::bee::Context;
122
123 #[test]
124 fn test_thunk() {
125 let mut worker = ThunkWorker::<u8>::default();
126 let thunk = Thunk::from(|| 5);
127 assert_eq!(5, worker.apply(thunk, &Context::empty()).unwrap());
128 }
129
130 #[test]
131 fn test_funk_ok() {
132 let mut worker = FunkWorker::<u8, String>::default();
133 let funk = Thunk::fallible(|| Ok(1));
134 assert_eq!(1, worker.apply(funk, &Context::empty()).unwrap())
135 }
136
137 #[test]
138 fn test_funk_error() {
139 let mut worker = FunkWorker::<u8, String>::default();
140 let funk = Thunk::fallible(|| Err("failure".into()));
141 let result = worker.apply(funk, &Context::empty());
142 let _error = String::from("failure");
143 assert!(matches!(
144 result,
145 Err(ApplyError::Fatal {
146 input: None,
147 error: _error
148 })
149 ));
150 }
151}