Skip to main content

layer_client/
peer_ref.rs

1//! [`PeerRef`]: flexible peer argument accepted by all `Client` methods.
2//!
3//! Every public API method that previously required a bare `tl::enums::Peer`
4//! now accepts `impl Into<PeerRef>`, so you can pass any of:
5//!
6//! ```rust,no_run
7//! # use layer_client::Client;
8//! # async fn f(client: Client) -> anyhow::Result<()> {
9//! // @username string
10//! client.send_message_to_peer("@durov", "hi").await?;
11//!
12//! // bare username (no @)
13//! client.send_message_to_peer("durov", "hi").await?;
14//!
15//! // "me" / "self"
16//! client.send_message_to_peer("me", "hi").await?;
17//!
18//! // numeric user ID (positive)
19//! client.send_message_to_peer(12345678_i64, "hi").await?;
20//!
21//! // Bot-API channel ID (negative, -100… prefix)
22//! client.iter_messages(-1001234567890_i64);
23//!
24//! // Bot-API basic-group ID (negative, small)
25//! client.mark_as_read(-123456_i64).await?;
26//!
27//! // already-resolved peer: zero overhead
28//! use layer_client::tl;
29//! let peer = tl::enums::Peer::User(tl::types::PeerUser { user_id: 123 });
30//! client.send_message_to_peer(peer, "hi").await?;
31//! # Ok(()) }
32//! ```
33
34use layer_tl_types as tl;
35
36/// Telegram channels / supergroups use this offset in the Bot API negative-ID
37/// encoding: `bot_api_id = -1_000_000_000_000 - channel_id`.
38const ZERO_CHANNEL_ID: i64 = -1_000_000_000_000;
39
40/// Flexible reference to a Telegram peer (user, basic group, or channel).
41///
42/// Construct via any of the `From` impls or by wrapping an already-resolved
43/// `tl::enums::Peer`.  Use `peer_ref.resolve(&client).await` to obtain the
44/// underlying `tl::enums::Peer`, performing a network lookup only when the
45/// username is not yet cached.
46#[derive(Clone, Debug)]
47pub enum PeerRef {
48    /// `"@username"`, `"username"`, `"me"`, or `"self"`.
49    Username(String),
50    /// Numeric ID.
51    ///
52    /// Positive → user.  
53    /// Negative above `−1 000 000 000 000` → basic group (`chat_id = -id`).  
54    /// Negative ≤ `−1 000 000 000 000` → channel/supergroup
55    /// (`channel_id = -id - 1_000_000_000_000`).
56    Id(i64),
57    /// Already-resolved TL peer: forwarded at zero cost.
58    Peer(tl::enums::Peer),
59}
60
61impl PeerRef {
62    /// Resolve this reference to a `tl::enums::Peer`.
63    ///
64    /// * `Peer` variant → returned immediately.
65    /// * `Id` variant   → decoded from Bot-API encoding, no network call.
66    /// * `Username` variant → may perform a `contacts.resolveUsername` RPC
67    /// if not already cached.
68    pub async fn resolve(
69        self,
70        client: &crate::Client,
71    ) -> Result<tl::enums::Peer, crate::InvocationError> {
72        match self {
73            PeerRef::Peer(p) => Ok(p),
74
75            PeerRef::Id(id) if id > 0 => {
76                Ok(tl::enums::Peer::User(tl::types::PeerUser { user_id: id }))
77            }
78            PeerRef::Id(id) if id <= ZERO_CHANNEL_ID => {
79                let channel_id = -id - 1_000_000_000_000;
80                Ok(tl::enums::Peer::Channel(tl::types::PeerChannel {
81                    channel_id,
82                }))
83            }
84            PeerRef::Id(id) => {
85                let chat_id = -id;
86                Ok(tl::enums::Peer::Chat(tl::types::PeerChat { chat_id }))
87            }
88
89            PeerRef::Username(s) => client.resolve_peer(&s).await,
90        }
91    }
92}
93
94impl From<&str> for PeerRef {
95    fn from(s: &str) -> Self {
96        PeerRef::Username(s.to_owned())
97    }
98}
99
100impl From<String> for PeerRef {
101    fn from(s: String) -> Self {
102        PeerRef::Username(s)
103    }
104}
105
106impl From<i64> for PeerRef {
107    fn from(id: i64) -> Self {
108        PeerRef::Id(id)
109    }
110}
111
112impl From<i32> for PeerRef {
113    fn from(id: i32) -> Self {
114        PeerRef::Id(id as i64)
115    }
116}
117
118impl From<tl::enums::Peer> for PeerRef {
119    fn from(p: tl::enums::Peer) -> Self {
120        PeerRef::Peer(p)
121    }
122}