idem_handler/
exchange.rs

1use std::any::{Any, TypeId};
2use std::collections::HashMap;
3use std::fmt::{Display, Formatter};
4
5pub struct Exchange<Input, Output, Metadata> {
6    metadata: Option<Metadata>,
7    input: Option<Input>,
8    output: Option<Output>,
9    input_listeners: Vec<Callback<Input>>,
10    output_listeners: Vec<Callback<Output>>,
11    attachments: Attachments,
12}
13
14impl<Input, Output, Metadata> Exchange<Input, Output, Metadata>
15where
16    Input: Send + 'static,
17    Output: Send + 'static,
18    Metadata: Send,
19{
20    pub fn new() -> Self {
21        Self {
22            metadata: None,
23            input: None,
24            output: None,
25            input_listeners: vec![],
26            output_listeners: vec![],
27            attachments: Attachments::new(),
28        }
29    }
30
31    pub fn add_metadata(&mut self, metadata: Metadata) {
32        self.metadata = Some(metadata);
33    }
34
35    pub fn attachments(&self) -> &Attachments {
36        &self.attachments
37    }
38
39    pub fn attachments_mut(&mut self) -> &mut Attachments {
40        &mut self.attachments
41    }
42
43    pub fn add_input_listener(
44        &mut self,
45        callback: impl FnMut(&mut Input, &mut Attachments) + Send + 'static,
46    ) {
47        self.input_listeners.push(Callback::new(callback));
48    }
49
50    pub fn add_output_listener(
51        &mut self,
52        callback: impl FnMut(&mut Output, &mut Attachments) + Send + 'static,
53    ) {
54        self.output_listeners.push(Callback::new(callback));
55    }
56
57    fn execute_input_callbacks(&mut self) -> Result<(), ExchangeError> {
58        if let Some(input) = &mut self.input {
59            for mut callback in &mut self.input_listeners.drain(..) {
60                callback.invoke(input, &mut self.attachments);
61            }
62            Ok(())
63        } else {
64            Err(ExchangeError::OutputCallbackError(
65                "No input available".to_string(),
66            ))
67        }
68    }
69
70    fn execute_output_callbacks(&mut self) -> Result<(), ExchangeError> {
71        if let Some(output) = &mut self.output {
72            for mut callback in &mut self.output_listeners.drain(..) {
73                callback.invoke(output, &mut self.attachments);
74            }
75            Ok(())
76        } else {
77            Err(ExchangeError::OutputReadError(
78                "No output available".to_string(),
79            ))
80        }
81    }
82
83    pub fn save_input(&mut self, request: Input) {
84        self.input = Some(request);
85    }
86
87    pub fn input(&self) -> Result<&Input, ExchangeError> {
88        match &self.input {
89            Some(out) => Ok(out),
90            None => Err(ExchangeError::InputReadError("No input available".to_string())),
91        }
92    }
93
94    pub fn input_mut(&mut self) -> Result<&mut Input, ExchangeError> {
95        match &mut self.input {
96            Some(out) => Ok(out),
97            None => Err(ExchangeError::InputReadError("No input available".to_string())),
98        }
99    }
100
101    pub fn take_request(&mut self) -> Result<Input, ExchangeError> {
102        if let Ok(_) = self.execute_input_callbacks() {
103            self.input
104                .take()
105                .ok_or_else(|| ExchangeError::InputReadError("No input available".to_string()))
106        } else {
107            Err(ExchangeError::InputCallbackError(
108                "Input callback failed".to_string(),
109            ))
110        }
111    }
112
113    pub fn save_output(&mut self, response: Output) {
114        self.output = Some(response);
115    }
116
117    pub fn output(&self) -> Result<&Output, ExchangeError> {
118        match &self.output {
119            Some(out) => Ok(out),
120            None => Err(ExchangeError::OutputReadError(
121                "No output available".to_string(),
122            )),
123        }
124    }
125
126    pub fn output_mut(&mut self) -> Result<&mut Output, ExchangeError> {
127        match &mut self.output {
128            Some(out) => Ok(out),
129            None => Err(ExchangeError::OutputReadError(
130                "No output available".to_string(),
131            )),
132        }
133    }
134
135    pub fn take_output(&mut self) -> Result<Output, ExchangeError> {
136        if let Ok(_) = self.execute_output_callbacks() {
137            self.output
138                .take()
139                .ok_or_else(|| ExchangeError::OutputReadError("Output not available".to_string()))
140        } else {
141            Err(ExchangeError::OutputCallbackError(
142                "Output callback failed".to_string(),
143            ))
144        }
145    }
146}
147
148pub struct Attachments {
149    attachments: HashMap<(AttachmentKey, TypeId), Box<dyn Any + Send>>,
150}
151
152impl Attachments {
153    pub fn new() -> Self {
154        Self {
155            attachments: HashMap::new(),
156        }
157    }
158
159    pub fn add_attachment<K>(&mut self, key: AttachmentKey, value: Box<dyn Any + Send>)
160    where
161        K: Send + 'static,
162    {
163        let type_id = TypeId::of::<K>();
164        self.attachments.insert((key, type_id), value);
165    }
166
167    pub fn attachment<K>(&self, key: AttachmentKey) -> Option<&K>
168    where
169        K: Send + 'static,
170    {
171        let type_id = TypeId::of::<K>();
172        if let Some(option_any) = self.attachments.get(&(key, type_id)) {
173            option_any.downcast_ref::<K>()
174        } else {
175            None
176        }
177    }
178
179    pub fn attachment_mut<K>(&mut self, key: AttachmentKey) -> Option<&mut K>
180    where
181        K: Send + 'static,
182    {
183        let type_id = TypeId::of::<K>();
184        if let Some(option_any) = self.attachments.get_mut(&(key, type_id)) {
185            option_any.downcast_mut::<K>()
186        } else {
187            None
188        }
189    }
190}
191
192#[derive(Debug)]
193pub enum ExchangeError {
194    InputReadError(String),
195    InputTakeError(String),
196    OutputReadError(String),
197    OutputTakeError(String),
198    InputCallbackError(String),
199    OutputCallbackError(String),
200}
201
202impl Display for ExchangeError {
203    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
204        let (error_type, error_msg) = match self {
205            ExchangeError::InputReadError(msg) => ("InputReadError", msg),
206            ExchangeError::InputTakeError(msg) => ("InputTakeError", msg),
207            ExchangeError::OutputReadError(msg) => ("OutputReadError", msg),
208            ExchangeError::OutputTakeError(msg) => ("OutputTakeError", msg),
209            ExchangeError::InputCallbackError(msg) => ("InputCallbackError", msg),
210            ExchangeError::OutputCallbackError(msg) => ("OutputCallbackError", msg),
211        };
212        write!(f, "{}: {}", error_type, error_msg)
213    }
214}
215
216impl std::error::Error for ExchangeError {}
217
218#[derive(PartialOrd, PartialEq, Hash, Eq)]
219pub struct AttachmentKey(pub &'static str);
220
221pub struct Callback<T> {
222    callback: Box<dyn FnMut(&mut T, &mut Attachments) + Send>,
223}
224
225impl<T> Callback<T>
226where
227    T: Send + 'static,
228{
229    pub fn new(callback: impl FnMut(&mut T, &mut Attachments) + Send + 'static) -> Self {
230        Self {
231            callback: Box::new(callback),
232        }
233    }
234
235    pub fn invoke(&mut self, write: &mut T, attachments: &mut Attachments) {
236        (self.callback)(write, attachments);
237    }
238}