tidepool_effect/
dispatch.rs1use crate::error::EffectError;
2use tidepool_bridge::{FromCore, ToCore};
3use tidepool_eval::value::Value;
4use tidepool_repr::DataConTable;
5use frunk::{HCons, HNil};
6
7pub struct EffectContext<'a, U = ()> {
8 table: &'a DataConTable,
9 user: &'a U,
10}
11
12impl<'a, U> EffectContext<'a, U> {
13 pub fn with_user(table: &'a DataConTable, user: &'a U) -> Self {
14 Self { table, user }
15 }
16
17 pub fn respond<T: ToCore>(&self, val: T) -> Result<Value, EffectError> {
18 val.to_value(self.table).map_err(EffectError::Bridge)
19 }
20
21 pub fn table(&self) -> &DataConTable {
22 self.table
23 }
24
25 pub fn user(&self) -> &U {
26 self.user
27 }
28}
29
30pub trait EffectHandler<U = ()> {
31 type Request: FromCore;
32 fn handle(
33 &mut self,
34 req: Self::Request,
35 cx: &EffectContext<'_, U>,
36 ) -> Result<Value, EffectError>;
37}
38
39pub trait DispatchEffect<U = ()> {
40 fn dispatch(
41 &mut self,
42 tag: u64,
43 request: &Value,
44 cx: &EffectContext<'_, U>,
45 ) -> Result<Value, EffectError>;
46}
47
48impl<U> DispatchEffect<U> for HNil {
49 fn dispatch(
50 &mut self,
51 tag: u64,
52 _request: &Value,
53 _cx: &EffectContext<'_, U>,
54 ) -> Result<Value, EffectError> {
55 Err(EffectError::UnhandledEffect { tag })
56 }
57}
58
59impl<U, H: EffectHandler<U>, T: DispatchEffect<U>> DispatchEffect<U> for HCons<H, T> {
60 fn dispatch(
61 &mut self,
62 tag: u64,
63 request: &Value,
64 cx: &EffectContext<'_, U>,
65 ) -> Result<Value, EffectError> {
66 if tag == 0 {
67 let req = H::Request::from_value(request, cx.table())?;
68 self.head.handle(req, cx)
69 } else {
70 self.tail.dispatch(tag - 1, request, cx)
71 }
72 }
73}
74
75#[cfg(feature = "async")]
78pub trait AsyncEffectHandler<U = ()>: Send {
79 type Request: FromCore + Send;
80 fn handle<'a>(
81 &'a mut self,
82 req: Self::Request,
83 cx: &'a EffectContext<'a, U>,
84 ) -> impl std::future::Future<Output = Result<Value, EffectError>> + Send + 'a;
85}
86
87#[cfg(feature = "async")]
88pub trait AsyncDispatchEffect<U = ()>: Send {
89 fn dispatch<'a>(
90 &'a mut self,
91 tag: u64,
92 request: &'a Value,
93 cx: &'a EffectContext<'a, U>,
94 ) -> impl std::future::Future<Output = Result<Value, EffectError>> + Send + 'a;
95}
96
97#[cfg(feature = "async")]
98impl<U: Sync> AsyncDispatchEffect<U> for HNil {
99 fn dispatch<'a>(
100 &'a mut self,
101 tag: u64,
102 _request: &'a Value,
103 _cx: &'a EffectContext<'a, U>,
104 ) -> impl std::future::Future<Output = Result<Value, EffectError>> + Send + 'a {
105 async move { Err(EffectError::UnhandledEffect { tag }) }
106 }
107}
108
109#[cfg(feature = "async")]
110impl<U, H, T> AsyncDispatchEffect<U> for HCons<H, T>
111where
112 U: Sync,
113 H: AsyncEffectHandler<U> + Send,
114 T: AsyncDispatchEffect<U> + Send,
115{
116 fn dispatch<'a>(
117 &'a mut self,
118 tag: u64,
119 request: &'a Value,
120 cx: &'a EffectContext<'a, U>,
121 ) -> impl std::future::Future<Output = Result<Value, EffectError>> + Send + 'a {
122 async move {
123 if tag == 0 {
124 let req = H::Request::from_value(request, cx.table())?;
125 self.head.handle(req, cx).await
126 } else {
127 self.tail.dispatch(tag - 1, request, cx).await
128 }
129 }
130 }
131}