Skip to main content

grammers_session/
peer.rs

1// Copyright 2020 - developers of the `grammers` project.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use std::{
10    fmt,
11    ops::{Deref as _, RangeInclusive},
12};
13
14use grammers_tl_types as tl;
15
16/// A compact peer identifier.
17/// ```
18/// use std::mem::size_of;
19/// assert_eq!(size_of::<grammers_session::types::PeerId>(), size_of::<i64>());
20/// ```
21/// The [`PeerInfo`] cached by the session for this `PeerId` may be retrieved via [`crate::Session::peer`].
22///
23/// The internal representation uses the Bot API Dialog ID format to
24/// bit-pack both the peer's true identifier and type in a single integer.
25///
26/// Internally, arbitrary values outside the valid range of Bot API Dialog ID
27/// may be used to represent special peer identifiers.
28#[repr(transparent)]
29#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
31pub struct PeerId(i64);
32
33/// Witness to the session's authority from Telegram to interact with a peer.
34///
35/// If Telegram deems the session to already have such authority, the session may
36/// be allowed to present [`PeerAuth::default`] instead of this witness. This can
37/// happen when the logged-in user is a bot account, or, for user accounts, when
38/// the peer being interacted with is one of its contacts.
39#[repr(transparent)]
40#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
41#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
42pub struct PeerAuth(i64);
43
44/// Ocap-style reference to a peer object, a peer object capability, bundling the identity
45/// of a peer (its [`PeerId`]) with authority over it (as [`PeerAuth`]), to allow fluent use.
46///
47/// This type implements conversion to [`tl::enums::InputPeer`] and derivatives.
48#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
50pub struct PeerRef {
51    /// The peer identity.
52    pub id: PeerId,
53    /// The authority bound to both the sibling identity and the session of the logged-in user.
54    pub auth: PeerAuth,
55}
56
57/// [`PeerId`]'s kind.
58///
59/// The `PeerId` bitpacks this information for size reasons.
60#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
61#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
62pub enum PeerKind {
63    /// The peer identity belongs to a [`tl::enums::User`]. May also represent [`PeerKind::UserSelf`].
64    User,
65    /// The peer identity belongs to a user with its [`tl::types::User::is_self`] flag set to `true`.
66    UserSelf,
67    /// The peer identity belongs to a [`tl::types::Chat`] or one of its derivatives.
68    Chat,
69    /// The peer identity belongs to a [`tl::types::Channel`] or one of its derivatives.
70    Channel,
71}
72
73/// An exploded peer reference along with any known useful information about the peer.
74#[derive(Clone, Debug, PartialEq, Eq)]
75#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
76pub enum PeerInfo {
77    User {
78        /// Bare user identifier.
79        ///
80        /// Despite being `i64`, Telegram only uses strictly positive values.
81        id: i64,
82        /// Non-ambient authority bound to both the user itself and the session.
83        auth: Option<PeerAuth>,
84        /// Whether this user represents a bot or not.
85        bot: Option<bool>,
86        /// Whether this user represents the logged-in user authorized by this session or not.
87        is_self: Option<bool>,
88    },
89    Chat {
90        /// Bare chat identifier.
91        ///
92        /// Note that the HTTP Bot API negates this identifier to signal that it is a chat,
93        /// but the true value used by Telegram's API is always strictly-positive.
94        id: i64,
95    },
96    Channel {
97        /// Bare channel identifier.
98        ///
99        /// Note that the HTTP Bot API prefixes this identifier with `-100` to signal that it is a channel,
100        /// but the true value used by Telegram's API is always strictly-positive.
101        id: i64,
102        /// Non-ambient authority bound to both the user itself and the session.
103        auth: Option<PeerAuth>,
104        /// Channel kind, useful to determine what the possible permissions on it are.
105        kind: Option<ChannelKind>,
106    },
107}
108
109/// Additional information about a [`PeerInfo::Channel`].
110///
111/// A non-zero enum,
112/// to make working with `Option<ChannelKind>`
113/// and `Result<ChannelKind, ()>`
114/// slightly more performant.
115/// (See [`mod@core::option`]'s documentation about the "null pointer optimization".)
116#[derive(Clone, Copy, Debug, PartialEq, Eq)]
117#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
118pub enum ChannelKind {
119    /// Value used for a channel with its [`tl::types::Channel::broadcast`] flag set to `true`.
120    Broadcast = 1,
121    /// Value used for a channel with its [`tl::types::Channel::megagroup`] flag set to `true`.
122    Megagroup,
123    /// Value used for a channel with its [`tl::types::Channel::gigagroup`] flag set to `true`.
124    Gigagroup,
125}
126
127/// Sentinel value used to represent the self-user
128/// when its true `PeerId` is unknown.
129///
130/// Per <https://core.telegram.org/api/bots/ids>:
131/// > a bot API dialog ID ranges from -4000000000000 to 1099511627775
132///
133/// This value is not intended to be visible or persisted,
134/// so it can be changed as needed in the future.
135const SELF_USER_ID: PeerId = PeerId(1 << 40);
136
137/// Sentinel value used to represent empty chats.
138///
139/// Per <https://core.telegram.org/api/bots/ids>:
140/// > \[…] transformed range for bot API chat dialog IDs is -999999999999 to -1 inclusively
141/// >
142/// > \[…] transformed range for bot API channel dialog IDs is -1997852516352 to -1000000000001 inclusively
143///
144/// `chat_id` parameters are in Telegram's API use the bare identifier,
145/// so there's no empty constructor,
146/// but it can be mimicked by picking the value in the correct range hole.
147/// This value is closer to "channel with ID 0" than "chat with ID 0",
148/// but there's no distinct `-0` integer,
149/// and channels have a proper constructor for empty already.
150const EMPTY_CHAT_ID: i64 = -1000000000000;
151
152/// https://core.telegram.org/api/bots/ids#user-ids
153const USER_ID_RANGE: RangeInclusive<i64> = 1..=0xffffffffff;
154/// https://core.telegram.org/api/bots/ids#chat-ids
155const CHAT_ID_RANGE: RangeInclusive<i64> = 1..=999999999999;
156/// https://core.telegram.org/api/bots/ids#supergroup-channel-ids
157const SUPERGROUP_AND_CHANNEL_ID_RANGE: RangeInclusive<i64> = 1..=997852516352;
158/// https://core.telegram.org/api/bots/ids#monoforum-ids
159const MONOFORUM_ID_RANGE: RangeInclusive<i64> = 1002147483649..=3000000000000;
160
161impl PeerId {
162    /// Creates a peer identity for the currently-logged-in user or bot account.
163    ///
164    /// Internally, this will use a special sentinel value outside of any valid Bot API Dialog ID range.
165    pub fn self_user() -> Self {
166        SELF_USER_ID
167    }
168
169    /// Creates a peer identity for a user or bot account.
170    pub fn user(id: i64) -> Option<Self> {
171        USER_ID_RANGE.contains(&id).then_some(Self(id))
172    }
173
174    /// Creates a peer identity for a small group chat.
175    pub fn chat(id: i64) -> Option<Self> {
176        CHAT_ID_RANGE.contains(&id).then_some(Self(-id))
177    }
178
179    /// Creates a peer identity for a broadcast channel, megagroup, gigagroup or monoforum.
180    pub fn channel(id: i64) -> Option<Self> {
181        (SUPERGROUP_AND_CHANNEL_ID_RANGE.contains(&id) || MONOFORUM_ID_RANGE.contains(&id))
182            .then_some(Self(-(1000000000000 + id)))
183    }
184
185    /// Creates a peer identity for a user or bot account.
186    /// Panics if the ID is out of the valid range.
187    #[doc(hidden)]
188    pub fn user_unchecked(id: i64) -> Self {
189        debug_assert!(USER_ID_RANGE.contains(&id), "user ID out of range");
190        Self(id)
191    }
192
193    /// Creates a peer identity for a small group chat.
194    /// Panics if the ID is out of the valid range.
195    #[doc(hidden)]
196    pub fn chat_unchecked(id: i64) -> Self {
197        debug_assert!(CHAT_ID_RANGE.contains(&id), "chat ID out of range");
198        Self(-id)
199    }
200
201    /// Creates a peer identity for a broadcast channel, megagroup, gigagroup or monoforum.
202    /// Panics if the ID is out of the valid range.
203    #[doc(hidden)]
204    pub fn channel_unchecked(id: i64) -> Self {
205        debug_assert!(
206            (SUPERGROUP_AND_CHANNEL_ID_RANGE.contains(&id) || MONOFORUM_ID_RANGE.contains(&id)),
207            "channel ID out of range"
208        );
209        Self(-(1000000000000 + id))
210    }
211
212    /// Peer kind.
213    pub fn kind(self) -> PeerKind {
214        if 1 <= self.0 && self.0 <= 0xffffffffff {
215            PeerKind::User
216        } else if self.0 == SELF_USER_ID.0 {
217            PeerKind::UserSelf
218        } else if -999999999999 <= self.0 && self.0 <= -1 {
219            PeerKind::Chat
220        } else if -1997852516352 <= self.0 && self.0 <= -1000000000001
221            || (-4000000000000 <= self.0 && self.0 <= -2002147483649)
222        {
223            PeerKind::Channel
224        } else {
225            unreachable!()
226        }
227    }
228
229    /// Returns the identity using the Bot API Dialog ID format.
230    ///
231    /// Will return an arbitrary value if [`Self::kind`] is [`PeerKind::UserSelf`].
232    /// This value should not be relied on and may change between releases.
233    pub fn bot_api_dialog_id(&self) -> i64 {
234        self.0
235    }
236
237    /// Unpacked peer identifier. Panics if [`Self::kind`] is [`PeerKind::UserSelf`].
238    pub fn bare_id(&self) -> i64 {
239        match self.kind() {
240            PeerKind::User => self.0,
241            PeerKind::UserSelf => panic!("self-user ID not known"),
242            PeerKind::Chat => -self.0,
243            PeerKind::Channel => -self.0 - 1000000000000,
244        }
245    }
246}
247
248impl PeerAuth {
249    /// Construct a new peer authentication using Telegram's `access_hash` value.
250    pub fn from_hash(access_hash: i64) -> Self {
251        PeerAuth(access_hash)
252    }
253
254    /// Grants access to the internal access hash.
255    pub fn hash(&self) -> i64 {
256        self.0
257    }
258}
259
260impl Default for PeerAuth {
261    /// Returns the ambient authority to authorize peers only when Telegram considers it valid.
262    ///
263    /// The internal representation uses `0` to signal the ambient authority,
264    /// although this might happen to be the actual witness used by some peers.
265    fn default() -> Self {
266        Self(0)
267    }
268}
269
270impl PeerInfo {
271    /// Returns the `PeerId` represented by this info.
272    ///
273    /// The returned [`PeerId::kind()`] will never be [`PeerKind::UserSelf`].
274    pub fn id(&self) -> PeerId {
275        match self {
276            PeerInfo::User { id, .. } => PeerId::user_unchecked(*id),
277            PeerInfo::Chat { id } => PeerId::chat_unchecked(*id),
278            PeerInfo::Channel { id, .. } => PeerId::channel_unchecked(*id),
279        }
280    }
281
282    /// Returns the `PeerAuth` stored in this info.
283    pub fn auth(&self) -> Option<PeerAuth> {
284        match self {
285            PeerInfo::User { auth, .. } => *auth,
286            PeerInfo::Chat { .. } => Some(PeerAuth::default()),
287            PeerInfo::Channel { auth, .. } => *auth,
288        }
289    }
290}
291
292impl fmt::Display for PeerId {
293    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
294        self.bot_api_dialog_id().fmt(f)
295    }
296}
297
298impl From<tl::enums::Peer> for PeerId {
299    #[inline]
300    fn from(peer: tl::enums::Peer) -> Self {
301        <Self as From<&tl::enums::Peer>>::from(&peer)
302    }
303}
304impl<'a> From<&'a tl::enums::Peer> for PeerId {
305    fn from(peer: &'a tl::enums::Peer) -> Self {
306        use tl::enums::Peer;
307        match peer {
308            Peer::User(user) => Self::from(user),
309            Peer::Chat(chat) => Self::from(chat),
310            Peer::Channel(channel) => Self::from(channel),
311        }
312    }
313}
314
315impl From<tl::types::PeerUser> for PeerId {
316    #[inline]
317    fn from(user: tl::types::PeerUser) -> Self {
318        <Self as From<&tl::types::PeerUser>>::from(&user)
319    }
320}
321impl<'a> From<&'a tl::types::PeerUser> for PeerId {
322    fn from(user: &'a tl::types::PeerUser) -> Self {
323        Self::user_unchecked(user.user_id)
324    }
325}
326
327impl From<tl::types::PeerChat> for PeerId {
328    #[inline]
329    fn from(user: tl::types::PeerChat) -> Self {
330        <Self as From<&tl::types::PeerChat>>::from(&user)
331    }
332}
333impl<'a> From<&'a tl::types::PeerChat> for PeerId {
334    fn from(chat: &'a tl::types::PeerChat) -> Self {
335        Self::chat_unchecked(chat.chat_id)
336    }
337}
338
339impl From<tl::types::PeerChannel> for PeerId {
340    #[inline]
341    fn from(channel: tl::types::PeerChannel) -> Self {
342        <Self as From<&tl::types::PeerChannel>>::from(&channel)
343    }
344}
345impl<'a> From<&'a tl::types::PeerChannel> for PeerId {
346    fn from(channel: &'a tl::types::PeerChannel) -> Self {
347        Self::channel_unchecked(channel.channel_id)
348    }
349}
350
351impl From<tl::enums::InputPeer> for PeerRef {
352    #[inline]
353    fn from(peer: tl::enums::InputPeer) -> Self {
354        <Self as From<&tl::enums::InputPeer>>::from(&peer)
355    }
356}
357impl<'a> From<&'a tl::enums::InputPeer> for PeerRef {
358    fn from(peer: &'a tl::enums::InputPeer) -> Self {
359        use tl::{enums::InputPeer, types::InputPeerSelf};
360        match peer {
361            InputPeer::Empty => panic!("InputPeer::Empty cannot be converted to any Peer"),
362            InputPeer::PeerSelf => <Self as From<&'a _>>::from(&InputPeerSelf {}),
363            InputPeer::User(user) => <Self as From<&'a _>>::from(user),
364            InputPeer::Chat(chat) => <Self as From<&'a _>>::from(chat),
365            InputPeer::Channel(channel) => <Self as From<&'a _>>::from(channel),
366            InputPeer::UserFromMessage(user) => <Self as From<&'a _>>::from(user.deref()),
367            InputPeer::ChannelFromMessage(channel) => <Self as From<&'a _>>::from(channel.deref()),
368        }
369    }
370}
371
372impl From<tl::types::InputPeerSelf> for PeerRef {
373    #[inline]
374    fn from(self_user: tl::types::InputPeerSelf) -> Self {
375        <Self as From<&tl::types::InputPeerSelf>>::from(&self_user)
376    }
377}
378impl<'a> From<&'a tl::types::InputPeerSelf> for PeerRef {
379    fn from(self_user: &'a tl::types::InputPeerSelf) -> Self {
380        _ = self_user;
381        Self {
382            id: SELF_USER_ID,
383            auth: PeerAuth::default(),
384        }
385    }
386}
387
388impl From<tl::types::InputPeerUser> for PeerRef {
389    #[inline]
390    fn from(user: tl::types::InputPeerUser) -> Self {
391        <Self as From<&tl::types::InputPeerUser>>::from(&user)
392    }
393}
394impl<'a> From<&'a tl::types::InputPeerUser> for PeerRef {
395    fn from(user: &'a tl::types::InputPeerUser) -> Self {
396        Self {
397            id: PeerId::user_unchecked(user.user_id),
398            auth: PeerAuth::from_hash(user.access_hash),
399        }
400    }
401}
402
403impl From<tl::types::InputPeerChat> for PeerRef {
404    #[inline]
405    fn from(chat: tl::types::InputPeerChat) -> Self {
406        <Self as From<&tl::types::InputPeerChat>>::from(&chat)
407    }
408}
409impl<'a> From<&'a tl::types::InputPeerChat> for PeerRef {
410    fn from(chat: &'a tl::types::InputPeerChat) -> Self {
411        Self {
412            id: PeerId::chat_unchecked(chat.chat_id),
413            auth: PeerAuth::default(),
414        }
415    }
416}
417
418impl From<tl::types::InputPeerChannel> for PeerRef {
419    #[inline]
420    fn from(channel: tl::types::InputPeerChannel) -> Self {
421        <Self as From<&tl::types::InputPeerChannel>>::from(&channel)
422    }
423}
424impl<'a> From<&'a tl::types::InputPeerChannel> for PeerRef {
425    fn from(channel: &'a tl::types::InputPeerChannel) -> Self {
426        Self {
427            id: PeerId::channel_unchecked(channel.channel_id),
428            auth: PeerAuth::from_hash(channel.access_hash),
429        }
430    }
431}
432
433impl From<tl::types::InputPeerUserFromMessage> for PeerRef {
434    #[inline]
435    fn from(user: tl::types::InputPeerUserFromMessage) -> Self {
436        <Self as From<&tl::types::InputPeerUserFromMessage>>::from(&user)
437    }
438}
439impl<'a> From<&'a tl::types::InputPeerUserFromMessage> for PeerRef {
440    fn from(user: &'a tl::types::InputPeerUserFromMessage) -> Self {
441        // Not currently willing to make PeerRef significantly larger to accomodate for this uncommon type.
442        Self {
443            id: PeerId::user_unchecked(user.user_id),
444            auth: PeerAuth::default(),
445        }
446    }
447}
448
449impl From<tl::types::InputPeerChannelFromMessage> for PeerRef {
450    #[inline]
451    fn from(channel: tl::types::InputPeerChannelFromMessage) -> Self {
452        <Self as From<&tl::types::InputPeerChannelFromMessage>>::from(&channel)
453    }
454}
455impl<'a> From<&'a tl::types::InputPeerChannelFromMessage> for PeerRef {
456    fn from(channel: &'a tl::types::InputPeerChannelFromMessage) -> Self {
457        // Not currently willing to make PeerRef significantly larger to accomodate for this uncommon type.
458        Self {
459            id: PeerId::channel_unchecked(channel.channel_id),
460            auth: PeerAuth::default(),
461        }
462    }
463}
464
465impl From<tl::enums::User> for PeerRef {
466    #[inline]
467    fn from(user: tl::enums::User) -> Self {
468        <Self as From<&tl::enums::User>>::from(&user)
469    }
470}
471impl<'a> From<&'a tl::enums::User> for PeerRef {
472    fn from(user: &'a tl::enums::User) -> Self {
473        use tl::enums::User;
474        match user {
475            User::Empty(user) => <Self as From<&_>>::from(user),
476            User::User(user) => <Self as From<&_>>::from(user),
477        }
478    }
479}
480
481impl From<tl::types::UserEmpty> for PeerRef {
482    #[inline]
483    fn from(user: tl::types::UserEmpty) -> Self {
484        <Self as From<&tl::types::UserEmpty>>::from(&user)
485    }
486}
487impl<'a> From<&'a tl::types::UserEmpty> for PeerRef {
488    fn from(user: &'a tl::types::UserEmpty) -> Self {
489        Self {
490            id: PeerId::user_unchecked(user.id),
491            auth: PeerAuth::default(),
492        }
493    }
494}
495
496impl From<tl::types::User> for PeerRef {
497    #[inline]
498    fn from(user: tl::types::User) -> Self {
499        <Self as From<&tl::types::User>>::from(&user)
500    }
501}
502impl<'a> From<&'a tl::types::User> for PeerRef {
503    fn from(user: &'a tl::types::User) -> Self {
504        Self {
505            id: if user.is_self {
506                PeerId::self_user()
507            } else {
508                PeerId::user_unchecked(user.id)
509            },
510            auth: user
511                .access_hash
512                .map(PeerAuth::from_hash)
513                .unwrap_or(PeerAuth::default()),
514        }
515    }
516}
517
518impl From<tl::enums::Chat> for PeerRef {
519    #[inline]
520    fn from(chat: tl::enums::Chat) -> Self {
521        <Self as From<&tl::enums::Chat>>::from(&chat)
522    }
523}
524impl<'a> From<&'a tl::enums::Chat> for PeerRef {
525    fn from(chat: &'a tl::enums::Chat) -> Self {
526        use tl::enums::Chat;
527        match chat {
528            Chat::Empty(chat) => <Self as From<&_>>::from(chat),
529            Chat::Chat(chat) => <Self as From<&_>>::from(chat),
530            Chat::Forbidden(chat) => <Self as From<&_>>::from(chat),
531            Chat::Channel(channel) => <Self as From<&_>>::from(channel),
532            Chat::ChannelForbidden(channel) => <Self as From<&_>>::from(channel),
533        }
534    }
535}
536
537impl From<tl::types::ChatEmpty> for PeerRef {
538    #[inline]
539    fn from(chat: tl::types::ChatEmpty) -> Self {
540        <Self as From<&tl::types::ChatEmpty>>::from(&chat)
541    }
542}
543impl<'a> From<&'a tl::types::ChatEmpty> for PeerRef {
544    fn from(chat: &'a tl::types::ChatEmpty) -> Self {
545        Self {
546            id: PeerId::chat_unchecked(chat.id),
547            auth: PeerAuth::default(),
548        }
549    }
550}
551
552impl From<tl::types::Chat> for PeerRef {
553    #[inline]
554    fn from(chat: tl::types::Chat) -> Self {
555        <Self as From<&tl::types::Chat>>::from(&chat)
556    }
557}
558impl<'a> From<&'a tl::types::Chat> for PeerRef {
559    fn from(chat: &'a tl::types::Chat) -> Self {
560        Self {
561            id: PeerId::chat_unchecked(chat.id),
562            auth: PeerAuth::default(),
563        }
564    }
565}
566
567impl From<tl::types::ChatForbidden> for PeerRef {
568    #[inline]
569    fn from(chat: tl::types::ChatForbidden) -> Self {
570        <Self as From<&tl::types::ChatForbidden>>::from(&chat)
571    }
572}
573impl<'a> From<&'a tl::types::ChatForbidden> for PeerRef {
574    fn from(chat: &'a tl::types::ChatForbidden) -> Self {
575        Self {
576            id: PeerId::chat_unchecked(chat.id),
577            auth: PeerAuth::default(),
578        }
579    }
580}
581
582impl From<tl::types::Channel> for PeerRef {
583    #[inline]
584    fn from(channel: tl::types::Channel) -> Self {
585        <Self as From<&tl::types::Channel>>::from(&channel)
586    }
587}
588impl<'a> From<&'a tl::types::Channel> for PeerRef {
589    fn from(channel: &'a tl::types::Channel) -> Self {
590        Self {
591            id: PeerId::channel_unchecked(channel.id),
592            auth: channel
593                .access_hash
594                .map(PeerAuth::from_hash)
595                .unwrap_or(PeerAuth::default()),
596        }
597    }
598}
599
600impl From<tl::types::ChannelForbidden> for PeerRef {
601    #[inline]
602    fn from(channel: tl::types::ChannelForbidden) -> Self {
603        <Self as From<&tl::types::ChannelForbidden>>::from(&channel)
604    }
605}
606impl<'a> From<&'a tl::types::ChannelForbidden> for PeerRef {
607    fn from(channel: &'a tl::types::ChannelForbidden) -> Self {
608        Self {
609            id: PeerId::channel_unchecked(channel.id),
610            auth: PeerAuth::from_hash(channel.access_hash),
611        }
612    }
613}
614
615impl From<PeerId> for tl::enums::Peer {
616    #[inline]
617    fn from(peer: PeerId) -> Self {
618        <Self as From<&PeerId>>::from(&peer)
619    }
620}
621impl<'a> From<&'a PeerId> for tl::enums::Peer {
622    fn from(peer: &'a PeerId) -> Self {
623        match peer.kind() {
624            PeerKind::User => Self::User(tl::types::PeerUser {
625                user_id: peer.bare_id(),
626            }),
627            PeerKind::UserSelf => panic!("self-user ID not known"),
628            PeerKind::Chat => Self::Chat(tl::types::PeerChat {
629                chat_id: peer.bare_id(),
630            }),
631            PeerKind::Channel => Self::Channel(tl::types::PeerChannel {
632                channel_id: peer.bare_id(),
633            }),
634        }
635    }
636}
637
638impl From<PeerRef> for tl::enums::InputPeer {
639    #[inline]
640    fn from(peer: PeerRef) -> Self {
641        <Self as From<&PeerRef>>::from(&peer)
642    }
643}
644impl<'a> From<&'a PeerRef> for tl::enums::InputPeer {
645    fn from(peer: &'a PeerRef) -> Self {
646        match peer.id.kind() {
647            PeerKind::User => Self::User(tl::types::InputPeerUser {
648                user_id: peer.id.bare_id(),
649                access_hash: peer.auth.hash(),
650            }),
651            PeerKind::UserSelf => Self::PeerSelf,
652            PeerKind::Chat => Self::Chat(tl::types::InputPeerChat {
653                chat_id: peer.id.bare_id(),
654            }),
655            PeerKind::Channel => Self::Channel(tl::types::InputPeerChannel {
656                channel_id: peer.id.bare_id(),
657                access_hash: peer.auth.hash(),
658            }),
659        }
660    }
661}
662
663impl From<PeerRef> for tl::enums::InputUser {
664    #[inline]
665    fn from(peer: PeerRef) -> Self {
666        <Self as From<&PeerRef>>::from(&peer)
667    }
668}
669impl<'a> From<&'a PeerRef> for tl::enums::InputUser {
670    fn from(peer: &'a PeerRef) -> Self {
671        match peer.id.kind() {
672            PeerKind::User => Self::User(tl::types::InputUser {
673                user_id: peer.id.bare_id(),
674                access_hash: peer.auth.hash(),
675            }),
676            PeerKind::UserSelf => Self::UserSelf,
677            PeerKind::Chat => Self::Empty,
678            PeerKind::Channel => Self::Empty,
679        }
680    }
681}
682
683impl From<PeerRef> for i64 {
684    #[inline]
685    fn from(peer: PeerRef) -> Self {
686        <Self as From<&PeerRef>>::from(&peer)
687    }
688}
689impl<'a> From<&'a PeerRef> for i64 {
690    fn from(peer: &'a PeerRef) -> Self {
691        match peer.id.kind() {
692            PeerKind::User => EMPTY_CHAT_ID,
693            PeerKind::UserSelf => EMPTY_CHAT_ID,
694            PeerKind::Chat => peer.id.bare_id(),
695            PeerKind::Channel => EMPTY_CHAT_ID,
696        }
697    }
698}
699
700impl From<PeerRef> for tl::enums::InputChannel {
701    #[inline]
702    fn from(peer: PeerRef) -> Self {
703        <Self as From<&PeerRef>>::from(&peer)
704    }
705}
706impl<'a> From<&'a PeerRef> for tl::enums::InputChannel {
707    fn from(peer: &'a PeerRef) -> Self {
708        match peer.id.kind() {
709            PeerKind::User => Self::Empty,
710            PeerKind::UserSelf => Self::Empty,
711            PeerKind::Chat => Self::Empty,
712            PeerKind::Channel => Self::Channel(tl::types::InputChannel {
713                channel_id: peer.id.bare_id(),
714                access_hash: peer.auth.hash(),
715            }),
716        }
717    }
718}
719
720impl From<tl::enums::Chat> for PeerInfo {
721    #[inline]
722    fn from(chat: tl::enums::Chat) -> Self {
723        <Self as From<&tl::enums::Chat>>::from(&chat)
724    }
725}
726impl<'a> From<&'a tl::enums::Chat> for PeerInfo {
727    fn from(chat: &'a tl::enums::Chat) -> Self {
728        match chat {
729            tl::enums::Chat::Chat(chat) => <Self as From<&tl::types::Chat>>::from(&chat),
730            tl::enums::Chat::Empty(chat) => <Self as From<&tl::types::ChatEmpty>>::from(&chat),
731            tl::enums::Chat::Forbidden(chat) => {
732                <Self as From<&tl::types::ChatForbidden>>::from(&chat)
733            }
734            tl::enums::Chat::Channel(channel) => {
735                <Self as From<&tl::types::Channel>>::from(&channel)
736            }
737            tl::enums::Chat::ChannelForbidden(channel) => {
738                <Self as From<&tl::types::ChannelForbidden>>::from(&channel)
739            }
740        }
741    }
742}
743
744impl From<tl::enums::User> for PeerInfo {
745    #[inline]
746    fn from(user: tl::enums::User) -> Self {
747        <Self as From<&tl::enums::User>>::from(&user)
748    }
749}
750impl<'a> From<&'a tl::enums::User> for PeerInfo {
751    fn from(user: &'a tl::enums::User) -> Self {
752        match user {
753            tl::enums::User::User(user) => <Self as From<&tl::types::User>>::from(&user),
754            tl::enums::User::Empty(user) => <Self as From<&tl::types::UserEmpty>>::from(&user),
755        }
756    }
757}
758
759impl From<tl::types::User> for PeerInfo {
760    #[inline]
761    fn from(user: tl::types::User) -> Self {
762        <Self as From<&tl::types::User>>::from(&user)
763    }
764}
765impl<'a> From<&'a tl::types::User> for PeerInfo {
766    fn from(user: &'a tl::types::User) -> Self {
767        Self::User {
768            id: user.id,
769            auth: user.access_hash.map(PeerAuth),
770            bot: Some(user.bot),
771            is_self: Some(user.is_self),
772        }
773    }
774}
775
776impl From<tl::types::UserEmpty> for PeerInfo {
777    #[inline]
778    fn from(user: tl::types::UserEmpty) -> Self {
779        <Self as From<&tl::types::UserEmpty>>::from(&user)
780    }
781}
782impl<'a> From<&'a tl::types::UserEmpty> for PeerInfo {
783    fn from(user: &'a tl::types::UserEmpty) -> Self {
784        Self::User {
785            id: user.id,
786            auth: None,
787            bot: None,
788            is_self: None,
789        }
790    }
791}
792
793impl From<tl::types::Chat> for PeerInfo {
794    #[inline]
795    fn from(chat: tl::types::Chat) -> Self {
796        <Self as From<&tl::types::Chat>>::from(&chat)
797    }
798}
799impl<'a> From<&'a tl::types::Chat> for PeerInfo {
800    fn from(chat: &'a tl::types::Chat) -> Self {
801        Self::Chat { id: chat.id }
802    }
803}
804
805impl From<tl::types::ChatEmpty> for PeerInfo {
806    #[inline]
807    fn from(chat: tl::types::ChatEmpty) -> Self {
808        <Self as From<&tl::types::ChatEmpty>>::from(&chat)
809    }
810}
811impl<'a> From<&'a tl::types::ChatEmpty> for PeerInfo {
812    fn from(chat: &'a tl::types::ChatEmpty) -> Self {
813        Self::Chat { id: chat.id }
814    }
815}
816
817impl From<tl::types::ChatForbidden> for PeerInfo {
818    #[inline]
819    fn from(chat: tl::types::ChatForbidden) -> Self {
820        <Self as From<&tl::types::ChatForbidden>>::from(&chat)
821    }
822}
823impl<'a> From<&'a tl::types::ChatForbidden> for PeerInfo {
824    fn from(chat: &'a tl::types::ChatForbidden) -> Self {
825        Self::Chat { id: chat.id }
826    }
827}
828
829impl From<tl::types::Channel> for PeerInfo {
830    #[inline]
831    fn from(channel: tl::types::Channel) -> Self {
832        <Self as From<&tl::types::Channel>>::from(&channel)
833    }
834}
835impl<'a> From<&'a tl::types::Channel> for PeerInfo {
836    fn from(channel: &'a tl::types::Channel) -> Self {
837        Self::Channel {
838            id: channel.id,
839            auth: channel.access_hash.map(PeerAuth),
840            kind: <ChannelKind as TryFrom<&'a tl::types::Channel>>::try_from(channel).ok(),
841        }
842    }
843}
844
845impl From<tl::types::ChannelForbidden> for PeerInfo {
846    #[inline]
847    fn from(channel: tl::types::ChannelForbidden) -> Self {
848        <Self as From<&tl::types::ChannelForbidden>>::from(&channel)
849    }
850}
851impl<'a> From<&'a tl::types::ChannelForbidden> for PeerInfo {
852    fn from(channel: &'a tl::types::ChannelForbidden) -> Self {
853        Self::Channel {
854            id: channel.id,
855            auth: Some(PeerAuth(channel.access_hash)),
856            kind: <ChannelKind as TryFrom<&'a tl::types::ChannelForbidden>>::try_from(channel).ok(),
857        }
858    }
859}
860
861impl TryFrom<tl::types::Channel> for ChannelKind {
862    type Error = <ChannelKind as TryFrom<&'static tl::types::Channel>>::Error;
863
864    #[inline]
865    fn try_from(channel: tl::types::Channel) -> Result<Self, Self::Error> {
866        <ChannelKind as TryFrom<&tl::types::Channel>>::try_from(&channel)
867    }
868}
869impl<'a> TryFrom<&'a tl::types::Channel> for ChannelKind {
870    type Error = ();
871
872    fn try_from(channel: &'a tl::types::Channel) -> Result<Self, Self::Error> {
873        match channel {
874            channel if channel.gigagroup => Ok(Self::Gigagroup),
875            channel if channel.broadcast => Ok(Self::Broadcast),
876            channel if channel.megagroup => Ok(Self::Megagroup),
877            _channel => Err(()),
878        }
879    }
880}
881
882impl TryFrom<tl::types::ChannelForbidden> for ChannelKind {
883    type Error = <ChannelKind as TryFrom<&'static tl::types::ChannelForbidden>>::Error;
884
885    #[inline]
886    fn try_from(channel: tl::types::ChannelForbidden) -> Result<Self, Self::Error> {
887        <ChannelKind as TryFrom<&tl::types::ChannelForbidden>>::try_from(&channel)
888    }
889}
890impl<'a> TryFrom<&'a tl::types::ChannelForbidden> for ChannelKind {
891    type Error = ();
892
893    fn try_from(channel: &'a tl::types::ChannelForbidden) -> Result<Self, Self::Error> {
894        match channel {
895            // channel if channel.gigagroup => Ok(Self::Gigagroup),
896            channel if channel.broadcast => Ok(Self::Broadcast),
897            channel if channel.megagroup => Ok(Self::Megagroup),
898            _channel => Err(()),
899        }
900    }
901}