1use std::{future::IntoFuture, pin::Pin, sync::Arc};
2
3use futures::{
4 future,
5 future::{ok, Ready},
6 task::{Context, Poll},
7 Future,
8};
9use once_cell::sync::OnceCell;
10use url::Url;
11
12use crate::{
13 payloads::GetMe,
14 requests::{HasPayload, Request, Requester},
15 types::*,
16};
17
18#[derive(Clone, Debug)]
23pub struct CacheMe<B> {
24 bot: B,
25 me: Arc<OnceCell<Me>>,
26}
27
28impl<B> CacheMe<B> {
29 pub fn new(bot: B) -> CacheMe<B> {
35 Self { bot, me: Arc::new(OnceCell::new()) }
36 }
37
38 pub fn inner(&self) -> &B {
40 &self.bot
41 }
42
43 pub fn into_inner(self) -> B {
45 self.bot
46 }
47
48 pub fn clear(&mut self) -> Option<Me> {
55 Arc::make_mut(&mut self.me).take()
56 }
57}
58
59macro_rules! f {
60 ($m:ident $this:ident ($($arg:ident : $T:ty),*)) => {
61 $this.inner().$m($($arg),*)
62 };
63}
64
65macro_rules! fty {
66 ($T:ident) => {
67 B::$T
68 };
69}
70
71impl<B> Requester for CacheMe<B>
72where
73 B: Requester,
74{
75 type Err = B::Err;
76
77 type GetMe = CachedMeRequest<B::GetMe>;
78
79 fn get_me(&self) -> Self::GetMe {
80 match self.me.get() {
81 Some(me) => CachedMeRequest(Inner::Ready(me.clone()), GetMe::new()),
82 None => CachedMeRequest(
83 Inner::Pending(self.bot.get_me(), Arc::clone(&self.me)),
84 GetMe::new(),
85 ),
86 }
87 }
88
89 requester_forward! {
90 log_out,
91 close,
92 get_updates,
93 set_webhook,
94 delete_webhook,
95 get_webhook_info,
96 forward_message,
97 forward_messages,
98 copy_message,
99 copy_messages,
100 send_message,
101 send_message_draft,
102 send_rich_message,
103 send_rich_message_draft,
104 send_photo,
105 send_audio,
106 send_document,
107 send_video,
108 send_animation,
109 send_voice,
110 send_video_note,
111 send_paid_media,
112 send_media_group,
113 send_location,
114 edit_message_live_location,
115 edit_message_live_location_inline,
116 stop_message_live_location,
117 stop_message_live_location_inline,
118 edit_message_checklist,
119 send_venue,
120 send_contact,
121 send_poll,
122 send_checklist,
123 send_dice,
124 send_chat_action,
125 set_message_reaction,
126 get_user_profile_photos,
127 get_user_profile_audios,
128 set_user_emoji_status,
129 get_file,
130 kick_chat_member,
131 ban_chat_member,
132 unban_chat_member,
133 restrict_chat_member,
134 promote_chat_member,
135 set_chat_administrator_custom_title,
136 set_chat_member_tag,
137 ban_chat_sender_chat,
138 unban_chat_sender_chat,
139 set_chat_permissions,
140 export_chat_invite_link,
141 create_chat_invite_link,
142 edit_chat_invite_link,
143 create_chat_subscription_invite_link,
144 edit_chat_subscription_invite_link,
145 revoke_chat_invite_link,
146 set_chat_photo,
147 delete_chat_photo,
148 set_chat_title,
149 set_chat_description,
150 pin_chat_message,
151 unpin_chat_message,
152 unpin_all_chat_messages,
153 leave_chat,
154 get_chat,
155 get_chat_administrators,
156 get_chat_members_count,
157 get_chat_member_count,
158 get_chat_member,
159 set_chat_sticker_set,
160 delete_chat_sticker_set,
161 get_forum_topic_icon_stickers,
162 create_forum_topic,
163 edit_forum_topic,
164 close_forum_topic,
165 reopen_forum_topic,
166 delete_forum_topic,
167 unpin_all_forum_topic_messages,
168 edit_general_forum_topic,
169 close_general_forum_topic,
170 reopen_general_forum_topic,
171 hide_general_forum_topic,
172 unhide_general_forum_topic,
173 unpin_all_general_forum_topic_messages,
174 answer_callback_query,
175 get_user_chat_boosts,
176 set_my_commands,
177 get_business_connection,
178 get_my_commands,
179 set_my_name,
180 get_my_name,
181 set_my_description,
182 get_my_description,
183 set_my_short_description,
184 get_my_short_description,
185 set_my_profile_photo,
186 remove_my_profile_photo,
187 get_managed_bot_token,
188 replace_managed_bot_token,
189 save_prepared_keyboard_button,
190 send_live_photo,
191 get_user_personal_chat_messages,
192 answer_guest_query,
193 get_managed_bot_access_settings,
194 set_managed_bot_access_settings,
195 delete_message_reaction,
196 delete_all_message_reactions,
197 set_chat_menu_button,
198 get_chat_menu_button,
199 set_my_default_administrator_rights,
200 get_my_default_administrator_rights,
201 delete_my_commands,
202 answer_inline_query,
203 answer_web_app_query,
204 save_prepared_inline_message,
205 edit_message_text,
206 edit_message_text_inline,
207 edit_message_caption,
208 edit_message_caption_inline,
209 edit_message_media,
210 edit_message_media_inline,
211 edit_message_reply_markup,
212 edit_message_reply_markup_inline,
213 stop_poll,
214 approve_suggested_post,
215 decline_suggested_post,
216 delete_message,
217 delete_messages,
218 send_sticker,
219 get_sticker_set,
220 get_custom_emoji_stickers,
221 upload_sticker_file,
222 create_new_sticker_set,
223 add_sticker_to_set,
224 set_sticker_position_in_set,
225 delete_sticker_from_set,
226 replace_sticker_in_set,
227 set_sticker_set_thumbnail,
228 set_custom_emoji_sticker_set_thumbnail,
229 set_sticker_set_title,
230 delete_sticker_set,
231 set_sticker_emoji_list,
232 set_sticker_keywords,
233 set_sticker_mask_position,
234 get_available_gifts,
235 send_gift,
236 send_gift_chat,
237 gift_premium_subscription,
238 verify_user,
239 verify_chat,
240 remove_user_verification,
241 remove_chat_verification,
242 read_business_message,
243 delete_business_messages,
244 set_business_account_name,
245 set_business_account_username,
246 set_business_account_bio,
247 set_business_account_profile_photo,
248 remove_business_account_profile_photo,
249 set_business_account_gift_settings,
250 get_business_account_star_balance,
251 transfer_business_account_stars,
252 get_business_account_gifts,
253 get_user_gifts,
254 get_chat_gifts,
255 convert_gift_to_stars,
256 upgrade_gift,
257 transfer_gift,
258 post_story,
259 repost_story,
260 edit_story,
261 delete_story,
262 send_invoice,
263 create_invoice_link,
264 answer_shipping_query,
265 answer_pre_checkout_query,
266 get_my_star_balance,
267 get_star_transactions,
268 refund_star_payment,
269 edit_user_star_subscription,
270 set_passport_data_errors,
271 send_game,
272 set_game_score,
273 set_game_score_inline,
274 get_game_high_scores,
275 approve_chat_join_request,
276 decline_chat_join_request,
277 answer_chat_join_request_query,
278 send_chat_join_request_web_app,
279 edit_ephemeral_message_text,
280 edit_ephemeral_message_media,
281 edit_ephemeral_message_caption,
282 edit_ephemeral_message_reply_markup,
283 delete_ephemeral_message
284 => f, fty
285 }
286}
287
288download_forward! {
289 B
290 CacheMe<B>
291 { this => this.inner() }
292}
293
294#[must_use = "Requests are lazy and do nothing unless sent"]
295pub struct CachedMeRequest<R: Request<Payload = GetMe>>(Inner<R>, GetMe);
296
297enum Inner<R: Request<Payload = GetMe>> {
298 Ready(Me),
299 Pending(R, Arc<OnceCell<Me>>),
300}
301
302impl<R> Request for CachedMeRequest<R>
303where
304 R: Request<Payload = GetMe>,
305{
306 type Err = R::Err;
307 type Send = Send<R>;
308 type SendRef = SendRef<R>;
309
310 fn send(self) -> Self::Send {
311 let fut = match self.0 {
312 Inner::Ready(me) => future::Either::Left(ok(me)),
313 Inner::Pending(req, cell) => future::Either::Right(Init(req.send(), cell)),
314 };
315 Send(fut)
316 }
317
318 fn send_ref(&self) -> Self::SendRef {
319 let fut = match &self.0 {
320 Inner::Ready(me) => future::Either::Left(ok(me.clone())),
321 Inner::Pending(req, cell) => {
322 future::Either::Right(Init(req.send_ref(), Arc::clone(cell)))
323 }
324 };
325 SendRef(fut)
326 }
327}
328
329impl<R: Request<Payload = GetMe>> HasPayload for CachedMeRequest<R> {
330 type Payload = GetMe;
331
332 fn payload_mut(&mut self) -> &mut Self::Payload {
333 &mut self.1
334 }
335
336 fn payload_ref(&self) -> &Self::Payload {
337 &self.1
338 }
339}
340
341impl<R: Request<Payload = GetMe>> IntoFuture for CachedMeRequest<R> {
342 type Output = Result<Me, R::Err>;
343 type IntoFuture = Send<R>;
344
345 fn into_future(self) -> Self::IntoFuture {
346 self.send()
347 }
348}
349
350type ReadyMe<Err> = Ready<Result<Me, Err>>;
351
352#[pin_project::pin_project]
353pub struct Send<R: Request<Payload = GetMe>>(
354 #[pin] future::Either<ReadyMe<R::Err>, Init<R::Send, Me>>,
355);
356
357impl<R: Request<Payload = GetMe>> Future for Send<R> {
358 type Output = Result<Me, R::Err>;
359
360 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
361 let this = self.project();
362 this.0.poll(cx)
363 }
364}
365
366#[pin_project::pin_project]
367pub struct SendRef<R: Request<Payload = GetMe>>(
368 #[pin] future::Either<ReadyMe<R::Err>, Init<R::SendRef, Me>>,
369);
370
371impl<R: Request<Payload = GetMe>> Future for SendRef<R> {
372 type Output = Result<Me, R::Err>;
373
374 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
375 let this = self.project();
376 this.0.poll(cx)
377 }
378}
379
380#[pin_project::pin_project]
381struct Init<F, T>(#[pin] F, Arc<OnceCell<T>>);
382
383impl<F: Future<Output = Result<T, E>>, T: Clone, E> Future for Init<F, T> {
384 type Output = Result<T, E>;
385
386 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
387 let this = self.project();
388 match this.0.poll(cx) {
389 Poll::Ready(Ok(ok)) => Poll::Ready(Ok(this.1.get_or_init(|| ok).clone())),
390 poll @ Poll::Ready(_) | poll @ Poll::Pending => poll,
391 }
392 }
393}