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_photo,
102 send_audio,
103 send_document,
104 send_video,
105 send_animation,
106 send_voice,
107 send_video_note,
108 send_paid_media,
109 send_media_group,
110 send_location,
111 edit_message_live_location,
112 edit_message_live_location_inline,
113 stop_message_live_location,
114 stop_message_live_location_inline,
115 edit_message_checklist,
116 send_venue,
117 send_contact,
118 send_poll,
119 send_checklist,
120 send_dice,
121 send_chat_action,
122 set_message_reaction,
123 get_user_profile_photos,
124 set_user_emoji_status,
125 get_file,
126 kick_chat_member,
127 ban_chat_member,
128 unban_chat_member,
129 restrict_chat_member,
130 promote_chat_member,
131 set_chat_administrator_custom_title,
132 ban_chat_sender_chat,
133 unban_chat_sender_chat,
134 set_chat_permissions,
135 export_chat_invite_link,
136 create_chat_invite_link,
137 edit_chat_invite_link,
138 create_chat_subscription_invite_link,
139 edit_chat_subscription_invite_link,
140 revoke_chat_invite_link,
141 set_chat_photo,
142 delete_chat_photo,
143 set_chat_title,
144 set_chat_description,
145 pin_chat_message,
146 unpin_chat_message,
147 unpin_all_chat_messages,
148 leave_chat,
149 get_chat,
150 get_chat_administrators,
151 get_chat_members_count,
152 get_chat_member_count,
153 get_chat_member,
154 set_chat_sticker_set,
155 delete_chat_sticker_set,
156 get_forum_topic_icon_stickers,
157 create_forum_topic,
158 edit_forum_topic,
159 close_forum_topic,
160 reopen_forum_topic,
161 delete_forum_topic,
162 unpin_all_forum_topic_messages,
163 edit_general_forum_topic,
164 close_general_forum_topic,
165 reopen_general_forum_topic,
166 hide_general_forum_topic,
167 unhide_general_forum_topic,
168 unpin_all_general_forum_topic_messages,
169 answer_callback_query,
170 get_user_chat_boosts,
171 set_my_commands,
172 get_business_connection,
173 get_my_commands,
174 set_my_name,
175 get_my_name,
176 set_my_description,
177 get_my_description,
178 set_my_short_description,
179 get_my_short_description,
180 set_chat_menu_button,
181 get_chat_menu_button,
182 set_my_default_administrator_rights,
183 get_my_default_administrator_rights,
184 delete_my_commands,
185 answer_inline_query,
186 answer_web_app_query,
187 save_prepared_inline_message,
188 edit_message_text,
189 edit_message_text_inline,
190 edit_message_caption,
191 edit_message_caption_inline,
192 edit_message_media,
193 edit_message_media_inline,
194 edit_message_reply_markup,
195 edit_message_reply_markup_inline,
196 stop_poll,
197 delete_message,
198 delete_messages,
199 send_sticker,
200 get_sticker_set,
201 get_custom_emoji_stickers,
202 upload_sticker_file,
203 create_new_sticker_set,
204 add_sticker_to_set,
205 set_sticker_position_in_set,
206 delete_sticker_from_set,
207 replace_sticker_in_set,
208 set_sticker_set_thumbnail,
209 set_custom_emoji_sticker_set_thumbnail,
210 set_sticker_set_title,
211 delete_sticker_set,
212 set_sticker_emoji_list,
213 set_sticker_keywords,
214 set_sticker_mask_position,
215 get_available_gifts,
216 send_gift,
217 send_gift_chat,
218 gift_premium_subscription,
219 verify_user,
220 verify_chat,
221 remove_user_verification,
222 remove_chat_verification,
223 read_business_message,
224 delete_business_messages,
225 set_business_account_name,
226 set_business_account_username,
227 set_business_account_bio,
228 set_business_account_profile_photo,
229 remove_business_account_profile_photo,
230 set_business_account_gift_settings,
231 get_business_account_star_balance,
232 transfer_business_account_stars,
233 get_business_account_gifts,
234 convert_gift_to_stars,
235 upgrade_gift,
236 transfer_gift,
237 post_story,
238 edit_story,
239 delete_story,
240 send_invoice,
241 create_invoice_link,
242 answer_shipping_query,
243 answer_pre_checkout_query,
244 get_my_star_balance,
245 get_star_transactions,
246 refund_star_payment,
247 edit_user_star_subscription,
248 set_passport_data_errors,
249 send_game,
250 set_game_score,
251 set_game_score_inline,
252 get_game_high_scores,
253 approve_chat_join_request,
254 decline_chat_join_request
255 => f, fty
256 }
257}
258
259download_forward! {
260 B
261 CacheMe<B>
262 { this => this.inner() }
263}
264
265#[must_use = "Requests are lazy and do nothing unless sent"]
266pub struct CachedMeRequest<R: Request<Payload = GetMe>>(Inner<R>, GetMe);
267
268enum Inner<R: Request<Payload = GetMe>> {
269 Ready(Me),
270 Pending(R, Arc<OnceCell<Me>>),
271}
272
273impl<R> Request for CachedMeRequest<R>
274where
275 R: Request<Payload = GetMe>,
276{
277 type Err = R::Err;
278 type Send = Send<R>;
279 type SendRef = SendRef<R>;
280
281 fn send(self) -> Self::Send {
282 let fut = match self.0 {
283 Inner::Ready(me) => future::Either::Left(ok(me)),
284 Inner::Pending(req, cell) => future::Either::Right(Init(req.send(), cell)),
285 };
286 Send(fut)
287 }
288
289 fn send_ref(&self) -> Self::SendRef {
290 let fut = match &self.0 {
291 Inner::Ready(me) => future::Either::Left(ok(me.clone())),
292 Inner::Pending(req, cell) => {
293 future::Either::Right(Init(req.send_ref(), Arc::clone(cell)))
294 }
295 };
296 SendRef(fut)
297 }
298}
299
300impl<R: Request<Payload = GetMe>> HasPayload for CachedMeRequest<R> {
301 type Payload = GetMe;
302
303 fn payload_mut(&mut self) -> &mut Self::Payload {
304 &mut self.1
305 }
306
307 fn payload_ref(&self) -> &Self::Payload {
308 &self.1
309 }
310}
311
312impl<R: Request<Payload = GetMe>> IntoFuture for CachedMeRequest<R> {
313 type Output = Result<Me, R::Err>;
314 type IntoFuture = Send<R>;
315
316 fn into_future(self) -> Self::IntoFuture {
317 self.send()
318 }
319}
320
321type ReadyMe<Err> = Ready<Result<Me, Err>>;
322
323#[pin_project::pin_project]
324pub struct Send<R: Request<Payload = GetMe>>(
325 #[pin] future::Either<ReadyMe<R::Err>, Init<R::Send, Me>>,
326);
327
328impl<R: Request<Payload = GetMe>> Future for Send<R> {
329 type Output = Result<Me, R::Err>;
330
331 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
332 let this = self.project();
333 this.0.poll(cx)
334 }
335}
336
337#[pin_project::pin_project]
338pub struct SendRef<R: Request<Payload = GetMe>>(
339 #[pin] future::Either<ReadyMe<R::Err>, Init<R::SendRef, Me>>,
340);
341
342impl<R: Request<Payload = GetMe>> Future for SendRef<R> {
343 type Output = Result<Me, R::Err>;
344
345 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
346 let this = self.project();
347 this.0.poll(cx)
348 }
349}
350
351#[pin_project::pin_project]
352struct Init<F, T>(#[pin] F, Arc<OnceCell<T>>);
353
354impl<F: Future<Output = Result<T, E>>, T: Clone, E> Future for Init<F, T> {
355 type Output = Result<T, E>;
356
357 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
358 let this = self.project();
359 match this.0.poll(cx) {
360 Poll::Ready(Ok(ok)) => Poll::Ready(Ok(this.1.get_or_init(|| ok).clone())),
361 poll @ Poll::Ready(_) | poll @ Poll::Pending => poll,
362 }
363 }
364}