Advertisement
Laster_Alex

Unholy DI things

Oct 13th, 2024 (edited)
165
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 4.30 KB | None | 0 0
  1. use std::sync::Arc;
  2.  
  3. use dptree::{case, deps, di::*, from_fn_with_description, HandlerDescription};
  4. use teloxide::{
  5.     dispatching::{dialogue::InMemStorage, HandlerExt, UpdateFilterExt, UpdateHandler},
  6.     macros::BotCommands,
  7.     prelude::*,
  8. };
  9.  
  10. pub trait InsertContainer {
  11.     fn insert_container(&mut self, cont: DependencyMap);
  12. }
  13.  
  14. impl InsertContainer for DependencyMap {
  15.     fn insert_container(&mut self, cont: DependencyMap) {
  16.         DependencyMap::insert_container(self, cont);
  17.     }
  18. }
  19.  
  20. trait InjectContainer<'a, Input, Output, Descr> {
  21.    fn inject_cont<Proj, Args>(self, proj: Proj) -> Handler<'a, Input, Output, Descr>
  22.     where
  23.         Input: Clone + InsertContainer,
  24.         Asyncify<Proj>: Injectable<Input, DependencyMap, Args> + Send + Sync + 'a;
  25. }
  26.  
  27. impl<'a, Input, Output, Descr> InjectContainer<'a, Input, Output, Descr>
  28.    for Handler<'a, Input, Output, Descr>
  29. where
  30.     Input: Send + 'a,
  31.    Output: 'a,
  32.     Descr: HandlerDescription,
  33. {
  34.     #[must_use]
  35.     #[track_caller]
  36.     fn inject_cont<Proj, Args>(self, proj: Proj) -> Handler<'a, Input, Output, Descr>
  37.    where
  38.        Input: Clone + InsertContainer,
  39.        Asyncify<Proj>: Injectable<Input, DependencyMap, Args> + Send + Sync + 'a,
  40.     {
  41.         self.chain(inject_cont_async_with_description(
  42.             Descr::map(),
  43.             Asyncify(proj),
  44.         ))
  45.     }
  46. }
  47.  
  48. #[must_use]
  49. pub fn inject_cont_async_with_description<'a, Projection, Input, Output, Args, Descr>(
  50.    description: Descr,
  51.    proj: Projection,
  52. ) -> Handler<'a, Input, Output, Descr>
  53. where
  54.     Input: Clone + InsertContainer,
  55.     Projection: Injectable<Input, DependencyMap, Args> + Send + Sync + 'a,
  56.    Input: Send + 'a,
  57.     Output: 'a,
  58.    Descr: HandlerDescription,
  59. {
  60.    let proj = Arc::new(proj);
  61.  
  62.    from_fn_with_description(description, move |container: Input, cont| {
  63.        let proj = Arc::clone(&proj);
  64.  
  65.        async move {
  66.            let proj = proj.inject(&container);
  67.            let res = proj().await;
  68.            std::mem::drop(proj);
  69.  
  70.            let mut intermediate = container.clone();
  71.            intermediate.insert_container(res);
  72.            match cont(intermediate).await {
  73.                ControlFlow::Continue(_) => ControlFlow::Continue(container),
  74.                ControlFlow::Break(result) => ControlFlow::Break(result),
  75.            }
  76.        }
  77.    })
  78. }
  79.  
  80. type HandlerResult = Result<(), Box<dyn std::error::Error + Send + Sync>>;
  81. type DiDialogue = Dialogue<DiState, InMemStorage<DiState>>;
  82.  
  83. #[derive(Clone)]
  84. struct DiState {
  85.    di: DependencyMap,
  86. }
  87.  
  88. impl Default for DiState {
  89.    fn default() -> Self {
  90.        DiState {
  91.            di: DependencyMap::new(),
  92.        }
  93.    }
  94. }
  95.  
  96. // Just for QoL, not necessary
  97. impl From<DependencyMap> for DiState {
  98.    fn from(value: DependencyMap) -> Self {
  99.        DiState { di: value }
  100.    }
  101. }
  102.  
  103. #[derive(BotCommands, Default, Clone, Debug)]
  104. #[command(rename_rule = "snake_case")]
  105. enum Commands {
  106.    #[default]
  107.    IAmSure,
  108. }
  109.  
  110. async fn handler(
  111.    bot: Bot,
  112.    message: Message,
  113.    DiState { mut di }: DiState,
  114.    didialogue: DiDialogue,
  115. ) -> HandlerResult {
  116.    let val_before = di.insert(3_i32);
  117.    let val: Arc<i32> = di.get();
  118.  
  119.    bot.send_message(
  120.        message.chat.id,
  121.        format!("Before: {:?}, Now: {:?}", val_before, val),
  122.    )
  123.    .await?;
  124.  
  125.    didialogue.update(di).await?;
  126.    Ok(())
  127. }
  128.  
  129. async fn i_am_sure(bot: Bot, message: Message, val: i32) -> HandlerResult {
  130.    bot.send_message(message.chat.id, format!("{val}")).await?;
  131.    Ok(())
  132. }
  133.  
  134. fn handler_tree() -> UpdateHandler<Box<dyn std::error::Error + Send + Sync + 'static>> {
  135.     dptree::entry()
  136.         .enter_dialogue::<Update, InMemStorage<DiState>, DiState>()
  137.         .inject_cont(|DiState { di }: DiState| di)
  138.         .branch(
  139.             Update::filter_message()
  140.                 .filter_command::<Commands>()
  141.                 .branch(case![Commands::IAmSure].endpoint(i_am_sure)),
  142.         )
  143.         .branch(Update::filter_message().endpoint(handler))
  144. }
  145.  
  146. #[tokio::main]
  147. async fn main() {
  148.     dotenv::dotenv().ok();
  149.  
  150.     let bot = Bot::from_env();
  151.  
  152.     Dispatcher::builder(bot, handler_tree())
  153.         .dependencies(deps![InMemStorage::<DiState>::new()])
  154.         .enable_ctrlc_handler()
  155.         .build()
  156.         .dispatch()
  157.         .await;
  158. }
  159.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement