1
2use fnv::FnvHasher;
3use std::any::{Any, TypeId};
4use std::collections::HashMap;
5use std::hash::{Hash, Hasher};
6use thiserror::Error;
7use uuid::Uuid;
8
9pub struct Exchange<I, O, M>
24where
25 I: Send + Sync,
26 O: Send + Sync,
27 M: Send + Sync,
28{
29 uuid: Uuid,
30 metadata: Option<M>,
31 input: Option<I>,
32 output: Option<O>,
33 input_listeners: Vec<Callback<I>>,
34 output_listeners: Vec<Callback<O>>,
35 attachments: Attachments,
36}
37
38impl<I, O, M> Exchange<I, O, M>
39where
40 I: Send + Sync,
41 O: Send + Sync,
42 M: Send + Sync,
43{
44 pub fn new() -> Self {
62 Self {
63 uuid: Uuid::new_v4(),
64 metadata: None,
65 input: None,
66 output: None,
67 input_listeners: Vec::new(),
68 output_listeners: Vec::new(),
69 attachments: Attachments::new(),
70 }
71 }
72
73 pub fn new_with_uuid(uuid: Uuid) -> Self {
91 Self {
92 uuid,
93 metadata: None,
94 input: None,
95 output: None,
96 input_listeners: Vec::new(),
97 output_listeners: Vec::new(),
98 attachments: Attachments::new(),
99 }
100 }
101
102 pub fn set_metadata(&mut self, metadata: M) {
107 self.metadata = Some(metadata);
108 }
109
110 pub fn metadata(&self) -> Result<&M, ExchangeError> {
120 match &self.metadata {
121 None => Err(ExchangeError::read_error(
122 &self.uuid,
123 "Metadata has not been set",
124 )),
125 Some(metadata) => Ok(metadata),
126 }
127 }
128
129 pub fn attachments(&self) -> &Attachments {
131 &self.attachments
132 }
133
134 pub fn attachments_mut(&mut self) -> &mut Attachments {
136 &mut self.attachments
137 }
138
139 pub fn add_input_listener(
145 &mut self,
146 callback: impl FnMut(&mut I, &mut Attachments) + Send + Sync + 'static,
147 ) {
148 self.input_listeners.push(Callback::new(callback));
149 }
150
151 pub fn add_output_listener(
157 &mut self,
158 callback: impl FnMut(&mut O, &mut Attachments) + Send + Sync + 'static,
159 ) {
160 self.output_listeners.push(Callback::new(callback));
161 }
162
163 pub fn uuid(&self) -> &Uuid {
165 &self.uuid
166 }
167
168 pub fn set_input(&mut self, input: I) {
170 self.input = Some(input);
171 }
172
173 pub async fn input(&self) -> Result<&I, ExchangeError> {
175 match &self.input {
176 Some(val) => Ok(val),
177 None => Err(ExchangeError::read_error(&self.uuid, "No input available")),
178 }
179 }
180
181 pub async fn input_mut(&mut self) -> Result<&mut I, ExchangeError> {
183 match &mut self.input {
184 Some(val) => Ok(val),
185 None => Err(ExchangeError::read_error(&self.uuid, "No input available"))
186 }
187 }
188
189 pub async fn take_input(&mut self) -> Result<I, ExchangeError> {
191 match self.input.take() {
192 Some(mut val) => {
193 for mut callback in &mut self.input_listeners.drain(..) {
194 callback.invoke(&mut val, &mut self.attachments);
195 }
196 Ok(val)
197 }
198 None => Err(ExchangeError::take_error(
199 &self.uuid,
200 "No input available to take",
201 )),
202 }
203 }
204
205 pub fn set_output(&mut self, output: O) {
207 self.output = Some(output);
208 }
209
210 pub async fn output(&self) -> Result<&O, ExchangeError> {
212 match &self.output {
213 Some(val) => Ok(val),
214 None => Err(ExchangeError::read_error(&self.uuid, "No output available")),
215 }
216 }
217
218 pub async fn output_mut(&mut self) -> Result<&mut O, ExchangeError> {
220 match &mut self.output {
221 Some(val) => Ok(val),
222 None => Err(ExchangeError::read_error(&self.uuid, "No output available")),
223 }
224 }
225
226 pub async fn take_output(&mut self) -> Result<O, ExchangeError> {
228 match self.output.take() {
229 Some(mut val) => {
230 for mut callback in &mut self.output_listeners.drain(..) {
232 callback.invoke(&mut val, &mut self.attachments);
233 }
234 Ok(val)
235 }
236 None => Err(ExchangeError::take_error(
237 &self.uuid,
238 "No output available to take",
239 )),
240 }
241 }
242
243 pub fn has_input(&self) -> bool {
245 self.input.is_some()
246 }
247
248 pub fn has_output(&self) -> bool {
250 self.output.is_some()
251 }
252}
253
254pub struct Attachments {
255 attachments: HashMap<AttachmentKey, Box<dyn Any + Send + Sync>, fnv::FnvBuildHasher>,
256}
257
258impl Attachments {
259 pub fn new() -> Self {
261 Self {
262 attachments: HashMap::with_hasher(fnv::FnvBuildHasher::default()),
263 }
264 }
265
266 pub fn add<K>(&mut self, key: impl AsRef<str>, value: K)
281 where
282 K: Send + Sync + 'static,
283 {
284 let type_id = TypeId::of::<K>();
285 self.attachments
286 .insert(AttachmentKey::new(key, type_id), Box::new(value));
287 }
288
289 pub fn get<K>(&self, key: impl AsRef<str>) -> Option<&K>
302 where
303 K: Send + 'static,
304 {
305 let type_id = TypeId::of::<K>();
306 if let Some(option_any) = self.attachments.get(&AttachmentKey::new(key, type_id)) {
307 option_any.downcast_ref::<K>()
308 } else {
309 None
310 }
311 }
312
313 pub fn get_mut<K>(&mut self, key: impl AsRef<str>) -> Option<&mut K>
315 where
316 K: Send + 'static,
317 {
318 let type_id = TypeId::of::<K>();
319 if let Some(option_any) = self.attachments.get_mut(&AttachmentKey::new(key, type_id)) {
320 option_any.downcast_mut::<K>()
321 } else {
322 None
323 }
324 }
325}
326
327#[derive(Error, Debug)]
328pub enum ExchangeError {
329 #[error("Exchange '{uuid}' has already been completed")]
330 Completed { uuid: Uuid },
331
332 #[error("Read error occurred for exchange '{uuid}'. {message}")]
333 Read { uuid: Uuid, message: String },
334
335 #[error("Take error occurred for exchange '{uuid}'. {message}")]
336 Take { uuid: Uuid, message: String },
337
338 #[error("Callback error occurred for exchange '{uuid}'. {message}")]
339 Callback { uuid: Uuid, message: String },
340}
341
342impl ExchangeError {
343 #[inline]
344 pub const fn exchange_completed(uuid: &Uuid) -> Self {
345 ExchangeError::Completed { uuid: *uuid }
346 }
347
348 #[inline]
349 pub fn read_error(uuid: &Uuid, msg: impl Into<String>) -> Self {
350 ExchangeError::Read {
351 uuid: *uuid,
352 message: msg.into(),
353 }
354 }
355
356 #[inline]
357 pub(crate) fn take_error(uuid: &Uuid, msg: impl Into<String>) -> Self {
358 ExchangeError::Take {
359 uuid: *uuid,
360 message: msg.into(),
361 }
362 }
363
364 #[inline]
365 pub(crate) fn callback_error(uuid: &Uuid, msg: impl Into<String>) -> Self {
366 ExchangeError::Callback {
367 uuid: *uuid,
368 message: msg.into(),
369 }
370 }
371}
372
373#[derive(PartialOrd, PartialEq, Hash, Eq)]
374pub struct AttachmentKey {
375 key_hash: u64,
376 type_hash: u64,
377}
378
379impl AttachmentKey {
380 pub fn new(key: impl AsRef<str>, type_id: TypeId) -> Self {
381 let key = key.as_ref();
382 let mut key_hasher = FnvHasher::default();
383 key.hash(&mut key_hasher);
384 let key_hash = key_hasher.finish();
385
386 let mut type_hasher = FnvHasher::default();
387 type_id.hash(&mut type_hasher);
388 let type_hash = type_hasher.finish();
389
390 Self {
391 key_hash,
392 type_hash,
393 }
394 }
395}
396
397pub struct Callback<T> {
398 callback: Box<dyn FnMut(&mut T, &mut Attachments) + Send + Sync>,
399}
400
401impl<T> Callback<T>
402where
403 T: Send,
404{
405 pub fn new(callback: impl FnMut(&mut T, &mut Attachments) + Send + Sync + 'static) -> Self {
406 Self {
407 callback: Box::new(callback),
408 }
409 }
410
411 pub fn invoke(&mut self, write: &mut T, attachments: &mut Attachments) {
412 (self.callback)(write, attachments);
413 }
414}
415
416#[cfg(test)]
417mod test {
418 use super::*;
419 use crate::exchange::Attachments;
420 use hyper::body::Bytes;
421
422 struct TestStruct;
423
424 #[test]
425 fn test_attachments() {
426 let mut attachments = Attachments::new();
427 let key1 = "test_key1";
428 let key2 = "test_key2";
429 let key3 = "test_key3";
430 let key4 = "test_key4";
431 {
432 attachments.add::<u64>(key1, 1);
433 attachments.add::<String>(key2, String::from("test"));
434 attachments.add::<bool>(key3, true);
435 let test_struct = TestStruct;
436 attachments.add::<TestStruct>(key4, test_struct);
437 }
438
439 {
440 assert!(attachments.get::<u64>(key1).is_some());
441 assert!(attachments.get::<String>(key2).is_some());
442 assert!(attachments.get::<bool>(key3).is_some());
443 assert!(attachments.get::<TestStruct>(key4).is_some());
444 }
445 }
446
447 #[tokio::test]
448 async fn test_unified_exchange_buffered() {
449 let mut exchange: Exchange<Bytes, Bytes, ()> = Exchange::new();
450
451 exchange.set_input(Bytes::from("test input"));
453 assert!(exchange.has_input());
454
455 exchange.set_output(Bytes::from("test output"));
457 assert!(exchange.has_output());
458
459 let output = exchange.take_output().await.unwrap();
460 assert_eq!(output, Bytes::from("test output"));
461 }
462
463 #[tokio::test]
464 async fn test_unified_exchange_callbacks() {
465 let mut exchange: Exchange<Bytes, Bytes, ()> = Exchange::new();
466
467 exchange.add_input_listener(|input: &mut Bytes, _| {
468 let mut new_data = b"prefix:".to_vec();
469 new_data.extend_from_slice(input);
470 *input = Bytes::from(new_data);
471 });
472
473 exchange.set_input(Bytes::from("test"));
474 let input = exchange.take_input().await.unwrap();
475 assert_eq!(input, Bytes::from("prefix:test"));
476 }
477
478 #[tokio::test]
479 async fn test_unified_exchange_metadata() {
480 let mut exchange: Exchange<(), (), String> = Exchange::new();
481
482 exchange.set_metadata("test metadata".to_string());
483 let metadata = exchange.metadata().unwrap();
484 assert_eq!(metadata, "test metadata");
485 }
486}