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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use crate::models::{ChatId, ChatMember, Message, Update};
use crate::{Bot, BotState};

/// Allow a parameter to be parsed from an update and the bot state.
/// Any type implementing this trait can be used as parameter in a handler
pub trait FromUpdate<'r, T: Sync>
where
    Self: Sized,
{
    /// Instantiate `Self` from an incoming update
    fn from_update(bot: &'r Bot, update: &'r Update, state: Option<&'r BotState<T>>) -> Option<Self>;
}

impl<'r, T: Sync> FromUpdate<'r, T> for &'r Bot {
    fn from_update(bot: &'r Bot, _: &Update, _: Option<&BotState<T>>) -> Option<Self> {
        Some(bot)
    }
}

impl<'r, T: Sync> FromUpdate<'r, T> for &'r Update {
    fn from_update(_: &Bot, update: &'r Update, _: Option<&BotState<T>>) -> Option<Self> {
        Some(update)
    }
}

impl<'r, T: Sync> FromUpdate<'r, T> for &'r BotState<T> {
    fn from_update(_: &Bot, _: &Update, state: Option<&'r BotState<T>>) -> Option<Self> {
        state
    }
}

impl<'r, T: Sync> FromUpdate<'r, T> for &'r Message {
    fn from_update(_: &Bot, u: &'r Update, _: Option<&BotState<T>>) -> Option<Self> {
        match u {
            Update::NewMessage(_, m) => Some(m),
            Update::EditedMessage(_, m) => Some(m),
            Update::NewChannelPost(_, m) => Some(m),
            Update::EditedChannelPost(_, m) => Some(m),
            Update::CallBackQuery(_, c) => c.message.as_ref(),
            _ => None,
        }
    }
}

impl<'r, T: Sync> FromUpdate<'r, T> for ChatId {
    fn from_update(_: &Bot, u: &'r Update, _: Option<&BotState<T>>) -> Option<Self> {
        match u {
            Update::NewMessage(_, Message { chat, .. }) => Some(chat.id.into()),
            Update::EditedMessage(_, Message { chat, .. }) => Some(chat.id.into()),
            Update::NewChannelPost(_, Message { chat, .. }) => Some(chat.id.into()),
            Update::EditedChannelPost(_, Message { chat, .. }) => Some(chat.id.into()),
            Update::CallBackQuery(_, c) => c.message.as_ref().map(|m| m.chat.id.into()),
            Update::BotStatus(_, s) => {
                if let ChatMember::Updated { chat, .. } = s {
                    Some(chat.id.into())
                } else {
                    None
                }
            }
            Update::MemberStatus(_, s) => {
                if let ChatMember::Updated { chat, .. } = s {
                    Some(chat.id.into())
                } else {
                    None
                }
            }
            Update::ChatJoinRequest(_, r) => Some(r.chat.id.into()),
            _ => None,
        }
    }
}