layer_client/peer_ref.rs
1// Copyright (c) Ankit Chaubey <ankitchaubey.dev@gmail.com>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4// NOTE:
5// The "Layer" project is no longer maintained or supported.
6// Its original purpose for personal SDK/APK experimentation and learning
7// has been fulfilled.
8//
9// Please use Ferogram instead:
10// https://github.com/ankit-chaubey/ferogram
11// Ferogram will receive future updates and development, although progress
12// may be slower.
13//
14// Ferogram is an async Telegram MTProto client library written in Rust.
15// Its implementation follows the behaviour of the official Telegram clients,
16// particularly Telegram Desktop and TDLib, and aims to provide a clean and
17// modern async interface for building Telegram clients and tools.
18
19//! [`PeerRef`]: flexible peer argument accepted by all `Client` methods.
20//!
21//! Every public API method that previously required a bare `tl::enums::Peer`
22//! now accepts `impl Into<PeerRef>`, so you can pass any of:
23//!
24//! ```rust,no_run
25//! # use layer_client::Client;
26//! # async fn f(client: Client) -> anyhow::Result<()> {
27//! // @username string
28//! client.send_message_to_peer("@durov", "hi").await?;
29//!
30//! // bare username (no @)
31//! client.send_message_to_peer("durov", "hi").await?;
32//!
33//! // "me" / "self"
34//! client.send_message_to_peer("me", "hi").await?;
35//!
36//! // numeric user ID (positive)
37//! client.send_message_to_peer(12345678_i64, "hi").await?;
38//!
39//! // Bot-API channel ID (negative, -100… prefix)
40//! client.iter_messages(-1001234567890_i64);
41//!
42//! // Bot-API basic-group ID (negative, small)
43//! client.mark_as_read(-123456_i64).await?;
44//!
45//! // already-resolved peer: zero overhead
46//! use layer_client::tl;
47//! let peer = tl::enums::Peer::User(tl::types::PeerUser { user_id: 123 });
48//! client.send_message_to_peer(peer, "hi").await?;
49//! # Ok(()) }
50//! ```
51
52use layer_tl_types as tl;
53
54/// Telegram channels / supergroups use this offset in the Bot API negative-ID
55/// encoding: `bot_api_id = -1_000_000_000_000 - channel_id`.
56const ZERO_CHANNEL_ID: i64 = -1_000_000_000_000;
57
58/// Flexible reference to a Telegram peer (user, basic group, or channel).
59///
60/// Construct via any of the `From` impls or by wrapping an already-resolved
61/// `tl::enums::Peer`. Use `peer_ref.resolve(&client).await` to obtain the
62/// underlying `tl::enums::Peer`, performing a network lookup only when the
63/// username is not yet cached.
64#[derive(Clone, Debug)]
65pub enum PeerRef {
66 /// `"@username"`, `"username"`, `"me"`, or `"self"`.
67 Username(String),
68 /// Numeric ID.
69 ///
70 /// Positive → user.
71 /// Negative above `−1 000 000 000 000` → basic group (`chat_id = -id`).
72 /// Negative ≤ `−1 000 000 000 000` → channel/supergroup
73 /// (`channel_id = -id - 1_000_000_000_000`).
74 Id(i64),
75 /// Already-resolved TL peer: forwarded at zero cost.
76 Peer(tl::enums::Peer),
77}
78
79impl PeerRef {
80 /// Resolve this reference to a `tl::enums::Peer`.
81 ///
82 /// * `Peer` variant → returned immediately.
83 /// * `Id` variant → decoded from Bot-API encoding, no network call.
84 /// * `Username` variant → may perform a `contacts.resolveUsername` RPC
85 /// if not already cached.
86 pub async fn resolve(
87 self,
88 client: &crate::Client,
89 ) -> Result<tl::enums::Peer, crate::InvocationError> {
90 match self {
91 PeerRef::Peer(p) => Ok(p),
92
93 PeerRef::Id(id) if id > 0 => {
94 Ok(tl::enums::Peer::User(tl::types::PeerUser { user_id: id }))
95 }
96 PeerRef::Id(id) if id <= ZERO_CHANNEL_ID => {
97 let channel_id = -id - 1_000_000_000_000;
98 Ok(tl::enums::Peer::Channel(tl::types::PeerChannel {
99 channel_id,
100 }))
101 }
102 PeerRef::Id(id) => {
103 let chat_id = -id;
104 Ok(tl::enums::Peer::Chat(tl::types::PeerChat { chat_id }))
105 }
106
107 PeerRef::Username(s) => client.resolve_peer(&s).await,
108 }
109 }
110}
111
112impl From<&str> for PeerRef {
113 fn from(s: &str) -> Self {
114 PeerRef::Username(s.to_owned())
115 }
116}
117
118impl From<String> for PeerRef {
119 fn from(s: String) -> Self {
120 PeerRef::Username(s)
121 }
122}
123
124impl From<i64> for PeerRef {
125 fn from(id: i64) -> Self {
126 PeerRef::Id(id)
127 }
128}
129
130impl From<i32> for PeerRef {
131 fn from(id: i32) -> Self {
132 PeerRef::Id(id as i64)
133 }
134}
135
136impl From<tl::enums::Peer> for PeerRef {
137 fn from(p: tl::enums::Peer) -> Self {
138 PeerRef::Peer(p)
139 }
140}