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}