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