tc_transact/public/
helpers.rs

1use std::fmt;
2
3use futures::future;
4use safecast::{TryCastFrom, TryCastInto};
5
6use tc_error::*;
7use tc_value::TCString;
8use tcgeneric::{Id, TCPath, Tuple};
9
10use super::{
11    DeleteHandler, GetHandler, Handler, HandlerType, PostHandler, PutHandler, StateInstance,
12};
13
14pub struct EchoHandler;
15
16impl<'a, State> Handler<'a, State> for EchoHandler
17where
18    State: StateInstance,
19{
20    fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b, State::Txn, State>>
21    where
22        'b: 'a,
23    {
24        Some(Box::new(|_txn, key| {
25            Box::pin(async move { Ok(key.into()) })
26        }))
27    }
28}
29
30pub struct ErrorHandler<'a> {
31    code: &'a Id,
32}
33
34impl<'a, State> Handler<'a, State> for ErrorHandler<'a>
35where
36    State: StateInstance,
37    TCString: TryCastFrom<State>,
38    Tuple<TCString>: TryCastFrom<State>,
39{
40    fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b, State::Txn, State>>
41    where
42        'b: 'a,
43    {
44        Some(Box::new(|_txn, key| {
45            Box::pin(async move {
46                let message: TCString =
47                    key.try_cast_into(|v| TCError::unexpected(v, "an error message"))?;
48
49                if let Some(err_type) = error_type(self.code) {
50                    Err(TCError::new(err_type, message.to_string()))
51                } else {
52                    Err(TCError::not_found(self.code))
53                }
54            })
55        }))
56    }
57
58    fn post<'b>(self: Box<Self>) -> Option<PostHandler<'a, 'b, State::Txn, State>>
59    where
60        'b: 'a,
61    {
62        Some(Box::new(|_txn, mut params| {
63            Box::pin(async move {
64                let message: TCString = params.require("message")?;
65                let stack: Tuple<TCString> = params.require("stack")?;
66                params.expect_empty()?;
67
68                if let Some(err_type) = error_type(self.code) {
69                    Err(TCError::with_stack(err_type, message, stack))
70                } else {
71                    Err(TCError::not_found(self.code))
72                }
73            })
74        }))
75    }
76}
77
78impl<'a> From<&'a Id> for ErrorHandler<'a> {
79    fn from(code: &'a Id) -> Self {
80        Self { code }
81    }
82}
83
84pub struct AttributeHandler<T> {
85    attribute: T,
86}
87
88impl<'a, State, T> Handler<'a, State> for AttributeHandler<T>
89where
90    State: StateInstance + From<T>,
91    T: Clone + Send + Sync + 'a,
92{
93    fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b, State::Txn, State>>
94    where
95        'b: 'a,
96    {
97        Some(Box::new(|_txn, key| {
98            Box::pin(async move {
99                if key.is_none() {
100                    Ok(self.attribute.into())
101                } else {
102                    Err(TCError::not_found(format!("attribute {key:?}")))
103                }
104            })
105        }))
106    }
107}
108
109impl<T> From<T> for AttributeHandler<T> {
110    fn from(attribute: T) -> Self {
111        Self { attribute }
112    }
113}
114
115pub struct MethodNotAllowedHandler;
116
117impl<'a, State: StateInstance> Handler<'a, State> for MethodNotAllowedHandler {
118    fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b, State::Txn, State>>
119    where
120        'b: 'a,
121    {
122        Some(Box::new(move |_txn, _key| {
123            Box::pin(future::ready(Err(TCError::method_not_allowed(
124                HandlerType::Get,
125                TCPath::default(),
126            ))))
127        }))
128    }
129
130    fn put<'b>(self: Box<Self>) -> Option<PutHandler<'a, 'b, State::Txn, State>>
131    where
132        'b: 'a,
133    {
134        Some(Box::new(move |_txn, _key, _value| {
135            Box::pin(future::ready(Err(TCError::method_not_allowed(
136                HandlerType::Put,
137                TCPath::default(),
138            ))))
139        }))
140    }
141
142    fn post<'b>(self: Box<Self>) -> Option<PostHandler<'a, 'b, State::Txn, State>>
143    where
144        'b: 'a,
145    {
146        Some(Box::new(move |_txn, _key| {
147            Box::pin(future::ready(Err(TCError::method_not_allowed(
148                HandlerType::Post,
149                TCPath::default(),
150            ))))
151        }))
152    }
153
154    fn delete<'b>(self: Box<Self>) -> Option<DeleteHandler<'a, 'b, State::Txn>>
155    where
156        'b: 'a,
157    {
158        Some(Box::new(move |_txn, _key| {
159            Box::pin(future::ready(Err(TCError::method_not_allowed(
160                HandlerType::Delete,
161                TCPath::default(),
162            ))))
163        }))
164    }
165}
166
167pub struct SelfHandler<'a, T> {
168    subject: &'a T,
169}
170
171impl<'a, State, T> Handler<'a, State> for SelfHandler<'a, T>
172where
173    State: StateInstance + From<T>,
174    T: Clone + Send + Sync + fmt::Debug,
175{
176    fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b, State::Txn, State>>
177    where
178        'b: 'a,
179    {
180        Some(Box::new(|_txn, key| {
181            Box::pin(async move {
182                if key.is_none() {
183                    Ok(self.subject.clone().into())
184                } else {
185                    Err(TCError::not_found(format!(
186                        "attribute {:?} of {:?}",
187                        key, self.subject
188                    )))
189                }
190            })
191        }))
192    }
193}
194
195impl<'a, T> From<&'a T> for SelfHandler<'a, T> {
196    fn from(subject: &'a T) -> Self {
197        Self { subject }
198    }
199}
200
201pub struct SelfHandlerOwned<T> {
202    subject: T,
203}
204
205impl<'a, State, T> Handler<'a, State> for SelfHandlerOwned<T>
206where
207    State: StateInstance + From<T>,
208    T: Send + Sync + fmt::Debug + 'a,
209{
210    fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b, State::Txn, State>>
211    where
212        'b: 'a,
213    {
214        Some(Box::new(|_txn, key| {
215            Box::pin(async move {
216                if key.is_none() {
217                    Ok(self.subject.into())
218                } else {
219                    Err(TCError::not_found(format!(
220                        "attribute {:?} of {:?}",
221                        key, self.subject
222                    )))
223                }
224            })
225        }))
226    }
227}
228
229impl<'a, T> From<T> for SelfHandlerOwned<T> {
230    fn from(subject: T) -> Self {
231        Self { subject }
232    }
233}
234
235fn error_type(err_type: &Id) -> Option<ErrorKind> {
236    match err_type.as_str() {
237        "bad_gateway" => Some(ErrorKind::BadGateway),
238        "bad_request" => Some(ErrorKind::BadRequest),
239        "conflict" => Some(ErrorKind::Conflict),
240        "forbidden" => Some(ErrorKind::Forbidden),
241        "internal" => Some(ErrorKind::Internal),
242        "method_not_allowed" => Some(ErrorKind::MethodNotAllowed),
243        "not_found" => Some(ErrorKind::NotFound),
244        "not_implemented" => Some(ErrorKind::NotImplemented),
245        "timeout" => Some(ErrorKind::Timeout),
246        "unauthorized" => Some(ErrorKind::Unauthorized),
247        _ => None,
248    }
249}