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}