1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
use std::marker::PhantomData;

use seance::{backend::SessionBackend, Session};

use crate::{
    core::{HandlerInput, TryFromInput},
    dialogue::{error::DialogueError, state::DialogueState},
};

/// Represents an input for a dialogue handler.
///
/// The input provides access to the dialogue state.
/// When included in a list of handler arguments,
/// [`TryFromInput`] will automatically handle the extraction of the input.
#[derive(Clone)]
pub struct DialogueInput<S, B>
where
    S: DialogueState,
    B: SessionBackend,
{
    /// Dialogue state
    pub state: S,
    session_backend: PhantomData<B>,
}

impl<S, B> TryFromInput for DialogueInput<S, B>
where
    S: DialogueState + Send,
    B: SessionBackend + Send + 'static,
{
    type Error = DialogueError;

    async fn try_from_input(input: HandlerInput) -> Result<Option<Self>, Self::Error> {
        match <Session<B>>::try_from_input(input.clone()).await? {
            Some(ref mut session) => {
                let session_key = S::session_key();
                let state = session
                    .get(session_key)
                    .await
                    .map_err(DialogueError::LoadState)?
                    .unwrap_or_default();
                Ok(Some(Self {
                    state,
                    session_backend: PhantomData,
                }))
            }
            None => unreachable!("TryFromInput implementation for Session<B> never returns None"),
        }
    }
}