telers/extractor.rs
1//! This module contains functionality for extracting data to the handler arguments.
2//!
3//! [`Extractor`] is the main trait which need to be implemented for extracting data.
4//! If you want to use your own types as handler arguments, you need to implement this trait for them.
5//! By default, this trait is implemented for the most common middlewares, types and filters, so you can use them without any additional actions.
6//! The trait also is implemented for `Option<T>`, `Result<T, E>` where `T: Extractor`,
7//! so you can don't implement it for your types if you want to use them as optional or result arguments.
8//!
9//! # Using extensions
10//!
11//! You can use [`Extension`] to extract data from [`Extensions`] that can be easily filled in,
12//! for example in middlewares:
13//! ```rust
14//! use telers::{
15//! errors::EventErrorKind,
16//! event::{telegram::HandlerResult, EventReturn},
17//! middlewares::outer::{Middleware, MiddlewareResponse},
18//! Extension, Request,
19//! };
20//!
21//! #[derive(Clone)]
22//! struct ToExtensionsMiddleware<T> {
23//! data: T,
24//! }
25//!
26//! impl<T> Middleware for ToExtensionsMiddleware<T>
27//! where
28//! T: Send + Sync + Clone + 'static,
29//! {
30//! async fn call(
31//! &mut self,
32//! mut request: Request,
33//! ) -> Result<MiddlewareResponse, EventErrorKind> {
34//! request.extensions.insert(self.data.clone());
35//!
36//! Ok((request, EventReturn::default()))
37//! }
38//! }
39//!
40//! async fn send_data_handler<T>(Extension(data2): Extension<T>) -> HandlerResult {
41//! todo!();
42//! }
43//! ```
44//!
45//! You can check examples of usage extensions in the [`examples`] directory.
46//!
47//! # Implementing trait
48//!
49//! Ways to implement [`Extractor`] for your own types:
50//! * Implement it directly (much boilerplate code, but it's needed for complex types)
51//! * Use the [`FromContext`] macro (simple way to implement this for types in a [`Context`] by its key)
52//! * Use the [`FromEvent`] macro (simple way to implement this for types in an event, for example, [`crate::types::Update`])
53//!
54//! ## Implementing directly
55//!
56//! Simple example with extracting id from [`crate::types::Update`]:
57//!
58//! ```rust
59//! use std::convert::Infallible;
60//! use telers::{Extractor, Request};
61//!
62//! struct UpdateId(i64);
63//!
64//! impl Extractor for UpdateId {
65//! type Error = Infallible;
66//!
67//! async fn extract(request: &Request) -> Result<Self, Self::Error> {
68//! Ok(UpdateId(request.update.update_id()))
69//! }
70//! }
71//! ```
72//!
73//! This example will extract the [`crate::types::Update`] id to the handler argument.
74//! After that, you can use this argument in the handler:
75//!
76//! ```ignore
77//! async fn handler(update_id: UpdateId) {
78//! println!("Update id: {}", id.0);
79//! }
80//! ```
81//!
82//! Another example with extracting id of the user who sent the message from [`crate::types::Update`]:
83//!
84//! ```rust
85//! use telers::{errors::ConvertToTypeError, Extractor, Request};
86//!
87//! struct UpdateFromId(i64);
88//!
89//! impl Extractor for UpdateFromId {
90//! type Error = ConvertToTypeError;
91//!
92//! // you can use your own error type, this is just an example
93//!
94//! async fn extract(request: &Request) -> Result<Self, Self::Error> {
95//! match request.update.from() {
96//! Some(from) => Ok(UpdateFromId(from.id)),
97//! None => Err(ConvertToTypeError::new("Update", "UpdateFromId")),
98//! }
99//! }
100//! }
101//! ```
102//!
103//! In some cases we sure that some data is not none, so in one handler we can use `Option` and in another handler we can use the type directly.
104//! After we implemented [`Extractor`] for our type, we can use it in both cases,
105//! because the trait is implemented for `Option<T>` and `Result<T, E>` where `T: Extractor`:
106//!
107//! ```rust
108//! use telers::{errors::ConvertToTypeError, Extractor, Request};
109//!
110//! struct UpdateFromId(i64);
111//!
112//! impl Extractor for UpdateFromId {
113//! type Error = ConvertToTypeError;
114//!
115//! // you can use your own error type, this is just an example
116//!
117//! async fn extract(request: &Request) -> Result<Self, Self::Error> {
118//! match request.update.from() {
119//! Some(from) => Ok(UpdateFromId(from.id)),
120//! None => Err(ConvertToTypeError::new("Update", "UpdateFromId")),
121//! }
122//! }
123//! }
124//! ```
125//!
126//! After that, you can use this argument in the handlers:
127//!
128//! ```ignore
129//! // Here `from_id` can't be `None` (for example we use filter which checks that `from_id` is not `None`)
130//! async fn handler_first(from_id: UpdateFromId) {
131//! println!("Update from id: {}", from_id.0);
132//! }
133//!
134//! // Here `from_id` can be `None`
135//! async fn handler_second(from_id: Option<UpdateFromId>) {
136//! if let Some(from_id) = from_id {
137//! println!("Update from id: {}", from_id.0);
138//! }
139//! }
140//! ```
141//!
142//! ## Implementing with [`FromEvent`] macro
143//!
144//! Simple example with extracting id from [`crate::types::Update`]:
145//!
146//! ```rust
147//! use telers::{types::Update, FromEvent};
148//!
149//! #[derive(FromEvent)]
150//! #[event(from = Update)]
151//! struct UpdateId(i64);
152//!
153//! // We need to implement `From<Update>` for `UpdateId` by ourselves (this is required by `FromEvent` macro)
154//! impl From<Update> for UpdateId {
155//! fn from(update: Update) -> Self {
156//! Self(update.update_id())
157//! }
158//! }
159//! ```
160//!
161//! Here we used `#[event(from = Update)]` attribute to specify the type from which the type will be converted.
162//!
163//! We also can use `#[event(try_from = "...")]`, but in this case we need to implement [`TryFrom`] for our type instead of [`From`]:
164//!
165//! ```rust
166//! use telers::{types::Update, FromEvent, errors::ConvertToTypeError};
167//!
168//! #[derive(FromEvent)]
169//! #[event(try_from = Update)] // you can specify [`ConvertToTypeError`] as error type, but it's not necessary, because it's default
170//! struct UpdateFromId(i64);
171//!
172//! impl TryFrom<Update> for UpdateFromId {
173//! type Error = ConvertToTypeError;
174//!
175//! fn try_from(update: Update) -> Result<Self, Self::Error> {
176//! match update.from() {
177//! Some(from) => Ok(Self(from.id)),
178//! None => Err(ConvertToTypeError::new("Update", "UpdateFromId")),
179//! }
180//! }
181//! }
182//! ```
183//!
184//! By default, the error type is [`ConvertToTypeError`](telers::errors::ConvertToTypeError),
185//! but you can specify your own error type with `#[event(error = "...")]` attribute:
186//!
187//! ```rust
188//! use std::convert::Infallible;
189//! use telers::{types::Update, FromEvent};
190//!
191//! #[derive(FromEvent)]
192//! #[event(try_from = Update, error = Infallible)]
193//! struct UpdateId(i64);
194//!
195//! impl TryFrom<Update> for UpdateId {
196//! // we use `TryFrom` here just for example, you need to use `From` if error is impossible
197//! type Error = Infallible;
198//!
199//! fn try_from(update: Update) -> Result<Self, Self::Error> {
200//! Ok(Self(update.update_id()))
201//! }
202//! }
203//! ```
204//!
205//! ## Implementing with [`FromContext`] macro
206//!
207//! Simple example with extracting struct by key from [`Context`]:
208//!
209//! ```rust
210//! use telers_macros::FromContext;
211//!
212//! #[derive(Clone, FromContext)]
213//! #[context(key = "my_struct")]
214//! struct MyStruct {
215//! field: i32,
216//! }
217//! ```
218//!
219//! Now we can use `MyStruct` as handler argument if we put it in the context with key `my_struct`.
220//! There is a serious problem here: we don't know where struct by key `my_struct` is set to the context
221//! and if context doesn't contain type by key `my_struct` we need to know where the source of the problem is.
222//! We can use `#[content(description = "...")]` to describe where the structure is installed, or cases where it is not installed, for example:
223//!
224//! ```rust
225//! use telers_macros::FromContext;
226//!
227//! #[derive(Clone, FromContext)]
228//! #[context(
229//! key = "my_struct",
230//! description = "This struct is set in the `MyMiddleware` middleware. If it is not set, \
231//! then the `MyMiddleware` middleware is not used."
232//! )]
233//! struct MyStruct {
234//! field: i32,
235//! }
236//! ```
237//!
238//! In some cases, you may want to use a one type in context, but extract it as another type.
239//! For this case, you can use `#[context(into = "...")]` attribute:
240//!
241//! ```rust
242//! use telers_macros::FromContext;
243//!
244//! #[derive(Clone, FromContext)]
245//! #[context(key = "my_struct", into = MyStructWrapper)]
246//! struct MyStruct {
247//! field: i32,
248//! }
249//!
250//! struct MyStructWrapper(MyStruct);
251//!
252//! impl From<MyStruct> for MyStructWrapper {
253//! fn from(my_struct: MyStruct) -> Self {
254//! Self(my_struct)
255//! }
256//! }
257//! ```
258//!
259//! This code will extract `MyStruct` from context and convert it to `MyStructWrapper`,
260//! but we need to implement `From<MyStruct>` for `MyStructWrapper` by ourselves (this is required by [`FromContext`] macro).
261//! In this case, the trait is implements for `MyStructWrapper`, not for `MyStruct`,
262//! so we can't use `MyStruct` as handler argument without implementing `Extractor` for it.
263//!
264//! We also can use `#[context(from = "...")]` attribute to specify the type from which the type will be converted:
265//!
266//! ```rust
267//! use telers_macros::FromContext;
268//!
269//! #[derive(Clone)]
270//! struct MyStruct {
271//! field: i32,
272//! }
273//!
274//! #[derive(FromContext)]
275//! #[context(key = "my_struct", from = MyStruct)]
276//! struct MyStructWrapper(MyStruct);
277//!
278//! impl From<MyStruct> for MyStructWrapper {
279//! fn from(my_struct: MyStruct) -> Self {
280//! Self(my_struct)
281//! }
282//! }
283//! ```
284//!
285//! This code similar to the previous one, but more useful in cases when `from` type is a foreign type.
286//!
287//! [`FromEvent`]: telers::FromEvent
288//! [`FromContext`]: telers::FromContext
289//! [`Extensions`]: telers::extensions::Extensions
290//! [`examples`]: https://github.com/Desiders/telers/tree/dev-1.x/examples
291
292use crate::{
293 client::{Bot, Reqwest},
294 context::Context,
295 errors::ExtractionError,
296 extensions::Extension,
297 Extensions, Request,
298};
299
300use std::{any::type_name, convert::Infallible, future::Future};
301
302/// Trait for extracting data from [`crate::types::Update`] and [`Context`] to handlers arguments
303pub trait Extractor<Client = Reqwest>: Sized {
304 type Error: Into<ExtractionError>;
305
306 /// Extracts data to handler argument
307 /// # Errors
308 /// If extraction was unsuccessful
309 ///
310 /// Possible variants:
311 /// * No found data in context by key
312 /// * Data in context by key has wrong type. For example, you try to extract `i32` from `String`.
313 /// * Custom user error
314 fn extract(request: &Request<Client>)
315 -> impl Future<Output = Result<Self, Self::Error>> + Send;
316}
317
318/// To be able to use [`Option`] as handler argument
319/// This implementation will return `None` if extraction was unsuccessful, and `Some(value)` otherwise
320impl<Client, T: Extractor<Client>> Extractor<Client> for Option<T>
321where
322 Client: Sync,
323{
324 type Error = Infallible;
325
326 #[inline]
327 async fn extract(request: &Request<Client>) -> Result<Self, Self::Error> {
328 match T::extract(request).await {
329 Ok(value) => Ok(Some(value)),
330 Err(_) => Ok(None),
331 }
332 }
333}
334
335/// To be able to use [`Result`] as handler argument
336/// This implementation will return `Ok(value)` if extraction was successful, and `Err(error)` otherwise,
337/// where `error` is `T::Error` converted to `E`
338impl<Client, T, E> Extractor<Client> for Result<T, E>
339where
340 T: Extractor<Client>,
341 T::Error: Into<E>,
342 Client: Sync,
343{
344 type Error = Infallible;
345
346 #[inline]
347 async fn extract(request: &Request<Client>) -> Result<Self, Self::Error> {
348 Ok(T::extract(request).await.map_err(Into::into))
349 }
350}
351
352/// To be able to use handler without arguments
353/// Handler without arguments will be called with `()` argument (unit type)
354impl<Client> Extractor<Client> for () {
355 type Error = Infallible;
356
357 #[allow(clippy::manual_async_fn)]
358 #[inline]
359 fn extract(
360 _request: &Request<Client>,
361 ) -> impl Future<Output = Result<Self, Self::Error>> + Send {
362 async move { Ok(()) }
363 }
364}
365
366impl<Client> Extractor<Client> for Bot<Client>
367where
368 Client: Clone + Send,
369{
370 type Error = Infallible;
371
372 #[inline]
373 fn extract(
374 request: &Request<Client>,
375 ) -> impl Future<Output = Result<Self, Self::Error>> + Send {
376 let bot = request.bot.clone();
377 async move { Ok(bot) }
378 }
379}
380
381impl<Client> Extractor<Client> for Context {
382 type Error = Infallible;
383
384 #[inline]
385 fn extract(
386 request: &Request<Client>,
387 ) -> impl Future<Output = Result<Self, Self::Error>> + Send {
388 let context = request.context.clone();
389 async move { Ok(context) }
390 }
391}
392
393impl<Client> Extractor<Client> for Extensions {
394 type Error = Infallible;
395
396 #[inline]
397 fn extract(
398 request: &Request<Client>,
399 ) -> impl Future<Output = Result<Self, Self::Error>> + Send {
400 let extensions = request.extensions.clone();
401 async move { Ok(extensions) }
402 }
403}
404
405impl<Client, Value> Extractor<Client> for Extension<Value>
406where
407 Value: Clone + Send + Sync + 'static,
408{
409 type Error = ExtractionError;
410
411 fn extract(
412 request: &Request<Client>,
413 ) -> impl Future<Output = Result<Self, Self::Error>> + Send {
414 let res = match request.extensions.get::<Value>() {
415 Some(value) => Ok(Self(value.clone())),
416 None => Err(ExtractionError::new(if request.extensions.is_empty() {
417 format!(
418 "Failed to extract data with type {}. Extensions are empty, it looks like you \
419 forgot to add a value.",
420 type_name::<Value>()
421 )
422 } else {
423 format!(
424 "Failed to extract data with type {}. It looks like you forgot to add a value \
425 of this type.",
426 type_name::<Value>()
427 )
428 })),
429 };
430 async move { res }
431 }
432}
433
434#[allow(non_snake_case)]
435mod factory_extractor {
436 //! This module is used to implement [`Extractor`] for tuple arguments, each of which implements it
437 //! If one of the arguments fails to extract, the whole extraction fails, and the error is returned
438
439 use super::{ExtractionError, Extractor, Request};
440
441 macro_rules! factory ({ $($param:ident)* } => {
442 impl<Client: Sync, $($param: Extractor<Client> + Send,)*> Extractor<Client> for ($($param,)*) {
443 type Error = ExtractionError;
444
445 async fn extract(request: &Request<Client>) -> Result<Self, Self::Error> {
446 Ok(($($param::extract(request).await.map_err(Into::into)?,)*))
447 }
448 }
449 });
450
451 // To be able to extract tuple with 1 arguments
452 factory! { A }
453 // To be able to extract tuple with 2 arguments
454 factory! { A B }
455 // To be able to extract tuple with 3 arguments
456 factory! { A B C }
457 // To be able to extract tuple with 4 arguments
458 factory! { A B C D }
459 // To be able to extract tuple with 5 arguments
460 factory! { A B C D E}
461 // To be able to extract tuple with 6 arguments
462 factory! { A B C D E F }
463 // To be able to extract tuple with 7 arguments
464 factory! { A B C D E F G}
465 // To be able to extract tuple with 8 arguments
466 factory! { A B C D E F G H }
467 // To be able to extract tuple with 9 arguments
468 factory! { A B C D E F G H I}
469 // To be able to extract tuple with 10 arguments
470 factory! { A B C D E F G H I J }
471 // To be able to extract tuple with 11 arguments
472 factory! { A B C D E F G H I J K}
473 // To be able to extract tuple with 12 arguments
474 factory! { A B C D E F G H I J K L }
475 // To be able to extract tuple with 13 arguments
476 factory! { A B C D E F G H I J K L M}
477 // To be able to extract tuple with 14 arguments
478 factory! { A B C D E F G H I J K L M N }
479 // To be able to extract tuple with 15 arguments
480 factory! { A B C D E F G H I J K L M N O}
481 // To be able to extract tuple with 16 arguments
482 factory! { A B C D E F G H I J K L M N O P }
483}
484
485#[allow(unreachable_code, clippy::extra_unused_type_parameters)]
486#[cfg(test)]
487mod tests {
488 use super::*;
489 use crate::{
490 errors::ConvertToTypeError,
491 types::{Message, MessageText, Update},
492 };
493
494 use std::sync::Arc;
495
496 #[test]
497 fn test_arg_number() {
498 fn assert_impl_handler<Client, T: Extractor<Client>>(_: T) {}
499
500 assert_impl_handler::<Reqwest, _>(());
501 assert_impl_handler::<Reqwest, _>((
502 (), // 1
503 (), // 2
504 (), // 3
505 (), // 4
506 (), // 5
507 (), // 6
508 (), // 7
509 (), // 8
510 (), // 9
511 (), // 10
512 (), // 11
513 (), // 12
514 (), // 13
515 (), // 14
516 (), // 15
517 (), // 16
518 ));
519 }
520
521 fn _check_bounds<Client, T: Extractor<Client>>() {
522 unimplemented!("This function is only used for checking bounds");
523
524 _check_bounds::<Client, ()>();
525
526 _check_bounds::<_, Bot>();
527 _check_bounds::<Client, Update>();
528 _check_bounds::<Client, Arc<Update>>();
529 _check_bounds::<Client, Context>();
530 _check_bounds::<Client, Extensions>();
531
532 _check_bounds::<Client, Message>();
533 _check_bounds::<Client, MessageText>();
534 }
535
536 fn _check_bounds_option<Client: Sync, T: Extractor<Client>>() {
537 unimplemented!("This function is only used for checking bounds");
538
539 _check_bounds::<Client, Option<()>>();
540
541 _check_bounds::<_, Option<Bot>>();
542 _check_bounds::<Client, Option<Update>>();
543 _check_bounds::<Client, Option<Arc<Update>>>();
544 _check_bounds::<Client, Option<Context>>();
545 _check_bounds::<Client, Option<Extensions>>();
546
547 _check_bounds::<Client, Option<Message>>();
548 _check_bounds::<Client, Option<MessageText>>();
549 }
550
551 fn _check_bounds_result<Client: Sync, T: Extractor<Client>, Err: Into<ExtractionError>>() {
552 unimplemented!("This function is only used for checking bounds");
553
554 _check_bounds::<Client, Result<(), Infallible>>();
555
556 _check_bounds::<_, Result<Bot, Infallible>>();
557 _check_bounds::<Client, Result<Update, Infallible>>();
558 _check_bounds::<Client, Result<Arc<Update>, Infallible>>();
559 _check_bounds::<Client, Result<Context, Infallible>>();
560 _check_bounds::<Client, Result<Extensions, Infallible>>();
561
562 _check_bounds::<Client, Result<Message, ConvertToTypeError>>();
563 _check_bounds::<Client, Result<MessageText, ConvertToTypeError>>();
564 }
565}