Skip to main content

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}