tg_flows/types/
chat_id.rs1use serde::{Deserialize, Serialize};
2
3use crate::types::UserId;
4
5#[derive(
9 Clone,
10 Copy,
11 Debug,
12 derive_more::Display,
13 PartialEq,
14 Eq,
15 PartialOrd,
16 Ord,
17 Hash,
18 Serialize,
19 Deserialize,
20)]
21#[serde(transparent)]
22pub struct ChatId(pub i64);
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
34pub(crate) enum BareChatId {
35 User(UserId),
36 Group(u64),
37 Channel(u64),
39}
40
41impl ChatId {
42 #[must_use]
44 pub fn is_user(self) -> bool {
45 matches!(self.to_bare(), BareChatId::User(_))
46 }
47
48 #[must_use]
52 pub fn is_group(self) -> bool {
53 matches!(self.to_bare(), BareChatId::Group(_))
54 }
55
56 #[must_use]
58 pub fn is_channel_or_supergroup(self) -> bool {
59 matches!(self.to_bare(), BareChatId::Channel(_))
60 }
61
62 pub(crate) fn to_bare(self) -> BareChatId {
66 use BareChatId::*;
67
68 match self.0 {
69 id @ MIN_MARKED_CHAT_ID..=MAX_MARKED_CHAT_ID => Group(-id as _),
70 id @ MIN_MARKED_CHANNEL_ID..=MAX_MARKED_CHANNEL_ID => {
71 Channel((MAX_MARKED_CHANNEL_ID - id) as _)
72 }
73 id @ MIN_USER_ID..=MAX_USER_ID => User(UserId(id as _)),
74 id => panic!("malformed chat id: {id}"),
75 }
76 }
77}
78
79impl From<UserId> for ChatId {
80 fn from(UserId(id): UserId) -> Self {
81 Self(id as _)
82 }
83}
84
85impl BareChatId {
86 #[allow(unused)]
88 pub(crate) fn to_bot_api(self) -> ChatId {
89 use BareChatId::*;
90
91 match self {
92 User(UserId(id)) => ChatId(id as _),
93 Group(id) => ChatId(-(id as i64)),
94 Channel(id) => ChatId(MAX_MARKED_CHANNEL_ID - (id as i64)),
95 }
96 }
97}
98
99const MIN_MARKED_CHANNEL_ID: i64 = -1997852516352;
101const MAX_MARKED_CHANNEL_ID: i64 = -1000000000000;
102const MIN_MARKED_CHAT_ID: i64 = MAX_MARKED_CHANNEL_ID + 1;
103const MAX_MARKED_CHAT_ID: i64 = MIN_USER_ID - 1;
104const MIN_USER_ID: i64 = 0;
105const MAX_USER_ID: i64 = (1 << 40) - 1;
106
107#[cfg(test)]
108mod tests {
109 use serde::{Deserialize, Serialize};
110
111 use crate::types::{BareChatId, ChatId, UserId};
112
113 #[test]
115 fn deser() {
116 let chat_id = S {
117 chat_id: ChatId(0xAA),
118 };
119 let json = r#"{"chat_id":170}"#;
120
121 #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
122 struct S {
123 chat_id: ChatId,
124 }
125
126 assert_eq!(serde_json::to_string(&chat_id).unwrap(), json);
127 assert_eq!(chat_id, serde_json::from_str(json).unwrap());
128 }
129
130 #[test]
131 fn chonky_user_id_to_bare() {
132 assert!(matches!(
133 ChatId(5298363099).to_bare(),
134 BareChatId::User(UserId(5298363099))
135 ));
136 }
137
138 #[test]
139 fn to_bare_to_bot_api_identity() {
140 fn assert_identity(x: u64) {
141 use BareChatId::*;
142
143 assert_eq!(User(UserId(x)), User(UserId(x)).to_bot_api().to_bare());
144 assert_eq!(Group(x), Group(x).to_bot_api().to_bare());
145 assert_eq!(Channel(x), Channel(x).to_bot_api().to_bare());
146 }
147
148 let ids = [
150 1,
151 4,
152 17,
153 34,
154 51,
155 777000,
156 1000000,
157 617136926,
158 1666111087,
159 1 << 20,
160 (1 << 35) | 123456,
161 ];
162
163 ids.iter().copied().for_each(assert_identity);
165 }
166
167 #[test]
168 fn display() {
169 assert_eq!(ChatId(1).to_string(), "1");
170 }
171}