diff --git a/README.md b/README.md index c3c500f52c9..cd834f1125f 100644 --- a/README.md +++ b/README.md @@ -182,7 +182,10 @@ async fn handle_event( ) -> Result<(), Box> { match event { Event::MessageCreate(msg) if msg.content == "!ping" => { - http.create_message(msg.channel_id).content("Pong!")?.await?; + http.create_message(msg.channel_id) + .content("Pong!")? + .exec() + .await?; } Event::ShardConnected(_) => { println!("Connected on shard {}", shard_id); diff --git a/gateway/queue/src/day_limiter.rs b/gateway/queue/src/day_limiter.rs index c55ea44d21a..52d45ee51ee 100644 --- a/gateway/queue/src/day_limiter.rs +++ b/gateway/queue/src/day_limiter.rs @@ -59,6 +59,7 @@ impl DayLimiter { let info = http .gateway() .authed() + .exec() .await .map_err(|source| DayLimiterError { kind: DayLimiterErrorType::RetrievingSessionAvailability, @@ -94,7 +95,7 @@ impl DayLimiter { } else { let wait = lock.last_check + lock.next_reset; time::sleep_until(wait).await; - if let Ok(res) = lock.http.gateway().authed().await { + if let Ok(res) = lock.http.gateway().authed().exec().await { if let Ok(info) = res.model().await { let last_check = Instant::now(); let next_reset = Duration::from_millis(info.session_start_limit.remaining); diff --git a/gateway/src/cluster/builder.rs b/gateway/src/cluster/builder.rs index 273c10e65e5..b867deb17c6 100644 --- a/gateway/src/cluster/builder.rs +++ b/gateway/src/cluster/builder.rs @@ -78,7 +78,7 @@ impl ClusterBuilder { /// [`ClusterStartErrorType::RetrievingGatewayInfo`]: super::ClusterStartErrorType::RetrievingGatewayInfo pub async fn build(mut self) -> Result<(Cluster, Events), ClusterStartError> { if (self.1).0.gateway_url.is_none() { - let maybe_response = (self.1).0.http_client.gateway().authed().await; + let maybe_response = (self.1).0.http_client.gateway().authed().exec().await; if let Ok(response) = maybe_response { let gateway_url = response.model().await.ok().map(|info| info.url); diff --git a/gateway/src/cluster/impl.rs b/gateway/src/cluster/impl.rs index 26b6fd66ee5..6d95266c672 100644 --- a/gateway/src/cluster/impl.rs +++ b/gateway/src/cluster/impl.rs @@ -356,6 +356,7 @@ impl Cluster { let gateway = http .gateway() .authed() + .exec() .await .map_err(|source| ClusterStartError { kind: ClusterStartErrorType::RetrievingGatewayInfo, diff --git a/gateway/src/shard/impl.rs b/gateway/src/shard/impl.rs index caebe58565c..79780fbc8d3 100644 --- a/gateway/src/shard/impl.rs +++ b/gateway/src/shard/impl.rs @@ -451,6 +451,7 @@ impl Shard { .http_client() .gateway() .authed() + .exec() .await .map_err(|source| ShardStartError { source: Some(Box::new(source)), diff --git a/http/examples/allowed-mentions/src/main.rs b/http/examples/allowed-mentions/src/main.rs index 8d11c9fc733..630d546adc1 100644 --- a/http/examples/allowed-mentions/src/main.rs +++ b/http/examples/allowed-mentions/src/main.rs @@ -32,6 +32,7 @@ async fn main() -> Result<(), Box> { .user_ids(vec![user_id]) .build(), ) + .exec() .await?; Ok(()) diff --git a/http/examples/get-message/src/main.rs b/http/examples/get-message/src/main.rs index 258508948a2..a35b070a0a6 100644 --- a/http/examples/get-message/src/main.rs +++ b/http/examples/get-message/src/main.rs @@ -16,10 +16,11 @@ async fn main() -> Result<(), Box> { .create_message(channel_id) .content(format!("Ping #{}", x)) .expect("content not a valid length") + .exec() })) .await; - let me = client.current_user().await?.model().await?; + let me = client.current_user().exec().await?.model().await?; println!("Current user: {}#{}", me.name, me.discriminator); Ok(()) diff --git a/http/examples/proxy/src/main.rs b/http/examples/proxy/src/main.rs index 782269367c5..275aadf0207 100644 --- a/http/examples/proxy/src/main.rs +++ b/http/examples/proxy/src/main.rs @@ -19,10 +19,11 @@ async fn main() -> Result<(), Box> { .create_message(channel_id) .content(format!("Ping #{}", x)) .expect("content not a valid length") + .exec() })) .await; - let me = client.current_user().await?.model().await?; + let me = client.current_user().exec().await?.model().await?; println!("Current user: {}#{}", me.name, me.discriminator); Ok(()) diff --git a/http/src/client/builder.rs b/http/src/client/builder.rs index ed5404246ee..822fe9d991f 100644 --- a/http/src/client/builder.rs +++ b/http/src/client/builder.rs @@ -51,7 +51,7 @@ impl ClientBuilder { proxy: self.proxy, ratelimiter: self.ratelimiter, timeout: self.timeout, - token_invalid: AtomicBool::new(false), + token_invalid: Arc::new(AtomicBool::new(false)), token: self.token, application_id: self.application_id, default_allowed_mentions: self.default_allowed_mentions, diff --git a/http/src/client/mod.rs b/http/src/client/mod.rs index e1d7dcca787..90741314a26 100644 --- a/http/src/client/mod.rs +++ b/http/src/client/mod.rs @@ -3,9 +3,8 @@ mod builder; pub use self::builder::ClientBuilder; use crate::{ - api_error::ApiError, error::{Error, ErrorType}, - ratelimiting::{RatelimitHeaders, Ratelimiter}, + ratelimiting::Ratelimiter, request::{ application::{ CreateFollowupMessage, CreateGlobalCommand, CreateGuildCommand, DeleteFollowupMessage, @@ -23,14 +22,13 @@ use crate::{ prelude::*, GetUserApplicationInfo, Method, Request, }, - response::{Response, StatusCode}, + response::ResponseFuture, API_VERSION, }; use hyper::{ - body, client::{Client as HyperClient, HttpConnector}, header::{HeaderMap, HeaderValue, AUTHORIZATION, CONTENT_LENGTH, CONTENT_TYPE, USER_AGENT}, - Body, StatusCode as HyperStatusCode, + Body, }; use std::{ convert::TryFrom, @@ -66,7 +64,7 @@ struct State { proxy: Option>, ratelimiter: Option, timeout: Duration, - token_invalid: AtomicBool, + token_invalid: Arc, token: Option>, use_http: bool, pub(crate) application_id: AtomicU64, @@ -233,6 +231,7 @@ impl Client { /// let audit_log = client /// // not done /// .audit_log(guild_id) + /// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -256,17 +255,17 @@ impl Client { /// # /// let guild_id = GuildId(1); /// - /// let bans = client.bans(guild_id).await?; + /// let bans = client.bans(guild_id).exec().await?; /// # Ok(()) } /// ``` - pub fn bans(&self, guild_id: GuildId) -> GetBans<'_> { + pub const fn bans(&self, guild_id: GuildId) -> GetBans<'_> { GetBans::new(self, guild_id) } /// Get information about a ban of a guild. /// /// Includes the user banned and the reason. - pub fn ban(&self, guild_id: GuildId, user_id: UserId) -> GetBan<'_> { + pub const fn ban(&self, guild_id: GuildId, user_id: UserId) -> GetBan<'_> { GetBan::new(self, guild_id, user_id) } @@ -291,6 +290,7 @@ impl Client { /// client.create_ban(guild_id, user_id) /// .delete_message_days(1)? /// .reason("memes")? + /// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -315,10 +315,10 @@ impl Client { /// let guild_id = GuildId(100); /// let user_id = UserId(200); /// - /// client.delete_ban(guild_id, user_id).await?; + /// client.delete_ban(guild_id, user_id).exec().await?; /// # Ok(()) } /// ``` - pub fn delete_ban(&self, guild_id: GuildId, user_id: UserId) -> DeleteBan<'_> { + pub const fn delete_ban(&self, guild_id: GuildId, user_id: UserId) -> DeleteBan<'_> { DeleteBan::new(self, guild_id, user_id) } @@ -338,15 +338,15 @@ impl Client { /// # /// let channel_id = ChannelId(100); /// # - /// let channel = client.channel(channel_id).await?; + /// let channel = client.channel(channel_id).exec().await?; /// # Ok(()) } /// ``` - pub fn channel(&self, channel_id: ChannelId) -> GetChannel<'_> { + pub const fn channel(&self, channel_id: ChannelId) -> GetChannel<'_> { GetChannel::new(self, channel_id) } /// Delete a channel by ID. - pub fn delete_channel(&self, channel_id: ChannelId) -> DeleteChannel<'_> { + pub const fn delete_channel(&self, channel_id: ChannelId) -> DeleteChannel<'_> { DeleteChannel::new(self, channel_id) } @@ -360,7 +360,7 @@ impl Client { /// The type returned is [`FollowedChannel`]. /// /// [`FollowedChannel`]: ::twilight_model::channel::FollowedChannel - pub fn follow_news_channel( + pub const fn follow_news_channel( &self, channel_id: ChannelId, webhook_channel_id: ChannelId, @@ -375,7 +375,7 @@ impl Client { /// /// [`MANAGE_CHANNELS`]: twilight_model::guild::Permissions::MANAGE_CHANNELS /// [`GuildChannel`]: twilight_model::channel::GuildChannel - pub fn channel_invites(&self, channel_id: ChannelId) -> GetChannelInvites<'_> { + pub const fn channel_invites(&self, channel_id: ChannelId) -> GetChannelInvites<'_> { GetChannelInvites::new(self, channel_id) } @@ -403,6 +403,7 @@ impl Client { /// .channel_messages(channel_id) /// .before(message_id) /// .limit(limit)? + /// .exec() /// .await?; /// /// # Ok(()) } @@ -452,6 +453,7 @@ impl Client { /// /// client.update_channel_permission(channel_id, allow, deny) /// .role(role_id) + /// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -465,17 +467,17 @@ impl Client { } /// Get all the webhooks of a channel. - pub fn channel_webhooks(&self, channel_id: ChannelId) -> GetChannelWebhooks<'_> { + pub const fn channel_webhooks(&self, channel_id: ChannelId) -> GetChannelWebhooks<'_> { GetChannelWebhooks::new(self, channel_id) } /// Get information about the current user. - pub fn current_user(&self) -> GetCurrentUser<'_> { + pub const fn current_user(&self) -> GetCurrentUser<'_> { GetCurrentUser::new(self) } /// Get information about the current bot application. - pub fn current_user_application(&self) -> GetUserApplicationInfo<'_> { + pub const fn current_user_application(&self) -> GetUserApplicationInfo<'_> { GetUserApplicationInfo::new(self) } @@ -495,7 +497,7 @@ impl Client { /// /// - `channel_id` must currently point to a stage channel. /// - Current user must have already joined `channel_id`. - pub fn update_current_user_voice_state( + pub const fn update_current_user_voice_state( &self, guild_id: GuildId, channel_id: ChannelId, @@ -506,7 +508,7 @@ impl Client { /// Get the current user's connections. /// /// Requires the `connections` `OAuth2` scope. - pub fn current_user_connections(&self) -> GetCurrentUserConnections<'_> { + pub const fn current_user_connections(&self) -> GetCurrentUserConnections<'_> { GetCurrentUserConnections::new(self) } @@ -531,10 +533,11 @@ impl Client { /// .after(after) /// .before(before) /// .limit(25)? + /// .exec() /// .await?; /// # Ok(()) } /// ``` - pub fn current_user_guilds(&self) -> GetCurrentUserGuilds<'_> { + pub const fn current_user_guilds(&self) -> GetCurrentUserGuilds<'_> { GetCurrentUserGuilds::new(self) } @@ -563,10 +566,10 @@ impl Client { /// # /// let guild_id = GuildId(100); /// - /// client.emojis(guild_id).await?; + /// client.emojis(guild_id).exec().await?; /// # Ok(()) } /// ``` - pub fn emojis(&self, guild_id: GuildId) -> GetEmojis<'_> { + pub const fn emojis(&self, guild_id: GuildId) -> GetEmojis<'_> { GetEmojis::new(self, guild_id) } @@ -587,10 +590,10 @@ impl Client { /// let guild_id = GuildId(50); /// let emoji_id = EmojiId(100); /// - /// client.emoji(guild_id, emoji_id).await?; + /// client.emoji(guild_id, emoji_id).exec().await?; /// # Ok(()) } /// ``` - pub fn emoji(&self, guild_id: GuildId, emoji_id: EmojiId) -> GetEmoji<'_> { + pub const fn emoji(&self, guild_id: GuildId, emoji_id: EmojiId) -> GetEmoji<'_> { GetEmoji::new(self, guild_id, emoji_id) } @@ -611,7 +614,7 @@ impl Client { } /// Delete an emoji in a guild, by id. - pub fn delete_emoji(&self, guild_id: GuildId, emoji_id: EmojiId) -> DeleteEmoji<'_> { + pub const fn delete_emoji(&self, guild_id: GuildId, emoji_id: EmojiId) -> DeleteEmoji<'_> { DeleteEmoji::new(self, guild_id, emoji_id) } @@ -634,7 +637,7 @@ impl Client { /// # async fn main() -> Result<(), Box> { /// # let client = Client::new("my token"); /// # - /// let info = client.gateway().await?; + /// let info = client.gateway().exec().await?; /// # Ok(()) } /// ``` /// @@ -648,13 +651,13 @@ impl Client { /// # async fn main() -> Result<(), Box> { /// # let client = Client::new("my token"); /// # - /// let info = client.gateway().authed().await?.model().await?; + /// let info = client.gateway().authed().exec().await?.model().await?; /// /// println!("URL: {}", info.url); /// println!("Recommended shards to use: {}", info.shards); /// # Ok(()) } /// ``` - pub fn gateway(&self) -> GetGateway<'_> { + pub const fn gateway(&self) -> GetGateway<'_> { GetGateway::new(self) } @@ -682,7 +685,7 @@ impl Client { } /// Delete a guild permanently. The user must be the owner. - pub fn delete_guild(&self, guild_id: GuildId) -> DeleteGuild<'_> { + pub const fn delete_guild(&self, guild_id: GuildId) -> DeleteGuild<'_> { DeleteGuild::new(self, guild_id) } @@ -696,12 +699,12 @@ impl Client { } /// Leave a guild by id. - pub fn leave_guild(&self, guild_id: GuildId) -> LeaveGuild<'_> { + pub const fn leave_guild(&self, guild_id: GuildId) -> LeaveGuild<'_> { LeaveGuild::new(self, guild_id) } /// Get the channels in a guild. - pub fn guild_channels(&self, guild_id: GuildId) -> GetGuildChannels<'_> { + pub const fn guild_channels(&self, guild_id: GuildId) -> GetGuildChannels<'_> { GetGuildChannels::new(self, guild_id) } @@ -752,7 +755,7 @@ impl Client { /// Refer to [the discord docs] for more information. /// /// [the discord docs]: https://discord.com/developers/docs/resources/guild#get-guild-widget - pub fn guild_widget(&self, guild_id: GuildId) -> GetGuildWidget<'_> { + pub const fn guild_widget(&self, guild_id: GuildId) -> GetGuildWidget<'_> { GetGuildWidget::new(self, guild_id) } @@ -762,12 +765,12 @@ impl Client { } /// Get the guild's integrations. - pub fn guild_integrations(&self, guild_id: GuildId) -> GetGuildIntegrations<'_> { + pub const fn guild_integrations(&self, guild_id: GuildId) -> GetGuildIntegrations<'_> { GetGuildIntegrations::new(self, guild_id) } /// Delete an integration for a guild, by the integration's id. - pub fn delete_guild_integration( + pub const fn delete_guild_integration( &self, guild_id: GuildId, integration_id: IntegrationId, @@ -780,7 +783,7 @@ impl Client { /// Requires the [`MANAGE_GUILD`] permission. /// /// [`MANAGE_GUILD`]: twilight_model::guild::Permissions::MANAGE_GUILD - pub fn guild_invites(&self, guild_id: GuildId) -> GetGuildInvites<'_> { + pub const fn guild_invites(&self, guild_id: GuildId) -> GetGuildInvites<'_> { GetGuildInvites::new(self, guild_id) } @@ -803,7 +806,7 @@ impl Client { /// # /// let guild_id = GuildId(100); /// let user_id = UserId(3000); - /// let members = client.guild_members(guild_id).after(user_id).await?; + /// let members = client.guild_members(guild_id).after(user_id).exec().await?; /// # Ok(()) } /// ``` /// @@ -834,7 +837,10 @@ impl Client { /// let client = Client::new("my token"); /// /// let guild_id = GuildId(100); - /// let members = client.search_guild_members(guild_id, String::from("Wumpus")).limit(10)?.await?; + /// let members = client.search_guild_members(guild_id, String::from("Wumpus")) + /// .limit(10)? + /// .exec() + /// .await?; /// # Ok(()) } /// ``` /// @@ -854,7 +860,7 @@ impl Client { } /// Get a member of a guild, by their id. - pub fn guild_member(&self, guild_id: GuildId, user_id: UserId) -> GetMember<'_> { + pub const fn guild_member(&self, guild_id: GuildId, user_id: UserId) -> GetMember<'_> { GetMember::new(self, guild_id, user_id) } @@ -882,7 +888,11 @@ impl Client { } /// Kick a member from a guild. - pub fn remove_guild_member(&self, guild_id: GuildId, user_id: UserId) -> RemoveMember<'_> { + pub const fn remove_guild_member( + &self, + guild_id: GuildId, + user_id: UserId, + ) -> RemoveMember<'_> { RemoveMember::new(self, guild_id, user_id) } @@ -904,6 +914,7 @@ impl Client { /// let member = client.update_guild_member(GuildId(1), UserId(2)) /// .mute(true) /// .nick(Some("pinkie pie".to_owned()))? + /// .exec() /// .await? /// .model() /// .await?; @@ -942,7 +953,10 @@ impl Client { /// let role_id = RoleId(2); /// let user_id = UserId(3); /// - /// client.add_guild_member_role(guild_id, user_id, role_id).reason("test")?.await?; + /// client.add_guild_member_role(guild_id, user_id, role_id) + /// .reason("test")? + /// .exec() + /// .await?; /// # Ok(()) } /// ``` pub fn add_guild_member_role( @@ -967,7 +981,7 @@ impl Client { /// For public guilds, get the guild preview. /// /// This works even if the user is not in the guild. - pub fn guild_preview(&self, guild_id: GuildId) -> GetGuildPreview<'_> { + pub const fn guild_preview(&self, guild_id: GuildId) -> GetGuildPreview<'_> { GetGuildPreview::new(self, guild_id) } @@ -986,24 +1000,24 @@ impl Client { } /// Get a guild's vanity url, if there is one. - pub fn guild_vanity_url(&self, guild_id: GuildId) -> GetGuildVanityUrl<'_> { + pub const fn guild_vanity_url(&self, guild_id: GuildId) -> GetGuildVanityUrl<'_> { GetGuildVanityUrl::new(self, guild_id) } /// Get voice region data for the guild. /// /// Can return VIP servers if the guild is VIP-enabled. - pub fn guild_voice_regions(&self, guild_id: GuildId) -> GetGuildVoiceRegions<'_> { + pub const fn guild_voice_regions(&self, guild_id: GuildId) -> GetGuildVoiceRegions<'_> { GetGuildVoiceRegions::new(self, guild_id) } /// Get the webhooks of a guild. - pub fn guild_webhooks(&self, guild_id: GuildId) -> GetGuildWebhooks<'_> { + pub const fn guild_webhooks(&self, guild_id: GuildId) -> GetGuildWebhooks<'_> { GetGuildWebhooks::new(self, guild_id) } /// Get the guild's welcome screen. - pub fn guild_welcome_screen(&self, guild_id: GuildId) -> GetGuildWelcomeScreen<'_> { + pub const fn guild_welcome_screen(&self, guild_id: GuildId) -> GetGuildWelcomeScreen<'_> { GetGuildWelcomeScreen::new(self, guild_id) } @@ -1034,6 +1048,7 @@ impl Client { /// let invite = client /// .invite("code") /// .with_counts() + /// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -1062,6 +1077,7 @@ impl Client { /// let invite = client /// .create_invite(channel_id) /// .max_uses(3)? + /// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -1083,7 +1099,7 @@ impl Client { } /// Get a message by [`ChannelId`] and [`MessageId`]. - pub fn message(&self, channel_id: ChannelId, message_id: MessageId) -> GetMessage<'_> { + pub const fn message(&self, channel_id: ChannelId, message_id: MessageId) -> GetMessage<'_> { GetMessage::new(self, channel_id, message_id) } @@ -1104,6 +1120,7 @@ impl Client { /// .create_message(channel_id) /// .content("Twilight is best pony")? /// .tts(true) + /// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -1129,7 +1146,7 @@ impl Client { } /// Delete a message by [`ChannelId`] and [`MessageId`]. - pub fn delete_message( + pub const fn delete_message( &self, channel_id: ChannelId, message_id: MessageId, @@ -1171,6 +1188,7 @@ impl Client { /// let client = Client::new("my token"); /// client.update_message(ChannelId(1), MessageId(2)) /// .content("test update".to_owned())? + /// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -1186,6 +1204,7 @@ impl Client { /// # let client = Client::new("my token"); /// client.update_message(ChannelId(1), MessageId(2)) /// .content(None)? + /// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -1200,7 +1219,7 @@ impl Client { } /// Crosspost a message by [`ChannelId`] and [`MessageId`]. - pub fn crosspost_message( + pub const fn crosspost_message( &self, channel_id: ChannelId, message_id: MessageId, @@ -1209,17 +1228,17 @@ impl Client { } /// Get the pins of a channel. - pub fn pins(&self, channel_id: ChannelId) -> GetPins<'_> { + pub const fn pins(&self, channel_id: ChannelId) -> GetPins<'_> { GetPins::new(self, channel_id) } /// Create a new pin in a channel, by ID. - pub fn create_pin(&self, channel_id: ChannelId, message_id: MessageId) -> CreatePin<'_> { + pub const fn create_pin(&self, channel_id: ChannelId, message_id: MessageId) -> CreatePin<'_> { CreatePin::new(self, channel_id, message_id) } /// Delete a pin in a channel, by ID. - pub fn delete_pin(&self, channel_id: ChannelId, message_id: MessageId) -> DeletePin<'_> { + pub const fn delete_pin(&self, channel_id: ChannelId, message_id: MessageId) -> DeletePin<'_> { DeletePin::new(self, channel_id, message_id) } @@ -1257,10 +1276,11 @@ impl Client { /// /// let reaction = client /// .create_reaction(channel_id, message_id, emoji) + /// .exec() /// .await?; /// # Ok(()) } /// ``` - pub fn create_reaction( + pub const fn create_reaction( &self, channel_id: ChannelId, message_id: MessageId, @@ -1291,7 +1311,7 @@ impl Client { } /// Remove all reactions on a message of an emoji. - pub fn delete_all_reaction( + pub const fn delete_all_reaction( &self, channel_id: ChannelId, message_id: MessageId, @@ -1301,7 +1321,7 @@ impl Client { } /// Delete all reactions by all users on a message. - pub fn delete_all_reactions( + pub const fn delete_all_reactions( &self, channel_id: ChannelId, message_id: MessageId, @@ -1310,19 +1330,19 @@ impl Client { } /// Fire a Typing Start event in the channel. - pub fn create_typing_trigger(&self, channel_id: ChannelId) -> CreateTypingTrigger<'_> { + pub const fn create_typing_trigger(&self, channel_id: ChannelId) -> CreateTypingTrigger<'_> { CreateTypingTrigger::new(self, channel_id) } /// Create a group DM. /// /// This endpoint is limited to 10 active group DMs. - pub fn create_private_channel(&self, recipient_id: UserId) -> CreatePrivateChannel<'_> { + pub const fn create_private_channel(&self, recipient_id: UserId) -> CreatePrivateChannel<'_> { CreatePrivateChannel::new(self, recipient_id) } /// Get the roles of a guild. - pub fn roles(&self, guild_id: GuildId) -> GetGuildRoles<'_> { + pub const fn roles(&self, guild_id: GuildId) -> GetGuildRoles<'_> { GetGuildRoles::new(self, guild_id) } @@ -1342,6 +1362,7 @@ impl Client { /// client.create_role(guild_id) /// .color(0xd90083) /// .name("Bright Pink") + /// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -1350,7 +1371,7 @@ impl Client { } /// Delete a role in a guild, by id. - pub fn delete_role(&self, guild_id: GuildId, role_id: RoleId) -> DeleteRole<'_> { + pub const fn delete_role(&self, guild_id: GuildId, role_id: RoleId) -> DeleteRole<'_> { DeleteRole::new(self, guild_id, role_id) } @@ -1389,7 +1410,7 @@ impl Client { } /// Gets the stage instance associated with a stage channel, if it exists. - pub fn stage_instance(&self, channel_id: ChannelId) -> GetStageInstance<'_> { + pub const fn stage_instance(&self, channel_id: ChannelId) -> GetStageInstance<'_> { GetStageInstance::new(self, channel_id) } @@ -1403,7 +1424,7 @@ impl Client { /// Delete the stage instance of a stage channel. /// /// Requires the user to be a moderator of the stage channel. - pub fn delete_stage_instance(&self, channel_id: ChannelId) -> DeleteStageInstance<'_> { + pub const fn delete_stage_instance(&self, channel_id: ChannelId) -> DeleteStageInstance<'_> { DeleteStageInstance::new(self, channel_id) } @@ -1459,7 +1480,7 @@ impl Client { } /// Get a list of templates in a guild, by ID. - pub fn get_templates(&self, guild_id: GuildId) -> GetTemplates<'_> { + pub const fn get_templates(&self, guild_id: GuildId) -> GetTemplates<'_> { GetTemplates::new(self, guild_id) } @@ -1492,7 +1513,7 @@ impl Client { /// /// - `channel_id` must currently point to a stage channel. /// - User must already have joined `channel_id`. - pub fn update_user_voice_state( + pub const fn update_user_voice_state( &self, guild_id: GuildId, user_id: UserId, @@ -1502,7 +1523,7 @@ impl Client { } /// Get a list of voice regions that can be used when creating a guild. - pub fn voice_regions(&self) -> GetVoiceRegions<'_> { + pub const fn voice_regions(&self) -> GetVoiceRegions<'_> { GetVoiceRegions::new(self) } @@ -1526,6 +1547,7 @@ impl Client { /// /// let webhook = client /// .create_webhook(channel_id, "Twily Bot") + /// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -1538,7 +1560,7 @@ impl Client { } /// Delete a webhook by its ID. - pub fn delete_webhook(&self, id: WebhookId) -> DeleteWebhook<'_> { + pub const fn delete_webhook(&self, id: WebhookId) -> DeleteWebhook<'_> { DeleteWebhook::new(self, id) } @@ -1574,6 +1596,7 @@ impl Client { /// let webhook = client /// .execute_webhook(id, "webhook token") /// .content("Pinkie...") + /// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -1615,6 +1638,7 @@ impl Client { /// # let client = Client::new("token"); /// client.update_webhook_message(WebhookId(1), "token here", MessageId(2)) /// .content(Some("new message content".to_owned()))? + /// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -1640,6 +1664,7 @@ impl Client { /// # let client = Client::new("token"); /// client /// .delete_webhook_message(WebhookId(1), "token here", MessageId(2)) + /// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -2134,14 +2159,23 @@ impl Client { SetCommandPermissions::new(self, application_id, guild_id, permissions) } - /// Execute a request, returning the response. + /// Execute a request, returning a future resolving to a [`Response`]. /// /// # Errors /// /// Returns an [`ErrorType::Unauthorized`] error type if the configured /// token has become invalid due to expiration, revokation, etc. + /// + /// [`Response`]: super::response::Response + pub fn request(&self, request: Request) -> ResponseFuture { + match self.try_request::(request) { + Ok(future) => future, + Err(source) => ResponseFuture::error(source), + } + } + #[allow(clippy::too_many_lines)] - pub async fn request(&self, request: Request) -> Result, Error> { + fn try_request(&self, request: Request) -> Result, Error> { if self.state.token_invalid.load(Ordering::Relaxed) { return Err(Error { kind: ErrorType::Unauthorized, @@ -2259,114 +2293,27 @@ impl Client { }; let inner = self.state.http.request(req); - let fut = time::timeout(self.state.timeout, inner); - - let ratelimiter = match self.state.ratelimiter.as_ref() { - Some(ratelimiter) => ratelimiter, - None => { - return Ok(Response::new( - fut.await - .map_err(|source| Error { - kind: ErrorType::RequestTimedOut, - source: Some(Box::new(source)), - })? - .map_err(|source| Error { - kind: ErrorType::RequestError, - source: Some(Box::new(source)), - })?, - )); - } - }; - - let rx = ratelimiter.get(bucket).await; - let tx = rx.await.map_err(|source| Error { - kind: ErrorType::RequestCanceled, - source: Some(Box::new(source)), - })?; - - let resp = fut - .await - .map_err(|source| Error { - kind: ErrorType::RequestTimedOut, - source: Some(Box::new(source)), - })? - .map_err(|source| Error { - kind: ErrorType::RequestError, - source: Some(Box::new(source)), - })?; - - // If the API sent back an Unauthorized response, then the client's - // configured token is permanently invalid and future requests must be - // ignored to avoid API bans. - if resp.status() == HyperStatusCode::UNAUTHORIZED { - self.state.token_invalid.store(true, Ordering::Relaxed); - } - - match RatelimitHeaders::try_from(resp.headers()) { - Ok(v) => { - let _res = tx.send(Some(v)); - } - #[allow(unused_variables)] - Err(why) => { - #[cfg(feature = "tracing")] - tracing::warn!("header parsing failed: {:?}; {:?}", why, resp); - - let _res = tx.send(None); - } - } - - let status = resp.status(); - - if status.is_success() { - return Ok(Response::new(resp)); - } - - match status { - HyperStatusCode::IM_A_TEAPOT => { - #[cfg(feature = "tracing")] - tracing::warn!( - "discord's api now runs off of teapots -- proceed to panic: {:?}", - resp, - ); - } - HyperStatusCode::TOO_MANY_REQUESTS => { - #[cfg(feature = "tracing")] - tracing::warn!("429 response: {:?}", resp); - } - HyperStatusCode::SERVICE_UNAVAILABLE => { - return Err(Error { - kind: ErrorType::ServiceUnavailable { response: resp }, - source: None, - }); - } - _ => {} - } - - let bytes = body::to_bytes(resp.into_body()) - .await - .map_err(|source| Error { - kind: ErrorType::ChunkingResponse, - source: Some(Box::new(source)), - })?; - - let error = crate::json::parse_bytes::(&bytes)?; - - #[cfg(feature = "tracing")] - if let ApiError::General(ref general) = error { - use crate::api_error::ErrorCode; - - if let ErrorCode::Other(num) = general.code { - tracing::debug!("got unknown API error code variant: {}; {:?}", num, error); - } + let token_invalid = Arc::clone(&self.state.token_invalid); + + // Clippy suggests bad code; an `Option::map_or_else` won't work here + // due to move semantics in both cases. + #[allow(clippy::option_if_let_else)] + if let Some(ratelimiter) = self.state.ratelimiter.as_ref() { + let rx = ratelimiter.ticket(bucket); + + Ok(ResponseFuture::ratelimit( + None, + token_invalid, + rx, + self.state.timeout, + inner, + )) + } else { + Ok(ResponseFuture::new( + token_invalid, + time::timeout(self.state.timeout, inner), + None, + )) } - - Err(Error { - kind: ErrorType::Response { - body: bytes.to_vec(), - error, - status: StatusCode::new(status.as_u16()), - }, - source: None, - }) } } diff --git a/http/src/json.rs b/http/src/json.rs index ddec6d5aea3..50a92f89252 100644 --- a/http/src/json.rs +++ b/http/src/json.rs @@ -3,7 +3,6 @@ pub use serde_json::{to_vec, Deserializer as JsonDeserializer, Error as JsonErro #[cfg(feature = "simd-json")] pub use simd_json::{to_vec, Deserializer as JsonDeserializer, Error as JsonError}; -use crate::error::{Error, ErrorType}; use hyper::body::Bytes; use serde::de::DeserializeOwned; @@ -24,12 +23,3 @@ pub fn from_bytes(bytes: &Bytes) -> JsonResult { simd_json::from_slice(&mut bytes.to_vec()) } } - -pub fn parse_bytes(bytes: &Bytes) -> Result { - from_bytes(bytes).map_err(|source| Error { - kind: ErrorType::Parsing { - body: bytes.to_vec(), - }, - source: Some(Box::new(source)), - }) -} diff --git a/http/src/ratelimiting/bucket.rs b/http/src/ratelimiting/bucket.rs index e6f0d489c08..e2266c4c59a 100644 --- a/http/src/ratelimiting/bucket.rs +++ b/http/src/ratelimiting/bucket.rs @@ -4,7 +4,7 @@ use std::{ collections::HashMap, sync::{ atomic::{AtomicU64, Ordering}, - Arc, + Arc, Mutex, }, time::{Duration, Instant}, }; @@ -12,7 +12,7 @@ use tokio::{ sync::{ mpsc::{self, UnboundedReceiver, UnboundedSender}, oneshot::{self, Sender}, - Mutex, + Mutex as AsyncMutex, }, time::{sleep, timeout}, }; @@ -58,9 +58,9 @@ impl Bucket { self.reset_after.load(Ordering::Relaxed) } - pub async fn time_remaining(&self) -> TimeRemaining { + pub fn time_remaining(&self) -> TimeRemaining { let reset_after = self.reset_after(); - let started_at = match *self.started_at.lock().await { + let started_at = match *self.started_at.lock().expect("bucket poisoned") { Some(v) => v, None => return TimeRemaining::NotStarted, }; @@ -73,14 +73,14 @@ impl Bucket { TimeRemaining::Some(Duration::from_millis(reset_after) - elapsed) } - pub async fn try_reset(&self) -> bool { - if self.started_at.lock().await.is_none() { + pub fn try_reset(&self) -> bool { + if self.started_at.lock().expect("bucket poisoned").is_none() { return false; } - if let TimeRemaining::Finished = self.time_remaining().await { + if let TimeRemaining::Finished = self.time_remaining() { self.remaining.store(self.limit(), Ordering::Relaxed); - *self.started_at.lock().await = None; + *self.started_at.lock().expect("bucket poisoned") = None; true } else { @@ -88,11 +88,11 @@ impl Bucket { } } - pub async fn update(&self, ratelimits: Option<(u64, u64, u64)>) { + pub fn update(&self, ratelimits: Option<(u64, u64, u64)>) { let bucket_limit = self.limit(); { - let mut started_at = self.started_at.lock().await; + let mut started_at = self.started_at.lock().expect("bucket poisoned"); if started_at.is_none() { started_at.replace(Instant::now()); @@ -114,7 +114,7 @@ impl Bucket { #[derive(Debug)] pub struct BucketQueue { - rx: Mutex>>>>, + rx: AsyncMutex>>>>, tx: UnboundedSender>>>, } @@ -141,7 +141,7 @@ impl Default for BucketQueue { let (tx, rx) = mpsc::unbounded_channel(); Self { - rx: Mutex::new(rx), + rx: AsyncMutex::new(rx), tx, } } @@ -204,7 +204,10 @@ impl BucketQueueTask { #[cfg(feature = "tracing")] tracing::debug!(parent: &span, "bucket appears finished, removing"); - self.buckets.lock().await.remove(&self.path); + self.buckets + .lock() + .expect("ratelimit buckets poisoned") + .remove(&self.path); } async fn handle_headers(&self, headers: &RatelimitHeaders) { @@ -232,7 +235,7 @@ impl BucketQueueTask { #[cfg(feature = "tracing")] tracing::debug!(path=?self.path, "updating bucket"); - self.bucket.update(ratelimits).await; + self.bucket.update(ratelimits); } async fn lock_global(&self, wait: Duration) { @@ -267,9 +270,9 @@ impl BucketQueueTask { #[cfg(feature = "tracing")] tracing::debug!(parent: &span, "0 tickets remaining, may have to wait"); - match self.bucket.time_remaining().await { + match self.bucket.time_remaining() { TimeRemaining::Finished => { - self.bucket.try_reset().await; + self.bucket.try_reset(); return; } @@ -290,6 +293,6 @@ impl BucketQueueTask { #[cfg(feature = "tracing")] tracing::debug!(parent: &span, "done waiting for ratelimit to pass"); - self.bucket.try_reset().await; + self.bucket.try_reset(); } } diff --git a/http/src/ratelimiting/mod.rs b/http/src/ratelimiting/mod.rs index c47d3ba12a7..f667010492c 100644 --- a/http/src/ratelimiting/mod.rs +++ b/http/src/ratelimiting/mod.rs @@ -8,19 +8,19 @@ pub use self::{ headers::RatelimitHeaders, }; +use self::bucket::{Bucket, BucketQueueTask, TimeRemaining}; use crate::routing::Path; -use bucket::{Bucket, BucketQueueTask, TimeRemaining}; use std::{ collections::hash_map::{Entry, HashMap}, sync::{ atomic::{AtomicBool, Ordering}, - Arc, + Arc, Mutex, }, time::Duration, }; use tokio::sync::{ oneshot::{self, Receiver, Sender}, - Mutex, + Mutex as AsyncMutex, }; /// Global lock. We use a pair to avoid actually locking the mutex every check. @@ -28,7 +28,7 @@ use tokio::sync::{ /// is in place by, in turn, waiting for a guard, and then each immediately /// dropping it. #[derive(Debug, Default)] -struct GlobalLockPair(Mutex<()>, AtomicBool); +struct GlobalLockPair(AsyncMutex<()>, AtomicBool); impl GlobalLockPair { pub fn lock(&self) { @@ -59,12 +59,17 @@ impl Ratelimiter { Self::default() } + #[deprecated(since = "0.5.0", note = "use `ticket` instead, which is not async")] pub async fn get(&self, path: Path) -> Receiver>> { + self.ticket(path) + } + + pub fn ticket(&self, path: Path) -> Receiver>> { #[cfg(feature = "tracing")] tracing::debug!("getting bucket for path: {:?}", path); let (tx, rx) = oneshot::channel(); - let (bucket, fresh) = self.entry(path.clone(), tx).await; + let (bucket, fresh) = self.entry(path.clone(), tx); if fresh { tokio::spawn( @@ -87,20 +92,21 @@ impl Ratelimiter { /// This method is not guaranteed to be accurate and may return /// None if either no ratelimit is known or buckets are remaining. pub async fn time_until_available(&self, path: &Path) -> Option { - let buckets = self.buckets.lock().await; - match buckets.get(path)?.time_remaining().await { + let buckets = self.buckets.lock().expect("ratelimit buckets poisoned"); + + match buckets.get(path)?.time_remaining() { TimeRemaining::Finished | TimeRemaining::NotStarted => None, TimeRemaining::Some(duration) => Some(duration), } } - async fn entry( + fn entry( &self, path: Path, tx: Sender>>, ) -> (Arc, bool) { // nb: not realisically point of contention - let mut buckets = self.buckets.lock().await; + let mut buckets = self.buckets.lock().expect("ratelimit buckets poisoned"); match buckets.entry(path.clone()) { Entry::Occupied(bucket) => { @@ -117,7 +123,7 @@ impl Ratelimiter { Entry::Vacant(entry) => { #[cfg(feature = "tracing")] tracing::debug!("making new bucket for path: {:?}", path); - let bucket = Bucket::new(path.clone()); + let bucket = Bucket::new(path); bucket.queue.push(tx); let bucket = Arc::new(bucket); diff --git a/http/src/request/application/create_followup_message.rs b/http/src/request/application/create_followup_message.rs index 8f8f22b3a51..7c2b7aa9e1b 100644 --- a/http/src/request/application/create_followup_message.rs +++ b/http/src/request/application/create_followup_message.rs @@ -1,7 +1,8 @@ use crate::{ client::Client, error::Error, - request::{Form, PendingResponse, Request}, + request::{Form, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -51,6 +52,7 @@ pub(crate) struct CreateFollowupMessageFields { /// client /// .create_followup_message("webhook token")? /// .content("Pinkie...") +/// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -61,7 +63,6 @@ pub(crate) struct CreateFollowupMessageFields { pub struct CreateFollowupMessage<'a> { pub(crate) fields: CreateFollowupMessageFields, files: Vec<(String, Vec)>, - fut: Option>, http: &'a Client, token: String, application_id: ApplicationId, @@ -76,7 +77,6 @@ impl<'a> CreateFollowupMessage<'a> { Self { fields: CreateFollowupMessageFields::default(), files: Vec::new(), - fut: None, http, token: token.into(), application_id, @@ -171,6 +171,7 @@ impl<'a> CreateFollowupMessage<'a> { /// let message = client.create_followup_message("token here")? /// .content("some content") /// .embeds(vec![EmbedBuilder::new().title("title").build()?]) + /// .exec() /// .await? /// .model() /// .await?; @@ -194,6 +195,7 @@ impl<'a> CreateFollowupMessage<'a> { /// let message = client.create_followup_message("token here")? /// .content("some content") /// .payload_json(r#"{ "content": "other content", "embeds": [ { "title": "title" } ] }"#) + /// .exec() /// .await? /// .model() /// .await?; @@ -224,9 +226,11 @@ impl<'a> CreateFollowupMessage<'a> { self } - fn start(&mut self) -> Result<(), Error> { + // `self` needs to be consumed and the client returned due to parameters + // being consumed in request construction. + fn request(mut self) -> Result<(Request, &'a Client), Error> { let mut request = Request::builder(Route::ExecuteWebhook { - token: self.token.clone(), + token: self.token, wait: None, webhook_id: self.application_id.0, }); @@ -250,11 +254,16 @@ impl<'a> CreateFollowupMessage<'a> { request = request.json(&self.fields)?; } - self.fut - .replace(Box::pin(self.http.request(request.build()))); + Ok((request.build(), self.http)) + } - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + match self.request() { + Ok((request, client)) => client.request(request), + Err(source) => ResponseFuture::error(source), + } } } - -poll_req!(CreateFollowupMessage<'_>, Message); diff --git a/http/src/request/application/create_global_command.rs b/http/src/request/application/create_global_command.rs index f23e34f1b7e..1cc378d39d6 100644 --- a/http/src/request/application/create_global_command.rs +++ b/http/src/request/application/create_global_command.rs @@ -3,9 +3,9 @@ use crate::{ error::Error as HttpError, request::{ application::{InteractionError, InteractionErrorType}, - validate, PendingResponse, Request, + validate, Request, RequestBuilder, }, - response::marker::EmptyBody, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::{ @@ -24,7 +24,6 @@ use twilight_model::{ pub struct CreateGlobalCommand<'a> { command: Command, application_id: ApplicationId, - fut: Option>, http: &'a Client, optional_option_added: bool, } @@ -61,7 +60,6 @@ impl<'a> CreateGlobalCommand<'a> { options: vec![], }, application_id, - fut: None, http, optional_option_added: false, }) @@ -98,17 +96,21 @@ impl<'a> CreateGlobalCommand<'a> { self } - fn start(&mut self) -> Result<(), HttpError> { - let request = Request::builder(Route::CreateGlobalCommand { + fn request(&self) -> Result { + Request::builder(Route::CreateGlobalCommand { application_id: self.application_id.0, }) - .json(&self.command)?; - - self.fut - .replace(Box::pin(self.http.request(request.build()))); + .json(&self.command) + .map(RequestBuilder::build) + } - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + match self.request() { + Ok(request) => self.http.request(request), + Err(source) => ResponseFuture::error(source), + } } } - -poll_req!(CreateGlobalCommand<'_>, EmptyBody); diff --git a/http/src/request/application/create_guild_command.rs b/http/src/request/application/create_guild_command.rs index 946dc87b32b..e228d0c2cbb 100644 --- a/http/src/request/application/create_guild_command.rs +++ b/http/src/request/application/create_guild_command.rs @@ -3,9 +3,9 @@ use crate::{ error::Error as HttpError, request::{ application::{InteractionError, InteractionErrorType}, - validate, PendingResponse, Request, + validate, Request, RequestBuilder, }, - response::marker::EmptyBody, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::{ @@ -24,7 +24,6 @@ use twilight_model::{ pub struct CreateGuildCommand<'a> { application_id: ApplicationId, command: Command, - fut: Option>, guild_id: GuildId, http: &'a Client, optional_option_added: bool, @@ -65,7 +64,6 @@ impl<'a> CreateGuildCommand<'a> { }, application_id, guild_id, - fut: None, http, optional_option_added: false, }) @@ -103,18 +101,22 @@ impl<'a> CreateGuildCommand<'a> { Ok(self) } - fn start(&mut self) -> Result<(), HttpError> { - let request = Request::builder(Route::CreateGuildCommand { + fn request(&self) -> Result { + Request::builder(Route::CreateGuildCommand { application_id: self.application_id.0, guild_id: self.guild_id.0, }) - .json(&self.command)?; - - self.fut - .replace(Box::pin(self.http.request(request.build()))); + .json(&self.command) + .map(RequestBuilder::build) + } - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + match self.request() { + Ok(request) => self.http.request(request), + Err(source) => ResponseFuture::error(source), + } } } - -poll_req!(CreateGuildCommand<'_>, EmptyBody); diff --git a/http/src/request/application/delete_followup_message.rs b/http/src/request/application/delete_followup_message.rs index 8afb0c50f5f..52e4f505c75 100644 --- a/http/src/request/application/delete_followup_message.rs +++ b/http/src/request/application/delete_followup_message.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::Request, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{ApplicationId, MessageId}; @@ -20,11 +19,11 @@ use twilight_model::id::{ApplicationId, MessageId}; /// let client = Client::new(env::var("DISCORD_TOKEN")?); /// client /// .delete_followup_message("token here", MessageId(2))? +/// .exec() /// .await?; /// # Ok(()) } /// ``` pub struct DeleteFollowupMessage<'a> { - fut: Option>, http: &'a Client, message_id: MessageId, token: String, @@ -39,7 +38,6 @@ impl<'a> DeleteFollowupMessage<'a> { message_id: MessageId, ) -> Self { Self { - fut: None, http, message_id, token: token.into(), @@ -47,26 +45,22 @@ impl<'a> DeleteFollowupMessage<'a> { } } - fn request(&self) -> Result { - let request = Request::from_route(Route::DeleteWebhookMessage { + fn request(self) -> Request { + Request::from_route(Route::DeleteWebhookMessage { message_id: self.message_id.0, - token: self.token.clone(), + token: self.token, webhook_id: self.application_id.0, - }); - - Ok(request) + }) } - fn start(&mut self) -> Result<(), Error> { - let request = self.request()?; - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + self.http.request(self.request()) } } -poll_req!(DeleteFollowupMessage<'_>, EmptyBody); - #[cfg(test)] mod tests { use super::DeleteFollowupMessage; @@ -78,7 +72,7 @@ mod tests { let client = Client::new("token"); let builder = DeleteFollowupMessage::new(&client, ApplicationId(1), "token", MessageId(2)); - let actual = builder.request().expect("failed to create request"); + let actual = builder.request(); let expected = Request::from_route(Route::DeleteWebhookMessage { message_id: 2, diff --git a/http/src/request/application/delete_global_command.rs b/http/src/request/application/delete_global_command.rs index 1474c4009df..df1d764d8c5 100644 --- a/http/src/request/application/delete_global_command.rs +++ b/http/src/request/application/delete_global_command.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::Request, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{ApplicationId, CommandId}; @@ -11,12 +10,11 @@ use twilight_model::id::{ApplicationId, CommandId}; pub struct DeleteGlobalCommand<'a> { application_id: ApplicationId, command_id: CommandId, - fut: Option>, http: &'a Client, } impl<'a> DeleteGlobalCommand<'a> { - pub(crate) fn new( + pub(crate) const fn new( http: &'a Client, application_id: ApplicationId, command_id: CommandId, @@ -24,21 +22,19 @@ impl<'a> DeleteGlobalCommand<'a> { Self { application_id, command_id, - fut: None, http, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::DeleteGlobalCommand { application_id: self.application_id.0, command_id: self.command_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(DeleteGlobalCommand<'_>, EmptyBody); diff --git a/http/src/request/application/delete_guild_command.rs b/http/src/request/application/delete_guild_command.rs index 30554448f70..564a8493a9f 100644 --- a/http/src/request/application/delete_guild_command.rs +++ b/http/src/request/application/delete_guild_command.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::Request, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{ApplicationId, CommandId, GuildId}; @@ -11,13 +10,12 @@ use twilight_model::id::{ApplicationId, CommandId, GuildId}; pub struct DeleteGuildCommand<'a> { application_id: ApplicationId, command_id: CommandId, - fut: Option>, guild_id: GuildId, http: &'a Client, } impl<'a> DeleteGuildCommand<'a> { - pub(crate) fn new( + pub(crate) const fn new( http: &'a Client, application_id: ApplicationId, guild_id: GuildId, @@ -26,23 +24,18 @@ impl<'a> DeleteGuildCommand<'a> { Self { application_id, command_id, - fut: None, guild_id, http, } } - fn start(&mut self) -> Result<(), Error> { + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::DeleteGuildCommand { application_id: self.application_id.0, command_id: self.command_id.0, guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(DeleteGuildCommand<'_>, EmptyBody); diff --git a/http/src/request/application/delete_original_response.rs b/http/src/request/application/delete_original_response.rs index 7a3148151f3..d5857eb8aae 100644 --- a/http/src/request/application/delete_original_response.rs +++ b/http/src/request/application/delete_original_response.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::Request, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::ApplicationId; @@ -24,12 +23,12 @@ use twilight_model::id::ApplicationId; /// /// client /// .delete_interaction_original("token here")? +/// .exec() /// .await?; /// # Ok(()) } /// ``` pub struct DeleteOriginalResponse<'a> { application_id: ApplicationId, - fut: Option>, http: &'a Client, token: String, } @@ -42,27 +41,20 @@ impl<'a> DeleteOriginalResponse<'a> { ) -> Self { Self { application_id, - fut: None, http, token: token.into(), } } - fn request(&self) -> Result { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::DeleteInteractionOriginal { application_id: self.application_id.0, - interaction_token: self.token.clone(), + interaction_token: self.token, }); - Ok(request) - } - - fn start(&mut self) -> Result<(), Error> { - let request = self.request()?; - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(DeleteOriginalResponse<'_>, EmptyBody); diff --git a/http/src/request/application/get_command_permissions.rs b/http/src/request/application/get_command_permissions.rs index 4d070aa17b6..b5a618401ca 100644 --- a/http/src/request/application/get_command_permissions.rs +++ b/http/src/request/application/get_command_permissions.rs @@ -1,9 +1,4 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::{ application::command::permissions::GuildCommandPermissions, id::{ApplicationId, CommandId, GuildId}, @@ -14,12 +9,11 @@ pub struct GetCommandPermissions<'a> { application_id: ApplicationId, command_id: CommandId, guild_id: GuildId, - fut: Option>, http: &'a Client, } impl<'a> GetCommandPermissions<'a> { - pub(crate) fn new( + pub(crate) const fn new( http: &'a Client, application_id: ApplicationId, guild_id: GuildId, @@ -29,22 +23,20 @@ impl<'a> GetCommandPermissions<'a> { application_id, command_id, guild_id, - fut: None, http, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetCommandPermissions { application_id: self.application_id.0, command_id: self.command_id.0, guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetCommandPermissions<'_>, GuildCommandPermissions); diff --git a/http/src/request/application/get_global_commands.rs b/http/src/request/application/get_global_commands.rs index 6c5bf2b8009..bf04d50a438 100644 --- a/http/src/request/application/get_global_commands.rs +++ b/http/src/request/application/get_global_commands.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::ListBody, + request::Request, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use twilight_model::{application::command::Command, id::ApplicationId}; @@ -10,28 +9,25 @@ use twilight_model::{application::command::Command, id::ApplicationId}; /// Retrieve all global commands for an application. pub struct GetGlobalCommands<'a> { application_id: ApplicationId, - fut: Option>>, http: &'a Client, } impl<'a> GetGlobalCommands<'a> { - pub(crate) fn new(http: &'a Client, application_id: ApplicationId) -> Self { + pub(crate) const fn new(http: &'a Client, application_id: ApplicationId) -> Self { Self { application_id, - fut: None, http, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetGlobalCommands { application_id: self.application_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetGlobalCommands<'_>, ListBody); diff --git a/http/src/request/application/get_guild_command_permissions.rs b/http/src/request/application/get_guild_command_permissions.rs index 5d846a2bf25..dd1fa8ae81c 100644 --- a/http/src/request/application/get_guild_command_permissions.rs +++ b/http/src/request/application/get_guild_command_permissions.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::ListBody, + request::Request, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use twilight_model::{ @@ -14,33 +13,31 @@ use twilight_model::{ pub struct GetGuildCommandPermissions<'a> { application_id: ApplicationId, guild_id: GuildId, - fut: Option>>, http: &'a Client, } impl<'a> GetGuildCommandPermissions<'a> { - pub(crate) fn new(http: &'a Client, application_id: ApplicationId, guild_id: GuildId) -> Self { + pub(crate) const fn new( + http: &'a Client, + application_id: ApplicationId, + guild_id: GuildId, + ) -> Self { Self { application_id, guild_id, - fut: None, http, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetGuildCommandPermissions { application_id: self.application_id.0, guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!( - GetGuildCommandPermissions<'_>, - ListBody -); diff --git a/http/src/request/application/get_guild_commands.rs b/http/src/request/application/get_guild_commands.rs index 4d53b7bb102..15612abd421 100644 --- a/http/src/request/application/get_guild_commands.rs +++ b/http/src/request/application/get_guild_commands.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::ListBody, + request::Request, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use twilight_model::{ @@ -14,30 +13,31 @@ use twilight_model::{ pub struct GetGuildCommands<'a> { application_id: ApplicationId, guild_id: GuildId, - fut: Option>>, http: &'a Client, } impl<'a> GetGuildCommands<'a> { - pub(crate) fn new(http: &'a Client, application_id: ApplicationId, guild_id: GuildId) -> Self { + pub(crate) const fn new( + http: &'a Client, + application_id: ApplicationId, + guild_id: GuildId, + ) -> Self { Self { application_id, guild_id, - fut: None, http, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetGuildCommands { application_id: self.application_id.0, guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetGuildCommands<'_>, ListBody); diff --git a/http/src/request/application/get_original_response.rs b/http/src/request/application/get_original_response.rs index b9e4a342a37..e2b551bec13 100644 --- a/http/src/request/application/get_original_response.rs +++ b/http/src/request/application/get_original_response.rs @@ -1,9 +1,4 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::{channel::Message, id::ApplicationId}; /// Get the original message, by its token. @@ -23,12 +18,12 @@ use twilight_model::{channel::Message, id::ApplicationId}; /// /// let message = client /// .get_interaction_original("token here")? +/// .exec() /// .await?; /// # Ok(()) } /// ``` pub struct GetOriginalResponse<'a> { application_id: ApplicationId, - fut: Option>, http: &'a Client, token: String, } @@ -41,27 +36,20 @@ impl<'a> GetOriginalResponse<'a> { ) -> Self { Self { application_id, - fut: None, http, token: token.into(), } } - fn request(&self) -> Result { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetInteractionOriginal { application_id: self.application_id.0, - interaction_token: self.token.clone(), + interaction_token: self.token, }); - Ok(request) - } - - fn start(&mut self) -> Result<(), Error> { - let request = self.request()?; - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetOriginalResponse<'_>, Message); diff --git a/http/src/request/application/interaction_callback.rs b/http/src/request/application/interaction_callback.rs index 14a5efe43ae..d0e54f2541e 100644 --- a/http/src/request/application/interaction_callback.rs +++ b/http/src/request/application/interaction_callback.rs @@ -1,8 +1,8 @@ use crate::{ client::Client, error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::Request, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::{application::callback::InteractionResponse, id::InteractionId}; @@ -12,7 +12,6 @@ pub struct InteractionCallback<'a> { interaction_id: InteractionId, interaction_token: String, response: InteractionResponse, - fut: Option>, http: &'a Client, } @@ -27,23 +26,30 @@ impl<'a> InteractionCallback<'a> { interaction_id, interaction_token: interaction_token.into(), response, - fut: None, http, } } - fn start(&mut self) -> Result<(), Error> { + // `self` needs to be consumed and the client returned due to parameters + // being consumed in request construction. + fn request(self) -> Result<(Request, &'a Client), Error> { let request = Request::builder(Route::InteractionCallback { interaction_id: self.interaction_id.0, - interaction_token: self.interaction_token.clone(), + interaction_token: self.interaction_token, }) - .json(&self.response)?; + .json(&self.response)? + .build(); - self.fut - .replace(Box::pin(self.http.request(request.build()))); + Ok((request, self.http)) + } - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + match self.request() { + Ok((request, client)) => client.request(request), + Err(source) => ResponseFuture::error(source), + } } } - -poll_req!(InteractionCallback<'_>, EmptyBody); diff --git a/http/src/request/application/set_command_permissions.rs b/http/src/request/application/set_command_permissions.rs index e67c4620905..1b43275af92 100644 --- a/http/src/request/application/set_command_permissions.rs +++ b/http/src/request/application/set_command_permissions.rs @@ -3,8 +3,9 @@ use crate::{ error::Error, request::{ application::{InteractionError, InteractionErrorType}, - validate, PendingResponse, Request, + validate, Request, RequestBuilder, }, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -28,7 +29,6 @@ pub struct SetCommandPermissions<'a> { application_id: ApplicationId, guild_id: GuildId, fields: Vec, - fut: Option>, http: &'a Client, } @@ -69,27 +69,30 @@ impl<'a> SetCommandPermissions<'a> { application_id, guild_id, fields, - fut: None, http, }) } - fn start(&mut self) -> Result<(), Error> { - let request = Request::builder(Route::SetCommandPermissions { + fn request(&self) -> Result { + Request::builder(Route::SetCommandPermissions { application_id: self.application_id.0, guild_id: self.guild_id.0, }) - .json(&self.fields)?; - - self.fut - .replace(Box::pin(self.http.request(request.build()))); + .json(&self.fields) + .map(RequestBuilder::build) + } - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + match self.request() { + Ok(request) => self.http.request(request), + Err(source) => ResponseFuture::error(source), + } } } -poll_req!(SetCommandPermissions<'_>, CommandPermissions); - #[cfg(test)] mod tests { use super::SetCommandPermissions; diff --git a/http/src/request/application/set_global_commands.rs b/http/src/request/application/set_global_commands.rs index bebe6ed03e0..a1c4d297866 100644 --- a/http/src/request/application/set_global_commands.rs +++ b/http/src/request/application/set_global_commands.rs @@ -1,8 +1,8 @@ use crate::{ client::Client, error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::{Request, RequestBuilder}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::{application::command::Command, id::ApplicationId}; @@ -14,7 +14,6 @@ use twilight_model::{application::command::Command, id::ApplicationId}; pub struct SetGlobalCommands<'a> { commands: Vec, application_id: ApplicationId, - fut: Option>, http: &'a Client, } @@ -27,22 +26,25 @@ impl<'a> SetGlobalCommands<'a> { Self { commands, application_id, - fut: None, http, } } - fn start(&mut self) -> Result<(), Error> { - let request = Request::builder(Route::SetGlobalCommands { + fn request(&self) -> Result { + Request::builder(Route::SetGlobalCommands { application_id: self.application_id.0, }) - .json(&self.commands)?; - - self.fut - .replace(Box::pin(self.http.request(request.build()))); + .json(&self.commands) + .map(RequestBuilder::build) + } - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + match self.request() { + Ok(request) => self.http.request(request), + Err(source) => ResponseFuture::error(source), + } } } - -poll_req!(SetGlobalCommands<'_>, EmptyBody); diff --git a/http/src/request/application/set_guild_commands.rs b/http/src/request/application/set_guild_commands.rs index 33c1629353c..7e63c83027f 100644 --- a/http/src/request/application/set_guild_commands.rs +++ b/http/src/request/application/set_guild_commands.rs @@ -1,8 +1,8 @@ use crate::{ client::Client, error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::{Request, RequestBuilder}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::{ @@ -18,7 +18,6 @@ pub struct SetGuildCommands<'a> { commands: Vec, application_id: ApplicationId, guild_id: GuildId, - fut: Option>, http: &'a Client, } @@ -33,23 +32,26 @@ impl<'a> SetGuildCommands<'a> { commands, application_id, guild_id, - fut: None, http, } } - fn start(&mut self) -> Result<(), Error> { - let request = Request::builder(Route::SetGuildCommands { + fn request(&self) -> Result { + Request::builder(Route::SetGuildCommands { application_id: self.application_id.0, guild_id: self.guild_id.0, }) - .json(&self.commands)?; - - self.fut - .replace(Box::pin(self.http.request(request.build()))); + .json(&self.commands) + .map(RequestBuilder::build) + } - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + match self.request() { + Ok(request) => self.http.request(request), + Err(source) => ResponseFuture::error(source), + } } } - -poll_req!(SetGuildCommands<'_>, EmptyBody); diff --git a/http/src/request/application/update_command_permissions.rs b/http/src/request/application/update_command_permissions.rs index 32c7fcf0938..7dc233be391 100644 --- a/http/src/request/application/update_command_permissions.rs +++ b/http/src/request/application/update_command_permissions.rs @@ -3,9 +3,9 @@ use crate::{ error::Error, request::{ application::{InteractionError, InteractionErrorType}, - validate, PendingResponse, Request, + validate, Request, RequestBuilder, }, - response::marker::ListBody, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use serde::Serialize; @@ -30,7 +30,6 @@ pub struct UpdateCommandPermissions<'a> { command_id: CommandId, guild_id: GuildId, fields: UpdateCommandPermissionsFields, - fut: Option>>, http: &'a Client, } @@ -53,24 +52,27 @@ impl<'a> UpdateCommandPermissions<'a> { command_id, guild_id, fields: UpdateCommandPermissionsFields { permissions }, - fut: None, http, }) } - fn start(&mut self) -> Result<(), Error> { - let request = Request::builder(Route::UpdateCommandPermissions { + fn request(&self) -> Result { + Request::builder(Route::UpdateCommandPermissions { application_id: self.application_id.0, command_id: self.command_id.0, guild_id: self.guild_id.0, }) - .json(&self.fields)?; - - self.fut - .replace(Box::pin(self.http.request(request.build()))); + .json(&self.fields) + .map(RequestBuilder::build) + } - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { + match self.request() { + Ok(request) => self.http.request(request), + Err(source) => ResponseFuture::error(source), + } } } - -poll_req!(UpdateCommandPermissions<'_>, ListBody); diff --git a/http/src/request/application/update_followup_message.rs b/http/src/request/application/update_followup_message.rs index a3a3eff21a6..48406d7cf7d 100644 --- a/http/src/request/application/update_followup_message.rs +++ b/http/src/request/application/update_followup_message.rs @@ -3,8 +3,8 @@ use crate::{ client::Client, error::Error as HttpError, - request::{validate, Form, NullableField, PendingResponse, Request}, - response::marker::EmptyBody, + request::{validate, Form, NullableField, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use serde::Serialize; @@ -148,6 +148,7 @@ struct UpdateFollowupMessageFields { /// // mentioned. /// .allowed_mentions(AllowedMentions::default()) /// .content(Some("test <@3>".to_owned()))? +/// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -156,7 +157,6 @@ struct UpdateFollowupMessageFields { pub struct UpdateFollowupMessage<'a> { fields: UpdateFollowupMessageFields, files: Vec<(String, Vec)>, - fut: Option>, http: &'a Client, message_id: MessageId, token: String, @@ -179,7 +179,6 @@ impl<'a> UpdateFollowupMessage<'a> { ..UpdateFollowupMessageFields::default() }, files: Vec::new(), - fut: None, http, message_id, token: token.into(), @@ -284,6 +283,7 @@ impl<'a> UpdateFollowupMessage<'a> { /// /// client.update_followup_message("token", MessageId(2))? /// .embeds(Some(vec![embed]))? + /// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -371,10 +371,12 @@ impl<'a> UpdateFollowupMessage<'a> { self } - fn request(&mut self) -> Result { + // `self` needs to be consumed and the client returned due to parameters + // being consumed in request construction. + fn request(mut self) -> Result<(Request, &'a Client), HttpError> { let mut request = Request::builder(Route::UpdateWebhookMessage { message_id: self.message_id.0, - token: self.token.clone(), + token: self.token, webhook_id: self.application_id.0, }); @@ -397,15 +399,13 @@ impl<'a> UpdateFollowupMessage<'a> { request = request.json(&self.fields)?; } - Ok(request.build()) + Ok((request.build(), self.http)) } - fn start(&mut self) -> Result<(), HttpError> { - let request = self.request()?; - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + pub fn exec(self) -> ResponseFuture { + match self.request() { + Ok((request, client)) => client.request(request), + Err(source) => ResponseFuture::error(source), + } } } - -poll_req!(UpdateFollowupMessage<'_>, EmptyBody); diff --git a/http/src/request/application/update_global_command.rs b/http/src/request/application/update_global_command.rs index 1806e7d96dc..dd4f986634f 100644 --- a/http/src/request/application/update_global_command.rs +++ b/http/src/request/application/update_global_command.rs @@ -1,8 +1,8 @@ use crate::{ client::Client, error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::{Request, RequestBuilder}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::{ @@ -30,7 +30,6 @@ pub struct UpdateGlobalCommand<'a> { fields: UpdateGlobalCommandFields, command_id: CommandId, application_id: ApplicationId, - fut: Option>, http: &'a Client, } @@ -44,7 +43,6 @@ impl<'a> UpdateGlobalCommand<'a> { application_id, command_id, fields: UpdateGlobalCommandFields::default(), - fut: None, http, } } @@ -74,18 +72,22 @@ impl<'a> UpdateGlobalCommand<'a> { self } - fn start(&mut self) -> Result<(), Error> { - let request = Request::builder(Route::UpdateGlobalCommand { + fn request(&self) -> Result { + Request::builder(Route::UpdateGlobalCommand { application_id: self.application_id.0, command_id: self.command_id.0, }) - .json(&self.fields)?; - - self.fut - .replace(Box::pin(self.http.request(request.build()))); + .json(&self.fields) + .map(RequestBuilder::build) + } - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + match self.request() { + Ok(request) => self.http.request(request), + Err(source) => ResponseFuture::error(source), + } } } - -poll_req!(UpdateGlobalCommand<'_>, EmptyBody); diff --git a/http/src/request/application/update_guild_command.rs b/http/src/request/application/update_guild_command.rs index 9b5713c2144..0bceebd7a6f 100644 --- a/http/src/request/application/update_guild_command.rs +++ b/http/src/request/application/update_guild_command.rs @@ -1,8 +1,8 @@ use crate::{ client::Client, error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::{Request, RequestBuilder}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::{ @@ -31,7 +31,6 @@ pub struct UpdateGuildCommand<'a> { application_id: ApplicationId, command_id: CommandId, guild_id: GuildId, - fut: Option>, http: &'a Client, } @@ -46,7 +45,6 @@ impl<'a> UpdateGuildCommand<'a> { application_id, command_id, fields: UpdateGuildCommandFields::default(), - fut: None, guild_id, http, } @@ -77,19 +75,23 @@ impl<'a> UpdateGuildCommand<'a> { self } - fn start(&mut self) -> Result<(), Error> { - let request = Request::builder(Route::UpdateGuildCommand { + fn request(&self) -> Result { + Request::builder(Route::UpdateGuildCommand { application_id: self.application_id.0, command_id: self.command_id.0, guild_id: self.guild_id.0, }) - .json(&self.fields)?; - - self.fut - .replace(Box::pin(self.http.request(request.build()))); + .json(&self.fields) + .map(RequestBuilder::build) + } - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + match self.request() { + Ok(request) => self.http.request(request), + Err(source) => ResponseFuture::error(source), + } } } - -poll_req!(UpdateGuildCommand<'_>, EmptyBody); diff --git a/http/src/request/application/update_original_response.rs b/http/src/request/application/update_original_response.rs index 2cb5e81078d..5dd82946447 100644 --- a/http/src/request/application/update_original_response.rs +++ b/http/src/request/application/update_original_response.rs @@ -3,7 +3,8 @@ use crate::{ client::Client, error::Error as HttpError, - request::{validate, Form, NullableField, PendingResponse, Request}, + request::{validate, Form, NullableField, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -147,6 +148,7 @@ struct UpdateOriginalResponseFields { /// // mentioned. /// .allowed_mentions(AllowedMentions::default()) /// .content(Some("test <@3>".to_owned()))? +/// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -156,7 +158,6 @@ pub struct UpdateOriginalResponse<'a> { application_id: ApplicationId, fields: UpdateOriginalResponseFields, files: Vec<(String, Vec)>, - fut: Option>, http: &'a Client, token: String, } @@ -177,7 +178,6 @@ impl<'a> UpdateOriginalResponse<'a> { ..UpdateOriginalResponseFields::default() }, files: Vec::new(), - fut: None, http, token: interaction_token.into(), } @@ -281,6 +281,7 @@ impl<'a> UpdateOriginalResponse<'a> { /// /// client.update_interaction_original("token")? /// .embeds(Some(vec![embed]))? + /// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -368,10 +369,12 @@ impl<'a> UpdateOriginalResponse<'a> { self } - fn request(&mut self) -> Result { + // `self` needs to be consumed and the client returned due to parameters + // being consumed in request construction. + fn request(mut self) -> Result<(Request, &'a Client), HttpError> { let mut request = Request::builder(Route::UpdateInteractionOriginal { application_id: self.application_id.0, - interaction_token: self.token.clone(), + interaction_token: self.token, }); if !self.files.is_empty() || self.fields.payload_json.is_some() { @@ -393,15 +396,13 @@ impl<'a> UpdateOriginalResponse<'a> { request = request.json(&self.fields)?; } - Ok(request.build()) + Ok((request.build(), self.http)) } - fn start(&mut self) -> Result<(), HttpError> { - let request = self.request()?; - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + pub fn exec(self) -> ResponseFuture { + match self.request() { + Ok((request, client)) => client.request(request), + Err(source) => ResponseFuture::error(source), + } } } - -poll_req!(UpdateOriginalResponse<'_>, Message); diff --git a/http/src/request/channel/create_pin.rs b/http/src/request/channel/create_pin.rs index 36c3a739e74..73fb33c8558 100644 --- a/http/src/request/channel/create_pin.rs +++ b/http/src/request/channel/create_pin.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{ChannelId, MessageId}; @@ -10,37 +9,44 @@ use twilight_model::id::{ChannelId, MessageId}; /// Create a new pin in a channel. pub struct CreatePin<'a> { channel_id: ChannelId, - fut: Option>, http: &'a Client, message_id: MessageId, reason: Option, } impl<'a> CreatePin<'a> { - pub(crate) fn new(http: &'a Client, channel_id: ChannelId, message_id: MessageId) -> Self { + pub(crate) const fn new( + http: &'a Client, + channel_id: ChannelId, + message_id: MessageId, + ) -> Self { Self { channel_id, - fut: None, http, message_id, reason: None, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::PinMessage { channel_id: self.channel_id.0, message_id: self.message_id.0, }); if let Some(reason) = &self.reason { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -52,5 +58,3 @@ impl<'a> AuditLogReason for CreatePin<'a> { Ok(self) } } - -poll_req!(CreatePin<'_>, EmptyBody); diff --git a/http/src/request/channel/create_typing_trigger.rs b/http/src/request/channel/create_typing_trigger.rs index 6d9391a5f35..79ff0408157 100644 --- a/http/src/request/channel/create_typing_trigger.rs +++ b/http/src/request/channel/create_typing_trigger.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::Request, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::ChannelId; @@ -10,28 +9,22 @@ use twilight_model::id::ChannelId; /// Fire a Typing Start event in the channel. pub struct CreateTypingTrigger<'a> { channel_id: ChannelId, - fut: Option>, http: &'a Client, } impl<'a> CreateTypingTrigger<'a> { - pub(crate) fn new(http: &'a Client, channel_id: ChannelId) -> Self { - Self { - channel_id, - fut: None, - http, - } + pub(crate) const fn new(http: &'a Client, channel_id: ChannelId) -> Self { + Self { channel_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::CreateTypingTrigger { channel_id: self.channel_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(CreateTypingTrigger<'_>, EmptyBody); diff --git a/http/src/request/channel/delete_channel.rs b/http/src/request/channel/delete_channel.rs index 145b81e6647..3cf45b5ee8a 100644 --- a/http/src/request/channel/delete_channel.rs +++ b/http/src/request/channel/delete_channel.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::ResponseFuture, routing::Route, }; use twilight_model::{channel::Channel, id::ChannelId}; @@ -9,34 +9,37 @@ use twilight_model::{channel::Channel, id::ChannelId}; /// Delete a channel by ID. pub struct DeleteChannel<'a> { channel_id: ChannelId, - fut: Option>, http: &'a Client, reason: Option, } impl<'a> DeleteChannel<'a> { - pub(crate) fn new(http: &'a Client, channel_id: ChannelId) -> Self { + pub(crate) const fn new(http: &'a Client, channel_id: ChannelId) -> Self { Self { channel_id, - fut: None, http, reason: None, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::DeleteChannel { channel_id: self.channel_id.0, }); if let Some(reason) = &self.reason { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -48,5 +51,3 @@ impl<'a> AuditLogReason for DeleteChannel<'a> { Ok(self) } } - -poll_req!(DeleteChannel<'_>, Channel); diff --git a/http/src/request/channel/delete_channel_permission.rs b/http/src/request/channel/delete_channel_permission.rs index 08319be1ef8..3e65c65f8d3 100644 --- a/http/src/request/channel/delete_channel_permission.rs +++ b/http/src/request/channel/delete_channel_permission.rs @@ -25,7 +25,7 @@ impl<'a> DeleteChannelPermission<'a> { self.configure(role_id.into().0) } - fn configure(self, target_id: u64) -> DeleteChannelPermissionConfigured<'a> { + const fn configure(self, target_id: u64) -> DeleteChannelPermissionConfigured<'a> { DeleteChannelPermissionConfigured::new(self.http, self.channel_id, target_id) } } diff --git a/http/src/request/channel/delete_channel_permission_configured.rs b/http/src/request/channel/delete_channel_permission_configured.rs index f44e94b172b..f6bc0ab7ff1 100644 --- a/http/src/request/channel/delete_channel_permission_configured.rs +++ b/http/src/request/channel/delete_channel_permission_configured.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::ChannelId; @@ -12,37 +11,40 @@ use twilight_model::id::ChannelId; /// The `target_id` is a `u64`, but it should point to a `RoleId` or a `UserId`. pub struct DeleteChannelPermissionConfigured<'a> { channel_id: ChannelId, - fut: Option>, http: &'a Client, reason: Option, target_id: u64, } impl<'a> DeleteChannelPermissionConfigured<'a> { - pub(crate) fn new(http: &'a Client, channel_id: ChannelId, target_id: u64) -> Self { + pub(crate) const fn new(http: &'a Client, channel_id: ChannelId, target_id: u64) -> Self { Self { channel_id, - fut: None, http, reason: None, target_id, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::DeletePermissionOverwrite { channel_id: self.channel_id.0, target_id: self.target_id, }); if let Some(reason) = &self.reason { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -54,5 +56,3 @@ impl<'a> AuditLogReason for DeleteChannelPermissionConfigured<'a> { Ok(self) } } - -poll_req!(DeleteChannelPermissionConfigured<'_>, EmptyBody); diff --git a/http/src/request/channel/delete_pin.rs b/http/src/request/channel/delete_pin.rs index 9226a5213cc..f9000e0c042 100644 --- a/http/src/request/channel/delete_pin.rs +++ b/http/src/request/channel/delete_pin.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{ChannelId, MessageId}; @@ -10,37 +9,44 @@ use twilight_model::id::{ChannelId, MessageId}; /// Delete a pin in a channel, by ID. pub struct DeletePin<'a> { channel_id: ChannelId, - fut: Option>, http: &'a Client, message_id: MessageId, reason: Option, } impl<'a> DeletePin<'a> { - pub(crate) fn new(http: &'a Client, channel_id: ChannelId, message_id: MessageId) -> Self { + pub(crate) const fn new( + http: &'a Client, + channel_id: ChannelId, + message_id: MessageId, + ) -> Self { Self { channel_id, - fut: None, http, message_id, reason: None, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::UnpinMessage { channel_id: self.channel_id.0, message_id: self.message_id.0, }); if let Some(reason) = &self.reason { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -52,5 +58,3 @@ impl<'a> AuditLogReason for DeletePin<'a> { Ok(self) } } - -poll_req!(DeletePin<'_>, EmptyBody); diff --git a/http/src/request/channel/follow_news_channel.rs b/http/src/request/channel/follow_news_channel.rs index d19dc7966cc..4b39ccfe289 100644 --- a/http/src/request/channel/follow_news_channel.rs +++ b/http/src/request/channel/follow_news_channel.rs @@ -1,9 +1,4 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use serde::Serialize; use twilight_model::{channel::FollowedChannel, id::ChannelId}; @@ -16,35 +11,35 @@ struct FollowNewsChannelFields { pub struct FollowNewsChannel<'a> { channel_id: ChannelId, fields: FollowNewsChannelFields, - fut: Option>, http: &'a Client, } impl<'a> FollowNewsChannel<'a> { - pub(crate) fn new( + pub(crate) const fn new( http: &'a Client, channel_id: ChannelId, webhook_channel_id: ChannelId, ) -> Self { Self { channel_id, - fut: None, http, fields: FollowNewsChannelFields { webhook_channel_id }, } } - fn start(&mut self) -> Result<(), Error> { - let request = Request::builder(Route::FollowNewsChannel { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let mut request = Request::builder(Route::FollowNewsChannel { channel_id: self.channel_id.0, - }) - .json(&self.fields)? - .build(); + }); - self.fut.replace(Box::pin(self.http.request(request))); + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; - Ok(()) + self.http.request(request.build()) } } - -poll_req!(FollowNewsChannel<'_>, FollowedChannel); diff --git a/http/src/request/channel/get_channel.rs b/http/src/request/channel/get_channel.rs index 73e214d936e..0d18dc5bb8a 100644 --- a/http/src/request/channel/get_channel.rs +++ b/http/src/request/channel/get_channel.rs @@ -1,9 +1,4 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::{channel::Channel, id::ChannelId}; /// Get a channel by its ID. @@ -22,33 +17,27 @@ use twilight_model::{channel::Channel, id::ChannelId}; /// /// let channel_id = ChannelId(100); /// -/// let channel = client.channel(channel_id).await?; +/// let channel = client.channel(channel_id).exec().await?; /// # Ok(()) } /// ``` pub struct GetChannel<'a> { channel_id: ChannelId, - fut: Option>, http: &'a Client, } impl<'a> GetChannel<'a> { - pub(crate) fn new(http: &'a Client, channel_id: ChannelId) -> Self { - Self { - channel_id, - fut: None, - http, - } + pub(crate) const fn new(http: &'a Client, channel_id: ChannelId) -> Self { + Self { channel_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetChannel { channel_id: self.channel_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetChannel<'_>, Channel); diff --git a/http/src/request/channel/get_pins.rs b/http/src/request/channel/get_pins.rs index 6d20c03d7a4..d4fa144a16b 100644 --- a/http/src/request/channel/get_pins.rs +++ b/http/src/request/channel/get_pins.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::ListBody, + request::Request, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use twilight_model::{channel::Message, id::ChannelId}; @@ -10,28 +9,22 @@ use twilight_model::{channel::Message, id::ChannelId}; /// Get the pins of a channel. pub struct GetPins<'a> { channel_id: ChannelId, - fut: Option>>, http: &'a Client, } impl<'a> GetPins<'a> { - pub(crate) fn new(http: &'a Client, channel_id: ChannelId) -> Self { - Self { - channel_id, - fut: None, - http, - } + pub(crate) const fn new(http: &'a Client, channel_id: ChannelId) -> Self { + Self { channel_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetPins { channel_id: self.channel_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetPins<'_>, ListBody); diff --git a/http/src/request/channel/invite/create_invite.rs b/http/src/request/channel/invite/create_invite.rs index abd3ff66504..3cf26b5d134 100644 --- a/http/src/request/channel/invite/create_invite.rs +++ b/http/src/request/channel/invite/create_invite.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error as HttpError, - request::{self, validate, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, + request::{self, validate, AuditLogReason, AuditLogReasonError, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -104,6 +104,7 @@ struct CreateInviteFields { /// let invite = client /// .create_invite(channel_id) /// .max_uses(3)? +/// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -112,7 +113,6 @@ struct CreateInviteFields { pub struct CreateInvite<'a> { channel_id: ChannelId, fields: CreateInviteFields, - fut: Option>, http: &'a Client, reason: Option, } @@ -122,7 +122,6 @@ impl<'a> CreateInvite<'a> { Self { channel_id, fields: CreateInviteFields::default(), - fut: None, http, reason: None, } @@ -148,6 +147,7 @@ impl<'a> CreateInvite<'a> { /// let client = Client::new(env::var("DISCORD_TOKEN")?); /// let invite = client.create_invite(ChannelId(1)) /// .max_age(60 * 60)? + /// .exec() /// .await? /// .model() /// .await?; @@ -185,6 +185,7 @@ impl<'a> CreateInvite<'a> { /// let client = Client::new(env::var("DISCORD_TOKEN")?); /// let invite = client.create_invite(ChannelId(1)) /// .max_uses(5)? + /// .exec() /// .await? /// .model() /// .await?; @@ -254,20 +255,29 @@ impl<'a> CreateInvite<'a> { self } - fn start(&mut self) -> Result<(), HttpError> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::CreateInvite { channel_id: self.channel_id.0, - }) - .json(&self.fields)?; + }); + + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; if let Some(reason) = &self.reason { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -280,8 +290,6 @@ impl<'a> AuditLogReason for CreateInvite<'a> { } } -poll_req!(CreateInvite<'_>, Invite); - #[cfg(test)] mod tests { use super::CreateInvite; diff --git a/http/src/request/channel/invite/delete_invite.rs b/http/src/request/channel/invite/delete_invite.rs index 832a84e2300..860936fc23d 100644 --- a/http/src/request/channel/invite/delete_invite.rs +++ b/http/src/request/channel/invite/delete_invite.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; @@ -15,7 +14,6 @@ use crate::{ /// [`MANAGE_GUILD`]: twilight_model::guild::Permissions::MANAGE_GUILD pub struct DeleteInvite<'a> { code: String, - fut: Option>, http: &'a Client, reason: Option, } @@ -24,25 +22,27 @@ impl<'a> DeleteInvite<'a> { pub(crate) fn new(http: &'a Client, code: impl Into) -> Self { Self { code: code.into(), - fut: None, http, reason: None, } } - fn start(&mut self) -> Result<(), Error> { - let mut request = Request::builder(Route::DeleteInvite { - code: self.code.clone(), - }); + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let mut request = Request::builder(Route::DeleteInvite { code: self.code }); if let Some(reason) = &self.reason { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -54,5 +54,3 @@ impl<'a> AuditLogReason for DeleteInvite<'a> { Ok(self) } } - -poll_req!(DeleteInvite<'_>, EmptyBody); diff --git a/http/src/request/channel/invite/get_channel_invites.rs b/http/src/request/channel/invite/get_channel_invites.rs index 05405cb235c..7fba62f36cb 100644 --- a/http/src/request/channel/invite/get_channel_invites.rs +++ b/http/src/request/channel/invite/get_channel_invites.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::ListBody, + request::Request, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use twilight_model::{id::ChannelId, invite::Invite}; @@ -16,28 +15,22 @@ use twilight_model::{id::ChannelId, invite::Invite}; /// [`GuildChannel`]: twilight_model::channel::GuildChannel pub struct GetChannelInvites<'a> { channel_id: ChannelId, - fut: Option>>, http: &'a Client, } impl<'a> GetChannelInvites<'a> { - pub(crate) fn new(http: &'a Client, channel_id: ChannelId) -> Self { - Self { - channel_id, - fut: None, - http, - } + pub(crate) const fn new(http: &'a Client, channel_id: ChannelId) -> Self { + Self { channel_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetChannelInvites { channel_id: self.channel_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetChannelInvites<'_>, ListBody); diff --git a/http/src/request/channel/invite/get_invite.rs b/http/src/request/channel/invite/get_invite.rs index 242960f842a..9776f3b3202 100644 --- a/http/src/request/channel/invite/get_invite.rs +++ b/http/src/request/channel/invite/get_invite.rs @@ -1,9 +1,4 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::invite::Invite; #[derive(Default)] @@ -30,6 +25,7 @@ struct GetInviteFields { /// let invite = client /// .invite("code") /// .with_counts() +/// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -39,7 +35,6 @@ struct GetInviteFields { pub struct GetInvite<'a> { code: String, fields: GetInviteFields, - fut: Option>, http: &'a Client, } @@ -48,7 +43,6 @@ impl<'a> GetInvite<'a> { Self { code: code.into(), fields: GetInviteFields::default(), - fut: None, http, } } @@ -67,17 +61,16 @@ impl<'a> GetInvite<'a> { self } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetInviteWithExpiration { - code: self.code.clone(), + code: self.code, with_counts: self.fields.with_counts, with_expiration: self.fields.with_expiration, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetInvite<'_>, Invite); diff --git a/http/src/request/channel/message/create_message.rs b/http/src/request/channel/message/create_message.rs index 0a288395915..ba26e0f329c 100644 --- a/http/src/request/channel/message/create_message.rs +++ b/http/src/request/channel/message/create_message.rs @@ -4,8 +4,9 @@ use crate::{ request::{ multipart::Form, validate::{self, EmbedValidationError}, - PendingResponse, Request, + Request, }, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -140,6 +141,7 @@ pub(crate) struct CreateMessageFields { /// .create_message(channel_id) /// .content("Twilight is best pony")? /// .tts(true) +/// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -147,7 +149,6 @@ pub struct CreateMessage<'a> { channel_id: ChannelId, pub(crate) fields: CreateMessageFields, files: Vec<(String, Vec)>, - fut: Option>, http: &'a Client, } @@ -160,7 +161,6 @@ impl<'a> CreateMessage<'a> { ..CreateMessageFields::default() }, files: Vec::new(), - fut: None, http, } } @@ -340,7 +340,10 @@ impl<'a> CreateMessage<'a> { self } - fn start(&mut self) -> Result<(), HttpError> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::CreateMessage { channel_id: self.channel_id.0, }); @@ -348,27 +351,29 @@ impl<'a> CreateMessage<'a> { if !self.files.is_empty() || self.fields.payload_json.is_some() { let mut form = Form::new(); - for (index, (name, file)) in self.files.drain(..).enumerate() { - form.file(format!("{}", index).as_bytes(), name.as_bytes(), &file); + for (index, (name, file)) in self.files.iter().enumerate() { + form.file(format!("{}", index).as_bytes(), name.as_bytes(), file); } if let Some(payload_json) = &self.fields.payload_json { form.payload_json(payload_json); } else { - let body = crate::json::to_vec(&self.fields).map_err(HttpError::json)?; + let body = match crate::json::to_vec(&self.fields) { + Ok(body) => body, + Err(source) => return ResponseFuture::error(HttpError::json(source)), + }; + form.payload_json(&body); } request = request.form(form); } else { - request = request.json(&self.fields)?; + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; } - self.fut - .replace(Box::pin(self.http.request(request.build()))); - - Ok(()) + self.http.request(request.build()) } } - -poll_req!(CreateMessage<'_>, Message); diff --git a/http/src/request/channel/message/crosspost_message.rs b/http/src/request/channel/message/crosspost_message.rs index f4c36b4ea3a..190c669c6a5 100644 --- a/http/src/request/channel/message/crosspost_message.rs +++ b/http/src/request/channel/message/crosspost_message.rs @@ -1,9 +1,4 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::{ channel::Message, id::{ChannelId, MessageId}, @@ -12,31 +7,32 @@ use twilight_model::{ /// Crosspost a message by [`ChannelId`] and [`MessageId`]. pub struct CrosspostMessage<'a> { channel_id: ChannelId, - fut: Option>, http: &'a Client, message_id: MessageId, } impl<'a> CrosspostMessage<'a> { - pub(crate) fn new(http: &'a Client, channel_id: ChannelId, message_id: MessageId) -> Self { + pub(crate) const fn new( + http: &'a Client, + channel_id: ChannelId, + message_id: MessageId, + ) -> Self { Self { channel_id, - fut: None, http, message_id, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::CrosspostMessage { channel_id: self.channel_id.0, message_id: self.message_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(CrosspostMessage<'_>, Message); diff --git a/http/src/request/channel/message/delete_message.rs b/http/src/request/channel/message/delete_message.rs index df24fdd35d7..a2cda37a2d1 100644 --- a/http/src/request/channel/message/delete_message.rs +++ b/http/src/request/channel/message/delete_message.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{ChannelId, MessageId}; @@ -10,37 +9,44 @@ use twilight_model::id::{ChannelId, MessageId}; /// Delete a message by [`ChannelId`] and [`MessageId`]. pub struct DeleteMessage<'a> { channel_id: ChannelId, - fut: Option>, http: &'a Client, message_id: MessageId, reason: Option, } impl<'a> DeleteMessage<'a> { - pub(crate) fn new(http: &'a Client, channel_id: ChannelId, message_id: MessageId) -> Self { + pub(crate) const fn new( + http: &'a Client, + channel_id: ChannelId, + message_id: MessageId, + ) -> Self { Self { channel_id, - fut: None, http, message_id, reason: None, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::DeleteMessage { channel_id: self.channel_id.0, message_id: self.message_id.0, }); if let Some(reason) = &self.reason { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -52,5 +58,3 @@ impl<'a> AuditLogReason for DeleteMessage<'a> { Ok(self) } } - -poll_req!(DeleteMessage<'_>, EmptyBody); diff --git a/http/src/request/channel/message/delete_messages.rs b/http/src/request/channel/message/delete_messages.rs index 8cf5fb3bdb9..61c2ea55bde 100644 --- a/http/src/request/channel/message/delete_messages.rs +++ b/http/src/request/channel/message/delete_messages.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use serde::Serialize; @@ -23,7 +22,6 @@ struct DeleteMessagesFields { pub struct DeleteMessages<'a> { channel_id: ChannelId, fields: DeleteMessagesFields, - fut: Option>, http: &'a Client, reason: Option, } @@ -39,26 +37,34 @@ impl<'a> DeleteMessages<'a> { fields: DeleteMessagesFields { messages: message_ids.into(), }, - fut: None, http, reason: None, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::DeleteMessages { channel_id: self.channel_id.0, - }) - .json(&self.fields)?; + }); + + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; if let Some(reason) = &self.reason { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -70,5 +76,3 @@ impl<'a> AuditLogReason for DeleteMessages<'a> { Ok(self) } } - -poll_req!(DeleteMessages<'_>, EmptyBody); diff --git a/http/src/request/channel/message/get_channel_messages.rs b/http/src/request/channel/message/get_channel_messages.rs index eedc38097ba..bb216fbde82 100644 --- a/http/src/request/channel/message/get_channel_messages.rs +++ b/http/src/request/channel/message/get_channel_messages.rs @@ -1,9 +1,8 @@ use super::GetChannelMessagesConfigured; use crate::{ client::Client, - error::Error as HttpError, - request::{validate, PendingResponse, Request}, - response::marker::ListBody, + request::{validate, Request}, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use std::{ @@ -96,6 +95,7 @@ struct GetChannelMessagesFields { /// .channel_messages(channel_id) /// .before(message_id) /// .limit(6u64)? +/// .exec() /// .await?; /// /// # Ok(()) } @@ -109,7 +109,6 @@ struct GetChannelMessagesFields { pub struct GetChannelMessages<'a> { channel_id: ChannelId, fields: GetChannelMessagesFields, - fut: Option>>, http: &'a Client, } @@ -118,12 +117,11 @@ impl<'a> GetChannelMessages<'a> { Self { channel_id, fields: GetChannelMessagesFields::default(), - fut: None, http, } } - pub fn after(self, message_id: MessageId) -> GetChannelMessagesConfigured<'a> { + pub const fn after(self, message_id: MessageId) -> GetChannelMessagesConfigured<'a> { GetChannelMessagesConfigured::new( self.http, self.channel_id, @@ -134,7 +132,7 @@ impl<'a> GetChannelMessages<'a> { ) } - pub fn around(self, message_id: MessageId) -> GetChannelMessagesConfigured<'a> { + pub const fn around(self, message_id: MessageId) -> GetChannelMessagesConfigured<'a> { GetChannelMessagesConfigured::new( self.http, self.channel_id, @@ -145,7 +143,7 @@ impl<'a> GetChannelMessages<'a> { ) } - pub fn before(self, message_id: MessageId) -> GetChannelMessagesConfigured<'a> { + pub const fn before(self, message_id: MessageId) -> GetChannelMessagesConfigured<'a> { GetChannelMessagesConfigured::new( self.http, self.channel_id, @@ -176,7 +174,10 @@ impl<'a> GetChannelMessages<'a> { Ok(self) } - fn start(&mut self) -> Result<(), HttpError> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetMessages { after: None, around: None, @@ -185,10 +186,6 @@ impl<'a> GetChannelMessages<'a> { limit: self.fields.limit, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetChannelMessages<'_>, ListBody); diff --git a/http/src/request/channel/message/get_channel_messages_configured.rs b/http/src/request/channel/message/get_channel_messages_configured.rs index 9e6ede1efbc..98d966aab45 100644 --- a/http/src/request/channel/message/get_channel_messages_configured.rs +++ b/http/src/request/channel/message/get_channel_messages_configured.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error as HttpError, - request::{validate, PendingResponse, Request}, - response::marker::ListBody, + request::{validate, Request}, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use std::{ @@ -86,12 +85,11 @@ pub struct GetChannelMessagesConfigured<'a> { before: Option, channel_id: ChannelId, fields: GetChannelMessagesConfiguredFields, - fut: Option>>, http: &'a Client, } impl<'a> GetChannelMessagesConfigured<'a> { - pub(crate) fn new( + pub(crate) const fn new( http: &'a Client, channel_id: ChannelId, after: Option, @@ -105,7 +103,6 @@ impl<'a> GetChannelMessagesConfigured<'a> { before, channel_id, fields: GetChannelMessagesConfiguredFields { limit }, - fut: None, http, } } @@ -130,7 +127,10 @@ impl<'a> GetChannelMessagesConfigured<'a> { Ok(self) } - fn start(&mut self) -> Result<(), HttpError> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetMessages { after: self.after.map(|x| x.0), around: self.around.map(|x| x.0), @@ -139,10 +139,6 @@ impl<'a> GetChannelMessagesConfigured<'a> { limit: self.fields.limit, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetChannelMessagesConfigured<'_>, ListBody); diff --git a/http/src/request/channel/message/get_message.rs b/http/src/request/channel/message/get_message.rs index 808099e2507..1e54b775f56 100644 --- a/http/src/request/channel/message/get_message.rs +++ b/http/src/request/channel/message/get_message.rs @@ -1,9 +1,4 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::{ channel::Message, id::{ChannelId, MessageId}, @@ -12,31 +7,32 @@ use twilight_model::{ /// Get a message by [`ChannelId`] and [`MessageId`]. pub struct GetMessage<'a> { channel_id: ChannelId, - fut: Option>, http: &'a Client, message_id: MessageId, } impl<'a> GetMessage<'a> { - pub(crate) fn new(http: &'a Client, channel_id: ChannelId, message_id: MessageId) -> Self { + pub(crate) const fn new( + http: &'a Client, + channel_id: ChannelId, + message_id: MessageId, + ) -> Self { Self { channel_id, - fut: None, http, message_id, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetMessage { channel_id: self.channel_id.0, message_id: self.message_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetMessage<'_>, Message); diff --git a/http/src/request/channel/message/update_message.rs b/http/src/request/channel/message/update_message.rs index bc83de14a56..508c2f28126 100644 --- a/http/src/request/channel/message/update_message.rs +++ b/http/src/request/channel/message/update_message.rs @@ -1,10 +1,10 @@ use crate::{ client::Client, - error::Error as HttpError, request::{ validate::{self, EmbedValidationError}, - NullableField, PendingResponse, Request, + NullableField, Request, }, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -146,6 +146,7 @@ struct UpdateMessageFields { /// let client = Client::new("my token"); /// client.update_message(ChannelId(1), MessageId(2)) /// .content("test update".to_owned())? +/// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -161,13 +162,13 @@ struct UpdateMessageFields { /// # let client = Client::new("my token"); /// client.update_message(ChannelId(1), MessageId(2)) /// .content(None)? +/// .exec() /// .await?; /// # Ok(()) } /// ``` pub struct UpdateMessage<'a> { channel_id: ChannelId, fields: UpdateMessageFields, - fut: Option>, http: &'a Client, message_id: MessageId, } @@ -177,7 +178,6 @@ impl<'a> UpdateMessage<'a> { Self { channel_id, fields: UpdateMessageFields::default(), - fut: None, http, message_id, } @@ -339,18 +339,20 @@ impl<'a> UpdateMessage<'a> { self } - fn start(&mut self) -> Result<(), HttpError> { - let request = Request::builder(Route::UpdateMessage { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let mut request = Request::builder(Route::UpdateMessage { channel_id: self.channel_id.0, message_id: self.message_id.0, - }) - .json(&self.fields)? - .build(); + }); - self.fut.replace(Box::pin(self.http.request(request))); + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; - Ok(()) + self.http.request(request.build()) } } - -poll_req!(UpdateMessage<'_>, Message); diff --git a/http/src/request/channel/reaction/create_reaction.rs b/http/src/request/channel/reaction/create_reaction.rs index 80fe45b0ce3..c96fa7ef3a5 100644 --- a/http/src/request/channel/reaction/create_reaction.rs +++ b/http/src/request/channel/reaction/create_reaction.rs @@ -1,9 +1,8 @@ use super::RequestReactionType; use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::Request, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{ChannelId, MessageId}; @@ -29,19 +28,19 @@ use twilight_model::id::{ChannelId, MessageId}; /// /// let reaction = client /// .create_reaction(channel_id, message_id, emoji) +/// .exec() /// .await?; /// # Ok(()) } /// ``` pub struct CreateReaction<'a> { channel_id: ChannelId, emoji: RequestReactionType, - fut: Option>, http: &'a Client, message_id: MessageId, } impl<'a> CreateReaction<'a> { - pub(crate) fn new( + pub(crate) const fn new( http: &'a Client, channel_id: ChannelId, message_id: MessageId, @@ -50,7 +49,6 @@ impl<'a> CreateReaction<'a> { Self { channel_id, emoji, - fut: None, http, message_id, } @@ -64,17 +62,14 @@ impl<'a> CreateReaction<'a> { }) } - fn start(&mut self) -> Result<(), Error> { - let request = self.request(); - - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + self.http.request(self.request()) } } -poll_req!(CreateReaction<'_>, EmptyBody); - #[cfg(test)] mod tests { use super::CreateReaction; diff --git a/http/src/request/channel/reaction/delete_all_reaction.rs b/http/src/request/channel/reaction/delete_all_reaction.rs index 68f357071b9..f472527531f 100644 --- a/http/src/request/channel/reaction/delete_all_reaction.rs +++ b/http/src/request/channel/reaction/delete_all_reaction.rs @@ -1,9 +1,8 @@ use super::RequestReactionType; use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::Request, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{ChannelId, MessageId}; @@ -12,13 +11,12 @@ use twilight_model::id::{ChannelId, MessageId}; pub struct DeleteAllReaction<'a> { channel_id: ChannelId, emoji: RequestReactionType, - fut: Option>, http: &'a Client, message_id: MessageId, } impl<'a> DeleteAllReaction<'a> { - pub(crate) fn new( + pub(crate) const fn new( http: &'a Client, channel_id: ChannelId, message_id: MessageId, @@ -27,23 +25,21 @@ impl<'a> DeleteAllReaction<'a> { Self { channel_id, emoji, - fut: None, http, message_id, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::DeleteMessageSpecificReaction { channel_id: self.channel_id.0, message_id: self.message_id.0, emoji: self.emoji.display().to_string(), }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(DeleteAllReaction<'_>, EmptyBody); diff --git a/http/src/request/channel/reaction/delete_all_reactions.rs b/http/src/request/channel/reaction/delete_all_reactions.rs index 06e9c57002e..90ef4b164f6 100644 --- a/http/src/request/channel/reaction/delete_all_reactions.rs +++ b/http/src/request/channel/reaction/delete_all_reactions.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::Request, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{ChannelId, MessageId}; @@ -10,31 +9,32 @@ use twilight_model::id::{ChannelId, MessageId}; /// Delete all reactions by all users on a message. pub struct DeleteAllReactions<'a> { channel_id: ChannelId, - fut: Option>, http: &'a Client, message_id: MessageId, } impl<'a> DeleteAllReactions<'a> { - pub(crate) fn new(http: &'a Client, channel_id: ChannelId, message_id: MessageId) -> Self { + pub(crate) const fn new( + http: &'a Client, + channel_id: ChannelId, + message_id: MessageId, + ) -> Self { Self { channel_id, - fut: None, http, message_id, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::DeleteMessageReactions { channel_id: self.channel_id.0, message_id: self.message_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(DeleteAllReactions<'_>, EmptyBody); diff --git a/http/src/request/channel/reaction/delete_reaction.rs b/http/src/request/channel/reaction/delete_reaction.rs index 97bb556a56f..a034b55d259 100644 --- a/http/src/request/channel/reaction/delete_reaction.rs +++ b/http/src/request/channel/reaction/delete_reaction.rs @@ -1,9 +1,8 @@ use super::RequestReactionType; use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::Request, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{ChannelId, MessageId}; @@ -12,7 +11,6 @@ use twilight_model::id::{ChannelId, MessageId}; pub struct DeleteReaction<'a> { channel_id: ChannelId, emoji: RequestReactionType, - fut: Option>, http: &'a Client, message_id: MessageId, target_user: String, @@ -29,25 +27,23 @@ impl<'a> DeleteReaction<'a> { Self { channel_id, emoji, - fut: None, http, message_id, target_user: target_user.into(), } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::DeleteReaction { channel_id: self.channel_id.0, emoji: self.emoji.display().to_string(), message_id: self.message_id.0, - user: self.target_user.clone(), + user: self.target_user, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(DeleteReaction<'_>, EmptyBody); diff --git a/http/src/request/channel/reaction/get_reactions.rs b/http/src/request/channel/reaction/get_reactions.rs index c7b488ca9e8..80f58bd58b9 100644 --- a/http/src/request/channel/reaction/get_reactions.rs +++ b/http/src/request/channel/reaction/get_reactions.rs @@ -1,9 +1,8 @@ use super::RequestReactionType; use crate::{ client::Client, - error::Error as HttpError, - request::{validate, PendingResponse, Request}, - response::marker::ListBody, + request::{validate, Request}, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use std::{ @@ -77,7 +76,6 @@ pub struct GetReactions<'a> { channel_id: ChannelId, emoji: RequestReactionType, fields: GetReactionsFields, - fut: Option>>, http: &'a Client, message_id: MessageId, } @@ -93,7 +91,6 @@ impl<'a> GetReactions<'a> { channel_id, emoji, fields: GetReactionsFields::default(), - fut: None, http, message_id, } @@ -127,7 +124,10 @@ impl<'a> GetReactions<'a> { Ok(self) } - fn start(&mut self) -> Result<(), HttpError> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetReactionUsers { after: self.fields.after.map(|x| x.0), channel_id: self.channel_id.0, @@ -136,10 +136,6 @@ impl<'a> GetReactions<'a> { message_id: self.message_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetReactions<'_>, ListBody); diff --git a/http/src/request/channel/stage/create_stage_instance.rs b/http/src/request/channel/stage/create_stage_instance.rs index bded790503b..fdaa95191e8 100644 --- a/http/src/request/channel/stage/create_stage_instance.rs +++ b/http/src/request/channel/stage/create_stage_instance.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error as HttpError, - request::{validate, PendingResponse, Request}, - response::marker::EmptyBody, + request::{validate, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use serde::Serialize; @@ -82,7 +81,6 @@ struct CreateStageInstanceFields { /// Requires the user to be a moderator of the stage channel. pub struct CreateStageInstance<'a> { fields: CreateStageInstanceFields, - fut: Option>, http: &'a Client, } @@ -113,7 +111,6 @@ impl<'a> CreateStageInstance<'a> { topic, ..CreateStageInstanceFields::default() }, - fut: None, http, }) } @@ -125,15 +122,17 @@ impl<'a> CreateStageInstance<'a> { self } - fn start(&mut self) -> Result<(), HttpError> { - let request = Request::builder(Route::CreateStageInstance) - .json(&self.fields)? - .build(); + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let mut request = Request::builder(Route::CreateStageInstance); - self.fut.replace(Box::pin(self.http.request(request))); + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; - Ok(()) + self.http.request(request.build()) } } - -poll_req!(CreateStageInstance<'_>, EmptyBody); diff --git a/http/src/request/channel/stage/delete_stage_instance.rs b/http/src/request/channel/stage/delete_stage_instance.rs index 149cb6edec2..6dd67cd386d 100644 --- a/http/src/request/channel/stage/delete_stage_instance.rs +++ b/http/src/request/channel/stage/delete_stage_instance.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::Request, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::ChannelId; @@ -12,28 +11,22 @@ use twilight_model::id::ChannelId; /// Requires the user to be a moderator of the stage channel. pub struct DeleteStageInstance<'a> { channel_id: ChannelId, - fut: Option>, http: &'a Client, } impl<'a> DeleteStageInstance<'a> { - pub(crate) fn new(http: &'a Client, channel_id: ChannelId) -> Self { - Self { - channel_id, - fut: None, - http, - } + pub(crate) const fn new(http: &'a Client, channel_id: ChannelId) -> Self { + Self { channel_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::DeleteStageInstance { channel_id: self.channel_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(DeleteStageInstance<'_>, EmptyBody); diff --git a/http/src/request/channel/stage/get_stage_instance.rs b/http/src/request/channel/stage/get_stage_instance.rs index 69aabeb1f26..8aa250d668a 100644 --- a/http/src/request/channel/stage/get_stage_instance.rs +++ b/http/src/request/channel/stage/get_stage_instance.rs @@ -1,36 +1,25 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::{channel::StageInstance, id::ChannelId}; /// Gets the stage instance associated with a stage channel, if it exists. pub struct GetStageInstance<'a> { channel_id: ChannelId, - fut: Option>, http: &'a Client, } impl<'a> GetStageInstance<'a> { - pub(crate) fn new(http: &'a Client, channel_id: ChannelId) -> Self { - Self { - channel_id, - fut: None, - http, - } + pub(crate) const fn new(http: &'a Client, channel_id: ChannelId) -> Self { + Self { channel_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetStageInstance { channel_id: self.channel_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetStageInstance<'_>, StageInstance); diff --git a/http/src/request/channel/stage/update_stage_instance.rs b/http/src/request/channel/stage/update_stage_instance.rs index 8771ff03b74..b31536e516a 100644 --- a/http/src/request/channel/stage/update_stage_instance.rs +++ b/http/src/request/channel/stage/update_stage_instance.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error as HttpError, - request::{validate, PendingResponse, Request}, - response::marker::EmptyBody, + request::{validate, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use serde::Serialize; @@ -83,7 +82,6 @@ struct UpdateStageInstanceFields { pub struct UpdateStageInstance<'a> { channel_id: ChannelId, fields: UpdateStageInstanceFields, - fut: Option>, http: &'a Client, } @@ -92,7 +90,6 @@ impl<'a> UpdateStageInstance<'a> { Self { channel_id, fields: UpdateStageInstanceFields::default(), - fut: None, http, } } @@ -122,17 +119,19 @@ impl<'a> UpdateStageInstance<'a> { Ok(self) } - fn start(&mut self) -> Result<(), HttpError> { - let request = Request::builder(Route::UpdateStageInstance { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let mut request = Request::builder(Route::UpdateStageInstance { channel_id: self.channel_id.0, - }) - .json(&self.fields)? - .build(); + }); - self.fut.replace(Box::pin(self.http.request(request))); + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; - Ok(()) + self.http.request(request.build()) } } - -poll_req!(UpdateStageInstance<'_>, EmptyBody); diff --git a/http/src/request/channel/update_channel.rs b/http/src/request/channel/update_channel.rs index 75b2996fcf8..38a162883e4 100644 --- a/http/src/request/channel/update_channel.rs +++ b/http/src/request/channel/update_channel.rs @@ -1,10 +1,8 @@ use crate::{ client::Client, error::Error as HttpError, - request::{ - self, validate, AuditLogReason, AuditLogReasonError, NullableField, PendingResponse, - Request, - }, + request::{self, validate, AuditLogReason, AuditLogReasonError, NullableField, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -117,7 +115,6 @@ struct UpdateChannelFields { pub struct UpdateChannel<'a> { channel_id: ChannelId, fields: UpdateChannelFields, - fut: Option>, http: &'a Client, reason: Option, } @@ -127,7 +124,6 @@ impl<'a> UpdateChannel<'a> { Self { channel_id, fields: UpdateChannelFields::default(), - fut: None, http, reason: None, } @@ -294,7 +290,7 @@ impl<'a> UpdateChannel<'a> { self } - fn start(&mut self) -> Result<(), HttpError> { + fn request(&self) -> Result { let mut request = Request::builder(Route::UpdateChannel { channel_id: self.channel_id.0, }) @@ -304,10 +300,17 @@ impl<'a> UpdateChannel<'a> { request = request.headers(request::audit_header(reason)?); } - self.fut - .replace(Box::pin(self.http.request(request.build()))); + Ok(request.build()) + } - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + match self.request() { + Ok(request) => self.http.request(request), + Err(source) => ResponseFuture::error(source), + } } } @@ -319,5 +322,3 @@ impl<'a> AuditLogReason for UpdateChannel<'a> { Ok(self) } } - -poll_req!(UpdateChannel<'_>, Channel); diff --git a/http/src/request/channel/update_channel_permission.rs b/http/src/request/channel/update_channel_permission.rs index 9a2a4bb3411..91a071f6c02 100644 --- a/http/src/request/channel/update_channel_permission.rs +++ b/http/src/request/channel/update_channel_permission.rs @@ -28,6 +28,7 @@ use twilight_model::{ /// /// client.update_channel_permission(channel_id, allow, deny) /// .role(role_id) +/// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -63,7 +64,10 @@ impl<'a> UpdateChannelPermission<'a> { self.configure(&PermissionOverwriteType::Role(role_id.into())) } - fn configure(self, target: &PermissionOverwriteType) -> UpdateChannelPermissionConfigured<'a> { + const fn configure( + self, + target: &PermissionOverwriteType, + ) -> UpdateChannelPermissionConfigured<'a> { UpdateChannelPermissionConfigured::new( self.http, self.channel_id, diff --git a/http/src/request/channel/update_channel_permission_configured.rs b/http/src/request/channel/update_channel_permission_configured.rs index 63401bd540c..dd8b50cc1ff 100644 --- a/http/src/request/channel/update_channel_permission_configured.rs +++ b/http/src/request/channel/update_channel_permission_configured.rs @@ -1,8 +1,8 @@ use crate::{ client::Client, error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use serde::Serialize; @@ -24,14 +24,13 @@ struct UpdateChannelPermissionConfiguredFields { pub struct UpdateChannelPermissionConfigured<'a> { channel_id: ChannelId, fields: UpdateChannelPermissionConfiguredFields, - fut: Option>, http: &'a Client, target_id: u64, reason: Option, } impl<'a> UpdateChannelPermissionConfigured<'a> { - pub(crate) fn new( + pub(crate) const fn new( http: &'a Client, channel_id: ChannelId, allow: Permissions, @@ -54,7 +53,6 @@ impl<'a> UpdateChannelPermissionConfigured<'a> { deny, kind: name, }, - fut: None, http, target_id, reason: None, @@ -75,12 +73,14 @@ impl<'a> UpdateChannelPermissionConfigured<'a> { Ok(request.build()) } - fn start(&mut self) -> Result<(), Error> { - let request = self.request()?; - - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + match self.request() { + Ok(request) => self.http.request(request), + Err(source) => ResponseFuture::error(source), + } } } @@ -93,8 +93,6 @@ impl<'a> AuditLogReason for UpdateChannelPermissionConfigured<'a> { } } -poll_req!(UpdateChannelPermissionConfigured<'_>, EmptyBody); - #[cfg(test)] mod tests { use super::{UpdateChannelPermissionConfigured, UpdateChannelPermissionConfiguredFields}; diff --git a/http/src/request/channel/webhook/create_webhook.rs b/http/src/request/channel/webhook/create_webhook.rs index e4e497630ef..fe499d53c5d 100644 --- a/http/src/request/channel/webhook/create_webhook.rs +++ b/http/src/request/channel/webhook/create_webhook.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -29,13 +29,13 @@ struct CreateWebhookFields { /// /// let webhook = client /// .create_webhook(channel_id, "Twily Bot") +/// .exec() /// .await?; /// # Ok(()) } /// ``` pub struct CreateWebhook<'a> { channel_id: ChannelId, fields: CreateWebhookFields, - fut: Option>, http: &'a Client, reason: Option, } @@ -48,7 +48,6 @@ impl<'a> CreateWebhook<'a> { avatar: None, name: name.into(), }, - fut: None, http, reason: None, } @@ -67,20 +66,29 @@ impl<'a> CreateWebhook<'a> { self } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::CreateWebhook { channel_id: self.channel_id.0, - }) - .json(&self.fields)?; + }); + + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; if let Some(reason) = self.reason.as_ref() { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -92,5 +100,3 @@ impl<'a> AuditLogReason for CreateWebhook<'a> { Ok(self) } } - -poll_req!(CreateWebhook<'_>, Webhook); diff --git a/http/src/request/channel/webhook/delete_webhook.rs b/http/src/request/channel/webhook/delete_webhook.rs index 651d773d3f4..0c924c7a204 100644 --- a/http/src/request/channel/webhook/delete_webhook.rs +++ b/http/src/request/channel/webhook/delete_webhook.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::WebhookId; @@ -14,17 +13,15 @@ struct DeleteWebhookParams { /// Delete a webhook by its ID. pub struct DeleteWebhook<'a> { fields: DeleteWebhookParams, - fut: Option>, http: &'a Client, id: WebhookId, reason: Option, } impl<'a> DeleteWebhook<'a> { - pub(crate) fn new(http: &'a Client, id: WebhookId) -> Self { + pub(crate) const fn new(http: &'a Client, id: WebhookId) -> Self { Self { fields: DeleteWebhookParams { token: None }, - fut: None, http, id, reason: None, @@ -38,20 +35,25 @@ impl<'a> DeleteWebhook<'a> { self } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::DeleteWebhook { webhook_id: self.id.0, - token: self.fields.token.clone(), + token: self.fields.token, }); if let Some(reason) = self.reason.as_ref() { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -63,5 +65,3 @@ impl<'a> AuditLogReason for DeleteWebhook<'a> { Ok(self) } } - -poll_req!(DeleteWebhook<'_>, EmptyBody); diff --git a/http/src/request/channel/webhook/delete_webhook_message.rs b/http/src/request/channel/webhook/delete_webhook_message.rs index 8eacc0b4ba5..1bb319fb95a 100644 --- a/http/src/request/channel/webhook/delete_webhook_message.rs +++ b/http/src/request/channel/webhook/delete_webhook_message.rs @@ -1,8 +1,8 @@ use crate::{ client::Client, error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{MessageId, WebhookId}; @@ -22,11 +22,11 @@ use twilight_model::id::{MessageId, WebhookId}; /// client /// .delete_webhook_message(WebhookId(1), "token here", MessageId(2)) /// .reason("reason here")? +/// .exec() /// .await?; /// # Ok(()) } /// ``` pub struct DeleteWebhookMessage<'a> { - fut: Option>, http: &'a Client, message_id: MessageId, reason: Option, @@ -42,7 +42,6 @@ impl<'a> DeleteWebhookMessage<'a> { message_id: MessageId, ) -> Self { Self { - fut: None, http, message_id, reason: None, @@ -51,10 +50,12 @@ impl<'a> DeleteWebhookMessage<'a> { } } - fn request(&self) -> Result { + // `self` needs to be consumed and the client returned due to parameters + // being consumed in request construction. + fn request(self) -> Result<(Request, &'a Client), Error> { let mut request = Request::builder(Route::DeleteWebhookMessage { message_id: self.message_id.0, - token: self.token.clone(), + token: self.token, webhook_id: self.webhook_id.0, }) .use_authorization_token(false); @@ -63,14 +64,17 @@ impl<'a> DeleteWebhookMessage<'a> { request = request.headers(request::audit_header(reason)?); } - Ok(request.build()) + Ok((request.build(), self.http)) } - fn start(&mut self) -> Result<(), Error> { - let request = self.request()?; - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + match self.request() { + Ok((request, client)) => client.request(request), + Err(source) => ResponseFuture::error(source), + } } } @@ -83,8 +87,6 @@ impl<'a> AuditLogReason for DeleteWebhookMessage<'a> { } } -poll_req!(DeleteWebhookMessage<'_>, EmptyBody); - #[cfg(test)] mod tests { use super::DeleteWebhookMessage; @@ -95,7 +97,7 @@ mod tests { fn test_request() { let client = Client::new("token"); let builder = DeleteWebhookMessage::new(&client, WebhookId(1), "token", MessageId(2)); - let actual = builder.request().expect("failed to create request"); + let (actual, _) = builder.request().expect("failed to create request"); let expected = Request::from_route(Route::DeleteWebhookMessage { message_id: 2, diff --git a/http/src/request/channel/webhook/execute_webhook.rs b/http/src/request/channel/webhook/execute_webhook.rs index 430dd97334c..fb0c871a0c4 100644 --- a/http/src/request/channel/webhook/execute_webhook.rs +++ b/http/src/request/channel/webhook/execute_webhook.rs @@ -2,8 +2,8 @@ use super::ExecuteWebhookAndWait; use crate::{ client::Client, error::Error, - request::{Form, PendingResponse, Request}, - response::marker::EmptyBody, + request::{Form, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use serde::Serialize; @@ -48,6 +48,7 @@ pub(crate) struct ExecuteWebhookFields { /// client /// .execute_webhook(id, "webhook token") /// .content("Pinkie...") +/// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -58,7 +59,6 @@ pub(crate) struct ExecuteWebhookFields { pub struct ExecuteWebhook<'a> { pub(crate) fields: ExecuteWebhookFields, files: Vec<(String, Vec)>, - fut: Option>, pub(super) http: &'a Client, token: String, webhook_id: WebhookId, @@ -69,7 +69,6 @@ impl<'a> ExecuteWebhook<'a> { Self { fields: ExecuteWebhookFields::default(), files: Vec::new(), - fut: None, http, token: token.into(), webhook_id, @@ -151,6 +150,7 @@ impl<'a> ExecuteWebhook<'a> { /// .content("some content") /// .embeds(vec![EmbedBuilder::new().title("title").build()?]) /// .wait() + /// .exec() /// .await? /// .model() /// .await?; @@ -172,6 +172,7 @@ impl<'a> ExecuteWebhook<'a> { /// .content("some content") /// .payload_json(r#"{ "content": "other content", "embeds": [ { "title": "title" } ] }"#) /// .wait() + /// .exec() /// .await? /// .model() /// .await?; @@ -208,13 +209,16 @@ impl<'a> ExecuteWebhook<'a> { /// Using this will result in receiving the created message. /// /// [Discord Docs/Execute Webhook]: https://discord.com/developers/docs/resources/webhook#execute-webhook-querystring-params + #[allow(clippy::missing_const_for_fn)] pub fn wait(self) -> ExecuteWebhookAndWait<'a> { ExecuteWebhookAndWait::new(self) } - pub(super) fn request(&mut self, wait: bool) -> Result { + // `self` needs to be consumed and the client returned due to parameters + // being consumed in request construction. + pub(super) fn request(self, wait: bool) -> Result<(Request, &'a Client), Error> { let mut request = Request::builder(Route::ExecuteWebhook { - token: self.token.clone(), + token: self.token, wait: Some(wait), webhook_id: self.webhook_id.0, }); @@ -226,14 +230,15 @@ impl<'a> ExecuteWebhook<'a> { if !self.files.is_empty() || self.fields.payload_json.is_some() { let mut form = Form::new(); - for (index, (name, file)) in self.files.drain(..).enumerate() { - form.file(format!("{}", index).as_bytes(), name.as_bytes(), &file); + for (index, (name, file)) in self.files.iter().enumerate() { + form.file(format!("{}", index).as_bytes(), name.as_bytes(), file); } if let Some(payload_json) = &self.fields.payload_json { form.payload_json(payload_json); } else { let body = crate::json::to_vec(&self.fields).map_err(Error::json)?; + form.payload_json(&body); } @@ -242,16 +247,16 @@ impl<'a> ExecuteWebhook<'a> { request = request.json(&self.fields)?; } - Ok(request.build()) + Ok((request.build(), self.http)) } - fn start(&mut self) -> Result<(), Error> { - let request = self.request(false)?; - - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + match self.request(false) { + Ok((request, client)) => client.request(request), + Err(source) => ResponseFuture::error(source), + } } } - -poll_req!(ExecuteWebhook<'_>, EmptyBody); diff --git a/http/src/request/channel/webhook/execute_webhook_and_wait.rs b/http/src/request/channel/webhook/execute_webhook_and_wait.rs index d7ca2f324ae..0b3415c3b7a 100644 --- a/http/src/request/channel/webhook/execute_webhook_and_wait.rs +++ b/http/src/request/channel/webhook/execute_webhook_and_wait.rs @@ -1,5 +1,5 @@ use super::execute_webhook::ExecuteWebhook; -use crate::{error::Error, request::PendingResponse}; +use crate::response::ResponseFuture; use twilight_model::channel::Message; /// Execute a webhook, sending a message to its channel, and then wait for the @@ -20,6 +20,7 @@ use twilight_model::channel::Message; /// .execute_webhook(id, "webhook token") /// .content("Pinkie...") /// .wait() +/// .exec() /// .await? /// .model() /// .await?; @@ -32,21 +33,23 @@ use twilight_model::channel::Message; /// [`embeds`]: Self::embeds /// [`file`]: Self::file pub struct ExecuteWebhookAndWait<'a> { - fut: Option>, inner: ExecuteWebhook<'a>, } impl<'a> ExecuteWebhookAndWait<'a> { - pub(crate) fn new(inner: ExecuteWebhook<'a>) -> Self { - Self { fut: None, inner } + pub(crate) const fn new(inner: ExecuteWebhook<'a>) -> Self { + Self { inner } } - fn start(&mut self) -> Result<(), Error> { - let request = self.inner.request(true)?; - self.fut.replace(Box::pin(self.inner.http.request(request))); + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let (request, client) = match self.inner.request(false) { + Ok((request, client)) => (request, client), + Err(source) => return ResponseFuture::error(source), + }; - Ok(()) + client.request(request) } } - -poll_req!(ExecuteWebhookAndWait<'_>, Message); diff --git a/http/src/request/channel/webhook/get_channel_webhooks.rs b/http/src/request/channel/webhook/get_channel_webhooks.rs index 636a122eb33..2c3db5f8a7d 100644 --- a/http/src/request/channel/webhook/get_channel_webhooks.rs +++ b/http/src/request/channel/webhook/get_channel_webhooks.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::ListBody, + request::Request, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use twilight_model::{channel::Webhook, id::ChannelId}; @@ -10,28 +9,22 @@ use twilight_model::{channel::Webhook, id::ChannelId}; /// Get all the webhooks of a channel. pub struct GetChannelWebhooks<'a> { channel_id: ChannelId, - fut: Option>>, http: &'a Client, } impl<'a> GetChannelWebhooks<'a> { - pub(crate) fn new(http: &'a Client, channel_id: ChannelId) -> Self { - Self { - channel_id, - fut: None, - http, - } + pub(crate) const fn new(http: &'a Client, channel_id: ChannelId) -> Self { + Self { channel_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetChannelWebhooks { channel_id: self.channel_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetChannelWebhooks<'_>, ListBody); diff --git a/http/src/request/channel/webhook/get_webhook.rs b/http/src/request/channel/webhook/get_webhook.rs index 4136b84724e..208183e55c7 100644 --- a/http/src/request/channel/webhook/get_webhook.rs +++ b/http/src/request/channel/webhook/get_webhook.rs @@ -1,9 +1,4 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::{channel::Webhook, id::WebhookId}; #[derive(Default)] @@ -14,7 +9,6 @@ struct GetWebhookFields { /// Get a webhook by ID. pub struct GetWebhook<'a> { fields: GetWebhookFields, - fut: Option>, http: &'a Client, id: WebhookId, } @@ -23,7 +17,6 @@ impl<'a> GetWebhook<'a> { pub(crate) fn new(http: &'a Client, id: WebhookId) -> Self { Self { fields: GetWebhookFields::default(), - fut: None, http, id, } @@ -37,23 +30,23 @@ impl<'a> GetWebhook<'a> { self } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let use_webhook_token = self.fields.token.is_some(); + let mut request = Request::builder(Route::GetWebhook { - token: self.fields.token.clone(), + token: self.fields.token, webhook_id: self.id.0, }); // If a webhook token has been configured, then we don't need to use // the client's authorization token. - if self.fields.token.is_some() { + if use_webhook_token { request = request.use_authorization_token(false); } - self.fut - .replace(Box::pin(self.http.request(request.build()))); - - Ok(()) + self.http.request(request.build()) } } - -poll_req!(GetWebhook<'_>, Webhook); diff --git a/http/src/request/channel/webhook/get_webhook_message.rs b/http/src/request/channel/webhook/get_webhook_message.rs index fc25d263662..be8b44da910 100644 --- a/http/src/request/channel/webhook/get_webhook_message.rs +++ b/http/src/request/channel/webhook/get_webhook_message.rs @@ -1,9 +1,4 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::{ channel::Message, id::{MessageId, WebhookId}, @@ -14,7 +9,6 @@ use twilight_model::{ /// [`WebhookId`]: twilight_model::id::WebhookId /// [`MessageId`]: twilight_model::id::MessageId pub struct GetWebhookMessage<'a> { - fut: Option>, http: &'a Client, message_id: MessageId, token: String, @@ -29,7 +23,6 @@ impl<'a> GetWebhookMessage<'a> { message_id: MessageId, ) -> Self { Self { - fut: None, http, message_id, token: token.into(), @@ -37,19 +30,18 @@ impl<'a> GetWebhookMessage<'a> { } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::builder(Route::GetWebhookMessage { message_id: self.message_id.0, - token: self.token.clone(), + token: self.token, webhook_id: self.webhook_id.0, }) .use_authorization_token(false) .build(); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetWebhookMessage<'_>, Message); diff --git a/http/src/request/channel/webhook/update_webhook.rs b/http/src/request/channel/webhook/update_webhook.rs index 2a0a54dc6fb..a1b7937ae42 100644 --- a/http/src/request/channel/webhook/update_webhook.rs +++ b/http/src/request/channel/webhook/update_webhook.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, NullableField, PendingResponse, Request}, + request::{self, AuditLogReason, AuditLogReasonError, NullableField, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -23,7 +23,6 @@ struct UpdateWebhookFields { /// Update a webhook by ID. pub struct UpdateWebhook<'a> { fields: UpdateWebhookFields, - fut: Option>, http: &'a Client, webhook_id: WebhookId, reason: Option, @@ -34,7 +33,6 @@ impl<'a> UpdateWebhook<'a> { pub(crate) fn new(http: &'a Client, webhook_id: WebhookId) -> Self { Self { fields: UpdateWebhookFields::default(), - fut: None, http, webhook_id, reason: None, @@ -72,21 +70,30 @@ impl<'a> UpdateWebhook<'a> { self } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::UpdateWebhook { token: None, webhook_id: self.webhook_id.0, - }) - .json(&self.fields)?; + }); + + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; if let Some(reason) = self.reason.as_ref() { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -98,5 +105,3 @@ impl<'a> AuditLogReason for UpdateWebhook<'a> { Ok(self) } } - -poll_req!(UpdateWebhook<'_>, Webhook); diff --git a/http/src/request/channel/webhook/update_webhook_message.rs b/http/src/request/channel/webhook/update_webhook_message.rs index 450372619a3..7ba30e2fdca 100644 --- a/http/src/request/channel/webhook/update_webhook_message.rs +++ b/http/src/request/channel/webhook/update_webhook_message.rs @@ -3,11 +3,8 @@ use crate::{ client::Client, error::Error as HttpError, - request::{ - self, validate, AuditLogReason, AuditLogReasonError, Form, NullableField, PendingResponse, - Request, - }, - response::marker::EmptyBody, + request::{self, validate, AuditLogReason, AuditLogReasonError, Form, NullableField, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use serde::Serialize; @@ -148,6 +145,7 @@ struct UpdateWebhookMessageFields { /// // mentioned. /// .allowed_mentions(AllowedMentions::default()) /// .content(Some("test <@3>".to_owned()))? +/// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -156,7 +154,6 @@ struct UpdateWebhookMessageFields { pub struct UpdateWebhookMessage<'a> { fields: UpdateWebhookMessageFields, files: Vec<(String, Vec)>, - fut: Option>, http: &'a Client, message_id: MessageId, reason: Option, @@ -180,7 +177,6 @@ impl<'a> UpdateWebhookMessage<'a> { ..UpdateWebhookMessageFields::default() }, files: Vec::new(), - fut: None, http, message_id, reason: None, @@ -283,6 +279,7 @@ impl<'a> UpdateWebhookMessage<'a> { /// /// client.update_webhook_message(WebhookId(1), "token", MessageId(2)) /// .embeds(Some(vec![embed]))? + /// .exec() /// .await?; /// # Ok(()) } /// ``` @@ -367,10 +364,12 @@ impl<'a> UpdateWebhookMessage<'a> { self } - fn request(&mut self) -> Result { + // `self` needs to be consumed and the client returned due to parameters + // being consumed in request construction. + fn request(self) -> Result<(Request, &'a Client), HttpError> { let mut request = Request::builder(Route::UpdateWebhookMessage { message_id: self.message_id.0, - token: self.token.clone(), + token: self.token, webhook_id: self.webhook_id.0, }) .use_authorization_token(false); @@ -378,8 +377,8 @@ impl<'a> UpdateWebhookMessage<'a> { if !self.files.is_empty() || self.fields.payload_json.is_some() { let mut form = Form::new(); - for (index, (name, file)) in self.files.drain(..).enumerate() { - form.file(format!("{}", index).as_bytes(), name.as_bytes(), &file); + for (index, (name, file)) in self.files.iter().enumerate() { + form.file(format!("{}", index).as_bytes(), name.as_bytes(), file); } if let Some(payload_json) = &self.fields.payload_json { @@ -398,14 +397,17 @@ impl<'a> UpdateWebhookMessage<'a> { request = request.headers(request::audit_header(reason)?); } - Ok(request.build()) + Ok((request.build(), self.http)) } - fn start(&mut self) -> Result<(), HttpError> { - let request = self.request()?; - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + match self.request() { + Ok((request, client)) => client.request(request), + Err(source) => ResponseFuture::error(source), + } } } @@ -418,8 +420,6 @@ impl<'a> AuditLogReason for UpdateWebhookMessage<'a> { } } -poll_req!(UpdateWebhookMessage<'_>, EmptyBody); - #[cfg(test)] mod tests { use super::{UpdateWebhookMessage, UpdateWebhookMessageFields}; @@ -433,12 +433,12 @@ mod tests { #[test] fn test_request() { let client = Client::new("token"); - let mut builder = UpdateWebhookMessage::new(&client, WebhookId(1), "token", MessageId(2)) + let builder = UpdateWebhookMessage::new(&client, WebhookId(1), "token", MessageId(2)) .content(Some("test".to_owned())) .expect("'test' content couldn't be set") .reason("reason") .expect("'reason' is not a valid reason"); - let actual = builder.request().expect("failed to create request"); + let (actual, _) = builder.request().expect("failed to create request"); let body = UpdateWebhookMessageFields { allowed_mentions: None, diff --git a/http/src/request/channel/webhook/update_webhook_with_token.rs b/http/src/request/channel/webhook/update_webhook_with_token.rs index bcce303e5df..695dd039901 100644 --- a/http/src/request/channel/webhook/update_webhook_with_token.rs +++ b/http/src/request/channel/webhook/update_webhook_with_token.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{NullableField, PendingResponse, Request}, + request::{NullableField, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -18,7 +18,6 @@ struct UpdateWebhookWithTokenFields { /// Update a webhook, with a token, by ID. pub struct UpdateWebhookWithToken<'a> { fields: UpdateWebhookWithTokenFields, - fut: Option>, http: &'a Client, token: String, webhook_id: WebhookId, @@ -28,7 +27,6 @@ impl<'a> UpdateWebhookWithToken<'a> { pub(crate) fn new(http: &'a Client, webhook_id: WebhookId, token: impl Into) -> Self { Self { fields: UpdateWebhookWithTokenFields::default(), - fut: None, http, token: token.into(), webhook_id, @@ -59,19 +57,21 @@ impl<'a> UpdateWebhookWithToken<'a> { self } - fn start(&mut self) -> Result<(), Error> { - let request = Request::builder(Route::UpdateWebhook { - token: Some(self.token.clone()), + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let mut request = Request::builder(Route::UpdateWebhook { + token: Some(self.token), webhook_id: self.webhook_id.0, }) - .json(&self.fields)? - .use_authorization_token(false) - .build(); + .use_authorization_token(false); - self.fut.replace(Box::pin(self.http.request(request))); + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; - Ok(()) + self.http.request(request.build()) } } - -poll_req!(UpdateWebhookWithToken<'_>, Webhook); diff --git a/http/src/request/get_gateway.rs b/http/src/request/get_gateway.rs index 3dc00045e04..9d552eb80f2 100644 --- a/http/src/request/get_gateway.rs +++ b/http/src/request/get_gateway.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{GetGatewayAuthed, PendingResponse, Request}, + request::{GetGatewayAuthed, Request}, + response::ResponseFuture, routing::Route, }; use twilight_model::gateway::connection_info::ConnectionInfo; @@ -20,7 +20,7 @@ use twilight_model::gateway::connection_info::ConnectionInfo; /// # async fn main() -> Result<(), Box> { /// let client = Client::new("my token"); /// -/// let info = client.gateway().await?.model().await?; +/// let info = client.gateway().exec().await?.model().await?; /// # Ok(()) } /// ``` /// @@ -34,37 +34,35 @@ use twilight_model::gateway::connection_info::ConnectionInfo; /// # async fn main() -> Result<(), Box> { /// let client = Client::new("my token"); /// -/// let info = client.gateway().authed().await?.model().await?; +/// let info = client.gateway().authed().exec().await?.model().await?; /// /// println!("URL: {}", info.url); /// println!("Recommended shards to use: {}", info.shards); /// # Ok(()) } /// ``` pub struct GetGateway<'a> { - fut: Option>, http: &'a Client, } impl<'a> GetGateway<'a> { - pub(crate) fn new(http: &'a Client) -> Self { - Self { fut: None, http } + pub(crate) const fn new(http: &'a Client) -> Self { + Self { http } } /// Call to authenticate this request. /// /// Returns additional information: the recommended number of shards to use, and information on /// the current session start limit. - pub fn authed(self) -> GetGatewayAuthed<'a> { + pub const fn authed(self) -> GetGatewayAuthed<'a> { GetGatewayAuthed::new(self.http) } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetGateway); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetGateway<'_>, ConnectionInfo); diff --git a/http/src/request/get_gateway_authed.rs b/http/src/request/get_gateway_authed.rs index 69b2c582f74..45466264f40 100644 --- a/http/src/request/get_gateway_authed.rs +++ b/http/src/request/get_gateway_authed.rs @@ -1,9 +1,4 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::gateway::connection_info::BotConnectionInfo; /// Get information about the gateway, authenticated as a bot user. @@ -11,22 +6,20 @@ use twilight_model::gateway::connection_info::BotConnectionInfo; /// Returns additional information: the recommended number of shards to use, and information on /// the current session start limit. pub struct GetGatewayAuthed<'a> { - fut: Option>, http: &'a Client, } impl<'a> GetGatewayAuthed<'a> { - pub(crate) fn new(http: &'a Client) -> Self { - Self { fut: None, http } + pub(crate) const fn new(http: &'a Client) -> Self { + Self { http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetGatewayBot); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetGatewayAuthed<'_>, BotConnectionInfo); diff --git a/http/src/request/get_user_application.rs b/http/src/request/get_user_application.rs index 1aef7da58b6..305c61e8a1c 100644 --- a/http/src/request/get_user_application.rs +++ b/http/src/request/get_user_application.rs @@ -1,28 +1,21 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::oauth::CurrentApplicationInfo; pub struct GetUserApplicationInfo<'a> { - fut: Option>, http: &'a Client, } impl<'a> GetUserApplicationInfo<'a> { - pub(crate) fn new(http: &'a Client) -> Self { - Self { fut: None, http } + pub(crate) const fn new(http: &'a Client) -> Self { + Self { http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetCurrentUserApplicationInfo); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetUserApplicationInfo<'_>, CurrentApplicationInfo); diff --git a/http/src/request/get_voice_regions.rs b/http/src/request/get_voice_regions.rs index 113dca1ba0d..944edd3785f 100644 --- a/http/src/request/get_voice_regions.rs +++ b/http/src/request/get_voice_regions.rs @@ -1,30 +1,27 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::ListBody, + request::Request, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use twilight_model::voice::VoiceRegion; /// Get a list of voice regions that can be used when creating a guild. pub struct GetVoiceRegions<'a> { - fut: Option>>, http: &'a Client, } impl<'a> GetVoiceRegions<'a> { - pub(crate) fn new(http: &'a Client) -> Self { - Self { fut: None, http } + pub(crate) const fn new(http: &'a Client) -> Self { + Self { http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetVoiceRegions); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetVoiceRegions<'_>, ListBody); diff --git a/http/src/request/guild/ban/create_ban.rs b/http/src/request/guild/ban/create_ban.rs index a4a5ed809e9..f53141cf42f 100644 --- a/http/src/request/guild/ban/create_ban.rs +++ b/http/src/request/guild/ban/create_ban.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error as HttpError, - request::{validate, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{validate, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use std::{ @@ -88,12 +87,12 @@ struct CreateBanFields { /// client.create_ban(guild_id, user_id) /// .delete_message_days(1)? /// .reason("memes")? +/// .exec() /// .await?; /// # Ok(()) } /// ``` pub struct CreateBan<'a> { fields: CreateBanFields, - fut: Option>, guild_id: GuildId, http: &'a Client, user_id: UserId, @@ -103,7 +102,6 @@ impl<'a> CreateBan<'a> { pub(crate) fn new(http: &'a Client, guild_id: GuildId, user_id: UserId) -> Self { Self { fields: CreateBanFields::default(), - fut: None, guild_id, http, user_id, @@ -130,17 +128,18 @@ impl<'a> CreateBan<'a> { Ok(self) } - fn start(&mut self) -> Result<(), HttpError> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::CreateBan { delete_message_days: self.fields.delete_message_days, guild_id: self.guild_id.0, - reason: self.fields.reason.clone(), + reason: self.fields.reason, user_id: self.user_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } @@ -153,5 +152,3 @@ impl<'a> AuditLogReason for CreateBan<'a> { Ok(self) } } - -poll_req!(CreateBan<'_>, EmptyBody); diff --git a/http/src/request/guild/ban/delete_ban.rs b/http/src/request/guild/ban/delete_ban.rs index 74c436e1165..f2f1e72dfa4 100644 --- a/http/src/request/guild/ban/delete_ban.rs +++ b/http/src/request/guild/ban/delete_ban.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{GuildId, UserId}; @@ -24,11 +23,10 @@ use twilight_model::id::{GuildId, UserId}; /// let guild_id = GuildId(100); /// let user_id = UserId(200); /// -/// client.delete_ban(guild_id, user_id).await?; +/// client.delete_ban(guild_id, user_id).exec().await?; /// # Ok(()) } /// ``` pub struct DeleteBan<'a> { - fut: Option>, guild_id: GuildId, http: &'a Client, user_id: UserId, @@ -36,9 +34,8 @@ pub struct DeleteBan<'a> { } impl<'a> DeleteBan<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId, user_id: UserId) -> Self { + pub(crate) const fn new(http: &'a Client, guild_id: GuildId, user_id: UserId) -> Self { Self { - fut: None, guild_id, http, user_id, @@ -46,20 +43,25 @@ impl<'a> DeleteBan<'a> { } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::DeleteBan { guild_id: self.guild_id.0, user_id: self.user_id.0, }); if let Some(reason) = self.reason.as_ref() { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -71,5 +73,3 @@ impl<'a> AuditLogReason for DeleteBan<'a> { Ok(self) } } - -poll_req!(DeleteBan<'_>, EmptyBody); diff --git a/http/src/request/guild/ban/get_ban.rs b/http/src/request/guild/ban/get_ban.rs index 45a372a4509..d68fcb1df3d 100644 --- a/http/src/request/guild/ban/get_ban.rs +++ b/http/src/request/guild/ban/get_ban.rs @@ -1,9 +1,4 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::{ guild::Ban, id::{GuildId, UserId}, @@ -13,32 +8,29 @@ use twilight_model::{ /// /// Includes the user banned and the reason. pub struct GetBan<'a> { - fut: Option>, guild_id: GuildId, http: &'a Client, user_id: UserId, } impl<'a> GetBan<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId, user_id: UserId) -> Self { + pub(crate) const fn new(http: &'a Client, guild_id: GuildId, user_id: UserId) -> Self { Self { - fut: None, guild_id, http, user_id, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetBan { guild_id: self.guild_id.0, user_id: self.user_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetBan<'_>, Ban); diff --git a/http/src/request/guild/ban/get_bans.rs b/http/src/request/guild/ban/get_bans.rs index 400d684e282..72f179f2cdd 100644 --- a/http/src/request/guild/ban/get_bans.rs +++ b/http/src/request/guild/ban/get_bans.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::ListBody, + request::Request, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use twilight_model::{guild::Ban, id::GuildId}; @@ -23,33 +22,27 @@ use twilight_model::{guild::Ban, id::GuildId}; /// /// let guild_id = GuildId(1); /// -/// let bans = client.bans(guild_id).await?; +/// let bans = client.bans(guild_id).exec().await?; /// # Ok(()) } /// ``` pub struct GetBans<'a> { - fut: Option>>, guild_id: GuildId, http: &'a Client, } impl<'a> GetBans<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { - Self { - fut: None, - guild_id, - http, - } + pub(crate) const fn new(http: &'a Client, guild_id: GuildId) -> Self { + Self { guild_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetBans { guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetBans<'_>, ListBody); diff --git a/http/src/request/guild/create_guild/mod.rs b/http/src/request/guild/create_guild/mod.rs index 9cead3a54be..b34e2a3a9f8 100644 --- a/http/src/request/guild/create_guild/mod.rs +++ b/http/src/request/guild/create_guild/mod.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error as HttpError, - request::{validate, PendingResponse, Request}, + request::{validate, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -238,7 +238,6 @@ impl From for VoiceFields { /// This endpoint can only be used by bots in less than 10 guilds. pub struct CreateGuild<'a> { fields: CreateGuildFields, - fut: Option>, http: &'a Client, } @@ -268,7 +267,6 @@ impl<'a> CreateGuild<'a> { system_channel_flags: None, verification_level: None, }, - fut: None, http, }) } @@ -336,7 +334,10 @@ impl<'a> CreateGuild<'a> { /// .add_category_builder(category) /// .build(); /// - /// let guild = client.create_guild("guild name")?.channels(channels)?.await?; + /// let guild = client.create_guild("guild name")? + /// .channels(channels)? + /// .exec() + /// .await?; /// # Ok(()) } /// ``` /// @@ -448,7 +449,7 @@ impl<'a> CreateGuild<'a> { /// # let client = Client::new("my token"); /// /// let roles = vec![RoleFieldsBuilder::new("role 1").color(0x543923)?.build()]; - /// client.create_guild("guild name")?.roles(roles)?.await?; + /// client.create_guild("guild name")?.roles(roles)?.exec().await?; /// # Ok(()) } /// ``` /// @@ -475,15 +476,17 @@ impl<'a> CreateGuild<'a> { Ok(self) } - fn start(&mut self) -> Result<(), HttpError> { - let request = Request::builder(Route::CreateGuild) - .json(&self.fields)? - .build(); + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let mut request = Request::builder(Route::CreateGuild); - self.fut.replace(Box::pin(self.http.request(request))); + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; - Ok(()) + self.http.request(request.build()) } } - -poll_req!(CreateGuild<'_>, PartialGuild); diff --git a/http/src/request/guild/create_guild_channel.rs b/http/src/request/guild/create_guild_channel.rs index b683f479070..bd3d22066b7 100644 --- a/http/src/request/guild/create_guild_channel.rs +++ b/http/src/request/guild/create_guild_channel.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error as HttpError, - request::{self, validate, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, + request::{self, validate, AuditLogReason, AuditLogReasonError, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -113,7 +113,6 @@ struct CreateGuildChannelFields { /// UTF-16 characters and the maximum is 100 UTF-16 characters. pub struct CreateGuildChannel<'a> { fields: CreateGuildChannelFields, - fut: Option>, guild_id: GuildId, http: &'a Client, reason: Option, @@ -152,7 +151,6 @@ impl<'a> CreateGuildChannel<'a> { topic: None, user_limit: None, }, - fut: None, guild_id, http, reason: None, @@ -277,20 +275,29 @@ impl<'a> CreateGuildChannel<'a> { self } - fn start(&mut self) -> Result<(), HttpError> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::CreateChannel { guild_id: self.guild_id.0, - }) - .json(&self.fields)?; + }); + + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; if let Some(reason) = self.reason.as_ref() { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -302,5 +309,3 @@ impl<'a> AuditLogReason for CreateGuildChannel<'a> { Ok(self) } } - -poll_req!(CreateGuildChannel<'_>, GuildChannel); diff --git a/http/src/request/guild/create_guild_prune.rs b/http/src/request/guild/create_guild_prune.rs index d93748fe24c..20ca3d0838b 100644 --- a/http/src/request/guild/create_guild_prune.rs +++ b/http/src/request/guild/create_guild_prune.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error as HttpError, - request::{self, validate, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, + request::{self, validate, AuditLogReason, AuditLogReasonError, Request}, + response::ResponseFuture, routing::Route, }; use std::{ @@ -80,7 +80,6 @@ struct CreateGuildPruneFields { pub struct CreateGuildPrune<'a> { fields: CreateGuildPruneFields, guild_id: GuildId, - fut: Option>, http: &'a Client, reason: Option, } @@ -89,7 +88,6 @@ impl<'a> CreateGuildPrune<'a> { pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { Self { fields: CreateGuildPruneFields::default(), - fut: None, guild_id, http, reason: None, @@ -132,22 +130,27 @@ impl<'a> CreateGuildPrune<'a> { Ok(self) } - fn start(&mut self) -> Result<(), HttpError> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::CreateGuildPrune { compute_prune_count: self.fields.compute_prune_count, days: self.fields.days, guild_id: self.guild_id.0, - include_roles: self.fields.include_roles.clone(), + include_roles: self.fields.include_roles, }); if let Some(reason) = self.reason.as_ref() { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -159,5 +162,3 @@ impl<'a> AuditLogReason for CreateGuildPrune<'a> { Ok(self) } } - -poll_req!(CreateGuildPrune<'_>, GuildPrune); diff --git a/http/src/request/guild/delete_guild.rs b/http/src/request/guild/delete_guild.rs index 62c7051a366..b3bc285d36b 100644 --- a/http/src/request/guild/delete_guild.rs +++ b/http/src/request/guild/delete_guild.rs @@ -1,37 +1,30 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::Request, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::GuildId; /// Delete a guild permanently. The user must be the owner. pub struct DeleteGuild<'a> { - fut: Option>, guild_id: GuildId, http: &'a Client, } impl<'a> DeleteGuild<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { - Self { - fut: None, - guild_id, - http, - } + pub(crate) const fn new(http: &'a Client, guild_id: GuildId) -> Self { + Self { guild_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::DeleteGuild { guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(DeleteGuild<'_>, EmptyBody); diff --git a/http/src/request/guild/emoji/create_emoji.rs b/http/src/request/guild/emoji/create_emoji.rs index e726970a808..bacda1778d3 100644 --- a/http/src/request/guild/emoji/create_emoji.rs +++ b/http/src/request/guild/emoji/create_emoji.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -26,7 +26,6 @@ struct CreateEmojiFields { /// /// [the discord docs]: https://discord.com/developers/docs/reference#image-data pub struct CreateEmoji<'a> { - fut: Option>, fields: CreateEmojiFields, guild_id: GuildId, http: &'a Client, @@ -46,7 +45,6 @@ impl<'a> CreateEmoji<'a> { name: name.into(), roles: None, }, - fut: None, guild_id, http, reason: None, @@ -64,20 +62,29 @@ impl<'a> CreateEmoji<'a> { self } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::CreateEmoji { guild_id: self.guild_id.0, - }) - .json(&self.fields)?; + }); + + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; if let Some(reason) = self.reason.as_ref() { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -89,5 +96,3 @@ impl<'a> AuditLogReason for CreateEmoji<'a> { Ok(self) } } - -poll_req!(CreateEmoji<'_>, Emoji); diff --git a/http/src/request/guild/emoji/delete_emoji.rs b/http/src/request/guild/emoji/delete_emoji.rs index 647efb6ed39..caebd6bdf79 100644 --- a/http/src/request/guild/emoji/delete_emoji.rs +++ b/http/src/request/guild/emoji/delete_emoji.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{EmojiId, GuildId}; @@ -10,37 +9,40 @@ use twilight_model::id::{EmojiId, GuildId}; /// Delete an emoji in a guild, by id. pub struct DeleteEmoji<'a> { emoji_id: EmojiId, - fut: Option>, guild_id: GuildId, http: &'a Client, reason: Option, } impl<'a> DeleteEmoji<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId, emoji_id: EmojiId) -> Self { + pub(crate) const fn new(http: &'a Client, guild_id: GuildId, emoji_id: EmojiId) -> Self { Self { emoji_id, - fut: None, guild_id, http, reason: None, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::DeleteEmoji { emoji_id: self.emoji_id.0, guild_id: self.guild_id.0, }); if let Some(reason) = self.reason.as_ref() { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -52,5 +54,3 @@ impl<'a> AuditLogReason for DeleteEmoji<'a> { Ok(self) } } - -poll_req!(DeleteEmoji<'_>, EmptyBody); diff --git a/http/src/request/guild/emoji/get_emoji.rs b/http/src/request/guild/emoji/get_emoji.rs index d33b90f0725..91ccca74ffb 100644 --- a/http/src/request/guild/emoji/get_emoji.rs +++ b/http/src/request/guild/emoji/get_emoji.rs @@ -1,9 +1,4 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::{ guild::Emoji, id::{EmojiId, GuildId}, @@ -26,36 +21,33 @@ use twilight_model::{ /// let guild_id = GuildId(50); /// let emoji_id = EmojiId(100); /// -/// client.emoji(guild_id, emoji_id).await?; +/// client.emoji(guild_id, emoji_id).exec().await?; /// # Ok(()) } /// ``` pub struct GetEmoji<'a> { emoji_id: EmojiId, - fut: Option>, guild_id: GuildId, http: &'a Client, } impl<'a> GetEmoji<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId, emoji_id: EmojiId) -> Self { + pub(crate) const fn new(http: &'a Client, guild_id: GuildId, emoji_id: EmojiId) -> Self { Self { emoji_id, - fut: None, guild_id, http, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetEmoji { emoji_id: self.emoji_id.0, guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetEmoji<'_>, Emoji); diff --git a/http/src/request/guild/emoji/get_emojis.rs b/http/src/request/guild/emoji/get_emojis.rs index e755475b1bd..f75384fa6e4 100644 --- a/http/src/request/guild/emoji/get_emojis.rs +++ b/http/src/request/guild/emoji/get_emojis.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::ListBody, + request::Request, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use twilight_model::{guild::Emoji, id::GuildId}; @@ -23,33 +22,27 @@ use twilight_model::{guild::Emoji, id::GuildId}; /// /// let guild_id = GuildId(100); /// -/// client.emojis(guild_id).await?; +/// client.emojis(guild_id).exec().await?; /// # Ok(()) } /// ``` pub struct GetEmojis<'a> { - fut: Option>>, guild_id: GuildId, http: &'a Client, } impl<'a> GetEmojis<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { - Self { - fut: None, - guild_id, - http, - } + pub(crate) const fn new(http: &'a Client, guild_id: GuildId) -> Self { + Self { guild_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetEmojis { guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetEmojis<'_>, ListBody); diff --git a/http/src/request/guild/emoji/update_emoji.rs b/http/src/request/guild/emoji/update_emoji.rs index d7088ffb18b..de09c87cf8a 100644 --- a/http/src/request/guild/emoji/update_emoji.rs +++ b/http/src/request/guild/emoji/update_emoji.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -22,7 +22,6 @@ struct UpdateEmojiFields { pub struct UpdateEmoji<'a> { emoji_id: EmojiId, fields: UpdateEmojiFields, - fut: Option>, guild_id: GuildId, http: &'a Client, reason: Option, @@ -33,7 +32,6 @@ impl<'a> UpdateEmoji<'a> { Self { fields: UpdateEmojiFields::default(), emoji_id, - fut: None, guild_id, http, reason: None, @@ -54,21 +52,30 @@ impl<'a> UpdateEmoji<'a> { self } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::UpdateEmoji { emoji_id: self.emoji_id.0, guild_id: self.guild_id.0, - }) - .json(&self.fields)?; + }); + + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; if let Some(reason) = self.reason.as_ref() { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -80,5 +87,3 @@ impl<'a> AuditLogReason for UpdateEmoji<'a> { Ok(self) } } - -poll_req!(UpdateEmoji<'_>, Emoji); diff --git a/http/src/request/guild/get_audit_log.rs b/http/src/request/guild/get_audit_log.rs index fb7d58d7812..3038de480b2 100644 --- a/http/src/request/guild/get_audit_log.rs +++ b/http/src/request/guild/get_audit_log.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error as HttpError, - request::{validate, PendingResponse, Request}, + request::{validate, Request}, + response::ResponseFuture, routing::Route, }; use std::{ @@ -85,12 +85,12 @@ struct GetAuditLogFields { /// let audit_log = client /// // not done /// .audit_log(guild_id) +/// .exec() /// .await?; /// # Ok(()) } /// ``` pub struct GetAuditLog<'a> { fields: GetAuditLogFields, - fut: Option>, guild_id: GuildId, http: &'a Client, } @@ -99,7 +99,6 @@ impl<'a> GetAuditLog<'a> { pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { Self { fields: GetAuditLogFields::default(), - fut: None, guild_id, http, } @@ -148,7 +147,10 @@ impl<'a> GetAuditLog<'a> { self } - fn start(&mut self) -> Result<(), HttpError> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetAuditLogs { action_type: self.fields.action_type.map(|x| x as u64), before: self.fields.before, @@ -157,10 +159,6 @@ impl<'a> GetAuditLog<'a> { user_id: self.fields.user_id.map(|x| x.0), }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetAuditLog<'_>, AuditLog); diff --git a/http/src/request/guild/get_guild.rs b/http/src/request/guild/get_guild.rs index 6ce24dcf7f1..3e69c6765fc 100644 --- a/http/src/request/guild/get_guild.rs +++ b/http/src/request/guild/get_guild.rs @@ -1,9 +1,4 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::{guild::Guild, id::GuildId}; #[derive(Default)] @@ -14,7 +9,6 @@ struct GetGuildFields { /// Get information about a guild. pub struct GetGuild<'a> { fields: GetGuildFields, - fut: Option>, guild_id: GuildId, http: &'a Client, } @@ -23,7 +17,6 @@ impl<'a> GetGuild<'a> { pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { Self { fields: GetGuildFields::default(), - fut: None, guild_id, http, } @@ -37,16 +30,15 @@ impl<'a> GetGuild<'a> { self } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetGuild { guild_id: self.guild_id.0, with_counts: self.fields.with_counts, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetGuild<'_>, Guild); diff --git a/http/src/request/guild/get_guild_channels.rs b/http/src/request/guild/get_guild_channels.rs index 289a4d51d23..42e2db76891 100644 --- a/http/src/request/guild/get_guild_channels.rs +++ b/http/src/request/guild/get_guild_channels.rs @@ -1,37 +1,30 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::ListBody, + request::Request, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use twilight_model::{channel::GuildChannel, id::GuildId}; /// Get the channels in a guild. pub struct GetGuildChannels<'a> { - fut: Option>>, guild_id: GuildId, http: &'a Client, } impl<'a> GetGuildChannels<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { - Self { - fut: None, - guild_id, - http, - } + pub(crate) const fn new(http: &'a Client, guild_id: GuildId) -> Self { + Self { guild_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetChannels { guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetGuildChannels<'_>, ListBody); diff --git a/http/src/request/guild/get_guild_invites.rs b/http/src/request/guild/get_guild_invites.rs index 1006db0e1a4..9db4899d238 100644 --- a/http/src/request/guild/get_guild_invites.rs +++ b/http/src/request/guild/get_guild_invites.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::ListBody, + request::Request, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use twilight_model::{id::GuildId, invite::Invite}; @@ -13,29 +12,23 @@ use twilight_model::{id::GuildId, invite::Invite}; /// /// [`MANAGE_GUILD`]: twilight_model::guild::Permissions::MANAGE_GUILD pub struct GetGuildInvites<'a> { - fut: Option>>, guild_id: GuildId, http: &'a Client, } impl<'a> GetGuildInvites<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { - Self { - fut: None, - guild_id, - http, - } + pub(crate) const fn new(http: &'a Client, guild_id: GuildId) -> Self { + Self { guild_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetGuildInvites { guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetGuildInvites<'_>, ListBody); diff --git a/http/src/request/guild/get_guild_preview.rs b/http/src/request/guild/get_guild_preview.rs index 3f226a93a5b..55ca3f07f33 100644 --- a/http/src/request/guild/get_guild_preview.rs +++ b/http/src/request/guild/get_guild_preview.rs @@ -1,38 +1,27 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::{guild::GuildPreview, id::GuildId}; /// For public guilds, get the guild preview. /// /// This works even if the user is not in the guild. pub struct GetGuildPreview<'a> { - fut: Option>, guild_id: GuildId, http: &'a Client, } impl<'a> GetGuildPreview<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { - Self { - fut: None, - guild_id, - http, - } + pub(crate) const fn new(http: &'a Client, guild_id: GuildId) -> Self { + Self { guild_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetGuildPreview { guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetGuildPreview<'_>, GuildPreview); diff --git a/http/src/request/guild/get_guild_prune_count.rs b/http/src/request/guild/get_guild_prune_count.rs index 8f762edcc53..d9efa21e6f2 100644 --- a/http/src/request/guild/get_guild_prune_count.rs +++ b/http/src/request/guild/get_guild_prune_count.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error as HttpError, - request::{validate, PendingResponse, Request}, + request::{validate, Request}, + response::ResponseFuture, routing::Route, }; use std::{ @@ -74,7 +74,6 @@ struct GetGuildPruneCountFields { /// Get the counts of guild members to be pruned. pub struct GetGuildPruneCount<'a> { fields: GetGuildPruneCountFields, - fut: Option>, guild_id: GuildId, http: &'a Client, } @@ -83,7 +82,6 @@ impl<'a> GetGuildPruneCount<'a> { pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { Self { fields: GetGuildPruneCountFields::default(), - fut: None, guild_id, http, } @@ -119,21 +117,20 @@ impl<'a> GetGuildPruneCount<'a> { self } - fn start(&mut self) -> Result<(), HttpError> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetGuildPruneCount { days: self.fields.days, guild_id: self.guild_id.0, - include_roles: self.fields.include_roles.clone(), + include_roles: self.fields.include_roles, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } -poll_req!(GetGuildPruneCount<'_>, GuildPrune); - #[cfg(test)] mod test { use super::GetGuildPruneCount; diff --git a/http/src/request/guild/get_guild_vanity_url.rs b/http/src/request/guild/get_guild_vanity_url.rs index f54af4bf940..39af44d7a8d 100644 --- a/http/src/request/guild/get_guild_vanity_url.rs +++ b/http/src/request/guild/get_guild_vanity_url.rs @@ -1,36 +1,25 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::{guild::VanityUrl, id::GuildId}; /// Get a guild's vanity url, if there is one. pub struct GetGuildVanityUrl<'a> { - fut: Option>, guild_id: GuildId, http: &'a Client, } impl<'a> GetGuildVanityUrl<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { - Self { - fut: None, - guild_id, - http, - } + pub(crate) const fn new(http: &'a Client, guild_id: GuildId) -> Self { + Self { guild_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetGuildVanityUrl { guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetGuildVanityUrl<'_>, VanityUrl); diff --git a/http/src/request/guild/get_guild_voice_regions.rs b/http/src/request/guild/get_guild_voice_regions.rs index 1813bcd144d..fc724296be9 100644 --- a/http/src/request/guild/get_guild_voice_regions.rs +++ b/http/src/request/guild/get_guild_voice_regions.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::ListBody, + request::Request, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use twilight_model::{id::GuildId, voice::VoiceRegion}; @@ -11,29 +10,23 @@ use twilight_model::{id::GuildId, voice::VoiceRegion}; /// /// Can return VIP servers if the guild is VIP-enabled. pub struct GetGuildVoiceRegions<'a> { - fut: Option>>, guild_id: GuildId, http: &'a Client, } impl<'a> GetGuildVoiceRegions<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { - Self { - fut: None, - guild_id, - http, - } + pub(crate) const fn new(http: &'a Client, guild_id: GuildId) -> Self { + Self { guild_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetGuildVoiceRegions { guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetGuildVoiceRegions<'_>, ListBody); diff --git a/http/src/request/guild/get_guild_webhooks.rs b/http/src/request/guild/get_guild_webhooks.rs index 595e9078bb6..eafcd50c1a5 100644 --- a/http/src/request/guild/get_guild_webhooks.rs +++ b/http/src/request/guild/get_guild_webhooks.rs @@ -1,37 +1,30 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::ListBody, + request::Request, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use twilight_model::{channel::Webhook, id::GuildId}; /// Get the webhooks of a guild. pub struct GetGuildWebhooks<'a> { - fut: Option>>, guild_id: GuildId, http: &'a Client, } impl<'a> GetGuildWebhooks<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { - Self { - fut: None, - guild_id, - http, - } + pub(crate) const fn new(http: &'a Client, guild_id: GuildId) -> Self { + Self { guild_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetGuildWebhooks { guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetGuildWebhooks<'_>, ListBody); diff --git a/http/src/request/guild/get_guild_welcome_screen.rs b/http/src/request/guild/get_guild_welcome_screen.rs index 5badf5d2580..89119b61f37 100644 --- a/http/src/request/guild/get_guild_welcome_screen.rs +++ b/http/src/request/guild/get_guild_welcome_screen.rs @@ -1,36 +1,25 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::{id::GuildId, invite::WelcomeScreen}; /// Get the guild's welcome screen. pub struct GetGuildWelcomeScreen<'a> { - fut: Option>, guild_id: GuildId, http: &'a Client, } impl<'a> GetGuildWelcomeScreen<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { - Self { - fut: None, - guild_id, - http, - } + pub(crate) const fn new(http: &'a Client, guild_id: GuildId) -> Self { + Self { guild_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetGuildWelcomeScreen { guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetGuildWelcomeScreen<'_>, WelcomeScreen); diff --git a/http/src/request/guild/get_guild_widget.rs b/http/src/request/guild/get_guild_widget.rs index 70c8a3743c5..1af68665095 100644 --- a/http/src/request/guild/get_guild_widget.rs +++ b/http/src/request/guild/get_guild_widget.rs @@ -1,9 +1,4 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use twilight_model::{guild::GuildWidget, id::GuildId}; /// Get the guild widget. @@ -12,29 +7,23 @@ use twilight_model::{guild::GuildWidget, id::GuildId}; /// /// [the discord docs]: https://discord.com/developers/docs/resources/guild#get-guild-widget pub struct GetGuildWidget<'a> { - fut: Option>, guild_id: GuildId, http: &'a Client, } impl<'a> GetGuildWidget<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { - Self { - fut: None, - guild_id, - http, - } + pub(crate) const fn new(http: &'a Client, guild_id: GuildId) -> Self { + Self { guild_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetGuildWidget { guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetGuildWidget<'_>, GuildWidget); diff --git a/http/src/request/guild/integration/delete_guild_integration.rs b/http/src/request/guild/integration/delete_guild_integration.rs index b288c5a1e5a..5b0e6cc1ce9 100644 --- a/http/src/request/guild/integration/delete_guild_integration.rs +++ b/http/src/request/guild/integration/delete_guild_integration.rs @@ -1,15 +1,13 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{GuildId, IntegrationId}; /// Delete an integration for a guild, by the integration's id. pub struct DeleteGuildIntegration<'a> { - fut: Option>, guild_id: GuildId, http: &'a Client, integration_id: IntegrationId, @@ -17,9 +15,12 @@ pub struct DeleteGuildIntegration<'a> { } impl<'a> DeleteGuildIntegration<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId, integration_id: IntegrationId) -> Self { + pub(crate) const fn new( + http: &'a Client, + guild_id: GuildId, + integration_id: IntegrationId, + ) -> Self { Self { - fut: None, guild_id, http, integration_id, @@ -27,20 +28,25 @@ impl<'a> DeleteGuildIntegration<'a> { } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::DeleteGuildIntegration { guild_id: self.guild_id.0, integration_id: self.integration_id.0, }); if let Some(reason) = self.reason.as_ref() { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -52,5 +58,3 @@ impl<'a> AuditLogReason for DeleteGuildIntegration<'a> { Ok(self) } } - -poll_req!(DeleteGuildIntegration<'_>, EmptyBody); diff --git a/http/src/request/guild/integration/get_guild_integrations.rs b/http/src/request/guild/integration/get_guild_integrations.rs index c212069589a..32167f5341a 100644 --- a/http/src/request/guild/integration/get_guild_integrations.rs +++ b/http/src/request/guild/integration/get_guild_integrations.rs @@ -1,37 +1,30 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::ListBody, + request::Request, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use twilight_model::{guild::GuildIntegration, id::GuildId}; /// Get the guild's integrations. pub struct GetGuildIntegrations<'a> { - fut: Option>>, guild_id: GuildId, http: &'a Client, } impl<'a> GetGuildIntegrations<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { - Self { - fut: None, - guild_id, - http, - } + pub(crate) const fn new(http: &'a Client, guild_id: GuildId) -> Self { + Self { guild_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetGuildIntegrations { guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetGuildIntegrations<'_>, ListBody); diff --git a/http/src/request/guild/member/add_guild_member.rs b/http/src/request/guild/member/add_guild_member.rs index c910bbe7373..cf310e168ca 100644 --- a/http/src/request/guild/member/add_guild_member.rs +++ b/http/src/request/guild/member/add_guild_member.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error as HttpError, - request::{validate, PendingResponse, Request}, + request::{validate, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -81,7 +81,6 @@ struct AddGuildMemberFields { pub struct AddGuildMember<'a> { fields: AddGuildMemberFields, - fut: Option>, guild_id: GuildId, http: &'a Client, user_id: UserId, @@ -103,7 +102,12 @@ impl<'a> AddGuildMember<'a> { Self::_new(http, guild_id, user_id, access_token.into()) } - fn _new(http: &'a Client, guild_id: GuildId, user_id: UserId, access_token: String) -> Self { + const fn _new( + http: &'a Client, + guild_id: GuildId, + user_id: UserId, + access_token: String, + ) -> Self { Self { fields: AddGuildMemberFields { access_token, @@ -112,7 +116,6 @@ impl<'a> AddGuildMember<'a> { nick: None, roles: None, }, - fut: None, guild_id, http, user_id, @@ -166,18 +169,20 @@ impl<'a> AddGuildMember<'a> { self } - fn start(&mut self) -> Result<(), HttpError> { - let request = Request::builder(Route::AddGuildMember { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let mut request = Request::builder(Route::AddGuildMember { guild_id: self.guild_id.0, user_id: self.user_id.0, - }) - .json(&self.fields)? - .build(); + }); - self.fut.replace(Box::pin(self.http.request(request))); + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; - Ok(()) + self.http.request(request.build()) } } - -poll_req!(AddGuildMember<'_>, PartialMember); diff --git a/http/src/request/guild/member/add_role_to_member.rs b/http/src/request/guild/member/add_role_to_member.rs index 3783f7107b7..d010c7caece 100644 --- a/http/src/request/guild/member/add_role_to_member.rs +++ b/http/src/request/guild/member/add_role_to_member.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{GuildId, RoleId, UserId}; @@ -25,11 +24,13 @@ use twilight_model::id::{GuildId, RoleId, UserId}; /// let role_id = RoleId(2); /// let user_id = UserId(3); /// -/// client.add_guild_member_role(guild_id, user_id, role_id).reason("test")?.await?; +/// client.add_guild_member_role(guild_id, user_id, role_id) +/// .reason("test")? +/// .exec() +/// .await?; /// # Ok(()) } /// ``` pub struct AddRoleToMember<'a> { - fut: Option>, guild_id: GuildId, http: &'a Client, role_id: RoleId, @@ -45,7 +46,6 @@ impl<'a> AddRoleToMember<'a> { role_id: impl Into, ) -> Self { Self { - fut: None, guild_id: guild_id.into(), http, role_id: role_id.into(), @@ -54,7 +54,10 @@ impl<'a> AddRoleToMember<'a> { } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::AddMemberRole { guild_id: self.guild_id.0, role_id: self.role_id.0, @@ -62,13 +65,15 @@ impl<'a> AddRoleToMember<'a> { }); if let Some(reason) = self.reason.as_ref() { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -80,5 +85,3 @@ impl<'a> AuditLogReason for AddRoleToMember<'a> { Ok(self) } } - -poll_req!(AddRoleToMember<'_>, EmptyBody); diff --git a/http/src/request/guild/member/get_guild_members.rs b/http/src/request/guild/member/get_guild_members.rs index 2aebc561ee0..a9218c5ab17 100644 --- a/http/src/request/guild/member/get_guild_members.rs +++ b/http/src/request/guild/member/get_guild_members.rs @@ -1,16 +1,12 @@ use crate::{ client::Client, - error::Error as HttpError, - request::{validate, PendingResponse, Request}, - response::{marker::MemberListBody, Response}, + request::{validate, Request}, + response::{marker::MemberListBody, ResponseFuture}, routing::Route, }; use std::{ error::Error, fmt::{Display, Formatter, Result as FmtResult}, - future::Future, - pin::Pin, - task::{Context, Poll}, }; use twilight_model::id::{GuildId, UserId}; @@ -93,12 +89,11 @@ struct GetGuildMembersFields { /// /// let guild_id = GuildId(100); /// let user_id = UserId(3000); -/// let members = client.guild_members(guild_id).after(user_id).await?; +/// let members = client.guild_members(guild_id).after(user_id).exec().await?; /// # Ok(()) } /// ``` pub struct GetGuildMembers<'a> { fields: GetGuildMembersFields, - fut: Option>, guild_id: GuildId, http: &'a Client, } @@ -107,7 +102,6 @@ impl<'a> GetGuildMembers<'a> { pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { Self { fields: GetGuildMembersFields::default(), - fut: None, guild_id, http, } @@ -147,7 +141,10 @@ impl<'a> GetGuildMembers<'a> { self } - fn start(&mut self) -> Result<(), HttpError> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetGuildMembers { after: self.fields.after.map(|x| x.0), guild_id: self.guild_id.0, @@ -155,28 +152,9 @@ impl<'a> GetGuildMembers<'a> { presences: self.fields.presences, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) - } -} - -impl Future for GetGuildMembers<'_> { - type Output = Result, HttpError>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - loop { - if let Some(fut) = self.as_mut().fut.as_mut() { - return fut.as_mut().poll(cx).map_ok(|mut res| { - res.set_guild_id(self.guild_id); + let mut future = self.http.request(request); + future.set_guild_id(self.guild_id); - res - }); - } - - if let Err(why) = self.as_mut().start() { - return Poll::Ready(Err(why)); - } - } + future } } diff --git a/http/src/request/guild/member/get_member.rs b/http/src/request/guild/member/get_member.rs index 5ca12313bb1..883653ab4d2 100644 --- a/http/src/request/guild/member/get_member.rs +++ b/http/src/request/guild/member/get_member.rs @@ -1,63 +1,39 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::{marker::MemberBody, Response}, + request::Request, + response::{marker::MemberBody, ResponseFuture}, routing::Route, }; -use std::{ - future::Future, - pin::Pin, - task::{Context, Poll}, -}; use twilight_model::id::{GuildId, UserId}; /// Get a member of a guild, by id. pub struct GetMember<'a> { - fut: Option>, guild_id: GuildId, http: &'a Client, user_id: UserId, } impl<'a> GetMember<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId, user_id: UserId) -> Self { + pub(crate) const fn new(http: &'a Client, guild_id: GuildId, user_id: UserId) -> Self { Self { - fut: None, guild_id, http, user_id, } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::GetMember { guild_id: self.guild_id.0, user_id: self.user_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) - } -} - -impl Future for GetMember<'_> { - type Output = Result, Error>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - loop { - if let Some(fut) = self.as_mut().fut.as_mut() { - return fut.as_mut().poll(cx).map_ok(|mut res| { - res.set_guild_id(self.guild_id); + let mut future = self.http.request(request); + future.set_guild_id(self.guild_id); - res - }); - } - - if let Err(why) = self.as_mut().start() { - return Poll::Ready(Err(why)); - } - } + future } } diff --git a/http/src/request/guild/member/remove_member.rs b/http/src/request/guild/member/remove_member.rs index ab35285b3fe..c1c8a068da4 100644 --- a/http/src/request/guild/member/remove_member.rs +++ b/http/src/request/guild/member/remove_member.rs @@ -1,15 +1,13 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{GuildId, UserId}; /// Kick a member from a guild, by their id. pub struct RemoveMember<'a> { - fut: Option>, guild_id: GuildId, http: &'a Client, user_id: UserId, @@ -17,9 +15,8 @@ pub struct RemoveMember<'a> { } impl<'a> RemoveMember<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId, user_id: UserId) -> Self { + pub(crate) const fn new(http: &'a Client, guild_id: GuildId, user_id: UserId) -> Self { Self { - fut: None, guild_id, http, user_id, @@ -27,20 +24,25 @@ impl<'a> RemoveMember<'a> { } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::RemoveMember { guild_id: self.guild_id.0, user_id: self.user_id.0, }); if let Some(reason) = self.reason.as_ref() { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -52,5 +54,3 @@ impl<'a> AuditLogReason for RemoveMember<'a> { Ok(self) } } - -poll_req!(RemoveMember<'_>, EmptyBody); diff --git a/http/src/request/guild/member/remove_role_from_member.rs b/http/src/request/guild/member/remove_role_from_member.rs index 7e30bcf76fe..738c1967607 100644 --- a/http/src/request/guild/member/remove_role_from_member.rs +++ b/http/src/request/guild/member/remove_role_from_member.rs @@ -1,15 +1,13 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{GuildId, RoleId, UserId}; /// Remove a role from a member in a guild, by id. pub struct RemoveRoleFromMember<'a> { - fut: Option>, guild_id: GuildId, http: &'a Client, role_id: RoleId, @@ -25,7 +23,6 @@ impl<'a> RemoveRoleFromMember<'a> { role_id: impl Into, ) -> Self { Self { - fut: None, guild_id: guild_id.into(), http, role_id: role_id.into(), @@ -34,7 +31,10 @@ impl<'a> RemoveRoleFromMember<'a> { } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::RemoveMemberRole { guild_id: self.guild_id.0, role_id: self.role_id.0, @@ -42,13 +42,15 @@ impl<'a> RemoveRoleFromMember<'a> { }); if let Some(reason) = self.reason.as_ref() { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -60,5 +62,3 @@ impl<'a> AuditLogReason for RemoveRoleFromMember<'a> { Ok(self) } } - -poll_req!(RemoveRoleFromMember<'_>, EmptyBody); diff --git a/http/src/request/guild/member/search_guild_members.rs b/http/src/request/guild/member/search_guild_members.rs index 1512a7b7560..ec66ebb64fc 100644 --- a/http/src/request/guild/member/search_guild_members.rs +++ b/http/src/request/guild/member/search_guild_members.rs @@ -1,16 +1,12 @@ use crate::{ client::Client, - error::Error as HttpError, - request::{validate, PendingResponse, Request}, - response::{marker::MemberListBody, Response}, + request::{validate, Request}, + response::{marker::MemberListBody, ResponseFuture}, routing::Route, }; use std::{ error::Error, fmt::{Display, Formatter, Result as FmtResult}, - future::Future, - pin::Pin, - task::{Context, Poll}, }; use twilight_model::id::GuildId; @@ -89,7 +85,10 @@ struct SearchGuildMembersFields { /// let client = Client::new("my token"); /// /// let guild_id = GuildId(100); -/// let members = client.search_guild_members(guild_id, String::from("Wumpus")).limit(10)?.await?; +/// let members = client.search_guild_members(guild_id, String::from("Wumpus")) +/// .limit(10)? +/// .exec() +/// .await?; /// # Ok(()) } /// ``` /// @@ -101,7 +100,6 @@ struct SearchGuildMembersFields { /// [`GUILD_MEMBERS`]: twilight_model::gateway::Intents#GUILD_MEMBERS pub struct SearchGuildMembers<'a> { fields: SearchGuildMembersFields, - fut: Option>, guild_id: GuildId, http: &'a Client, } @@ -111,10 +109,9 @@ impl<'a> SearchGuildMembers<'a> { Self::_new(http, guild_id, query.into()) } - fn _new(http: &'a Client, guild_id: GuildId, query: String) -> Self { + const fn _new(http: &'a Client, guild_id: GuildId, query: String) -> Self { Self { fields: SearchGuildMembersFields { query, limit: None }, - fut: None, guild_id, http, } @@ -142,35 +139,19 @@ impl<'a> SearchGuildMembers<'a> { Ok(self) } - fn start(&mut self) -> Result<(), HttpError> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let request = Request::from_route(Route::SearchGuildMembers { guild_id: self.guild_id.0, limit: self.fields.limit, - query: self.fields.query.clone(), + query: self.fields.query, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) - } -} - -impl Future for SearchGuildMembers<'_> { - type Output = Result, HttpError>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - loop { - if let Some(fut) = self.as_mut().fut.as_mut() { - return fut.as_mut().poll(cx).map_ok(|mut res| { - res.set_guild_id(self.guild_id); + let mut future = self.http.request(request); + future.set_guild_id(self.guild_id); - res - }); - } - - if let Err(why) = self.as_mut().start() { - return Poll::Ready(Err(why)); - } - } + future } } diff --git a/http/src/request/guild/member/update_guild_member.rs b/http/src/request/guild/member/update_guild_member.rs index fe80e80ad9d..553890506ea 100644 --- a/http/src/request/guild/member/update_guild_member.rs +++ b/http/src/request/guild/member/update_guild_member.rs @@ -1,20 +1,14 @@ use crate::{ client::Client, error::Error as HttpError, - request::{ - self, validate, AuditLogReason, AuditLogReasonError, NullableField, PendingResponse, - Request, - }, - response::{marker::MemberBody, Response}, + request::{self, validate, AuditLogReason, AuditLogReasonError, NullableField, Request}, + response::{marker::MemberBody, ResponseFuture}, routing::Route, }; use serde::Serialize; use std::{ error::Error, fmt::{Display, Formatter, Result as FmtResult}, - future::Future, - pin::Pin, - task::{Context, Poll}, }; use twilight_model::id::{ChannelId, GuildId, RoleId, UserId}; @@ -91,7 +85,6 @@ struct UpdateGuildMemberFields { /// [the discord docs]: https://discord.com/developers/docs/resources/guild#modify-guild-member pub struct UpdateGuildMember<'a> { fields: UpdateGuildMemberFields, - fut: Option>, guild_id: GuildId, http: &'a Client, user_id: UserId, @@ -102,7 +95,6 @@ impl<'a> UpdateGuildMember<'a> { pub(crate) fn new(http: &'a Client, guild_id: GuildId, user_id: UserId) -> Self { Self { fields: UpdateGuildMemberFields::default(), - fut: None, guild_id, http, user_id, @@ -183,11 +175,19 @@ impl<'a> UpdateGuildMember<'a> { Ok(request.build()) } - fn start(&mut self) -> Result<(), HttpError> { - let request = self.request()?; - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + match self.request() { + Ok(request) => { + let mut future = self.http.request(request); + future.set_guild_id(self.guild_id); + + future + } + Err(source) => ResponseFuture::error(source), + } } } @@ -200,26 +200,6 @@ impl<'a> AuditLogReason for UpdateGuildMember<'a> { } } -impl Future for UpdateGuildMember<'_> { - type Output = Result, HttpError>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - loop { - if let Some(fut) = self.as_mut().fut.as_mut() { - return fut.as_mut().poll(cx).map_ok(|mut res| { - res.set_guild_id(self.guild_id); - - res - }); - } - - if let Err(why) = self.as_mut().start() { - return Poll::Ready(Err(why)); - } - } - } -} - #[cfg(test)] mod tests { use super::{UpdateGuildMember, UpdateGuildMemberFields}; diff --git a/http/src/request/guild/role/create_role.rs b/http/src/request/guild/role/create_role.rs index 7c30dfa367d..c7c3c227a22 100644 --- a/http/src/request/guild/role/create_role.rs +++ b/http/src/request/guild/role/create_role.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -40,12 +40,12 @@ struct CreateRoleFields { /// client.create_role(guild_id) /// .color(0xd90083) /// .name("Bright Pink") +/// .exec() /// .await?; /// # Ok(()) } /// ``` pub struct CreateRole<'a> { fields: CreateRoleFields, - fut: Option>, guild_id: GuildId, http: &'a Client, reason: Option, @@ -55,7 +55,6 @@ impl<'a> CreateRole<'a> { pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { Self { fields: CreateRoleFields::default(), - fut: None, guild_id, http, reason: None, @@ -99,20 +98,29 @@ impl<'a> CreateRole<'a> { self } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::CreateRole { guild_id: self.guild_id.0, - }) - .json(&self.fields)?; + }); + + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; if let Some(reason) = &self.reason { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -124,5 +132,3 @@ impl<'a> AuditLogReason for CreateRole<'a> { Ok(self) } } - -poll_req!(CreateRole<'_>, Role); diff --git a/http/src/request/guild/role/delete_role.rs b/http/src/request/guild/role/delete_role.rs index 0aebcd75a66..02e898c6642 100644 --- a/http/src/request/guild/role/delete_role.rs +++ b/http/src/request/guild/role/delete_role.rs @@ -1,15 +1,13 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, PendingResponse, Request}, - response::marker::EmptyBody, + request::{self, AuditLogReason, AuditLogReasonError, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use twilight_model::id::{GuildId, RoleId}; /// Delete a role in a guild, by id. pub struct DeleteRole<'a> { - fut: Option>, guild_id: GuildId, http: &'a Client, role_id: RoleId, @@ -17,9 +15,8 @@ pub struct DeleteRole<'a> { } impl<'a> DeleteRole<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId, role_id: RoleId) -> Self { + pub(crate) const fn new(http: &'a Client, guild_id: GuildId, role_id: RoleId) -> Self { Self { - fut: None, guild_id, http, role_id, @@ -27,20 +24,25 @@ impl<'a> DeleteRole<'a> { } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::DeleteRole { guild_id: self.guild_id.0, role_id: self.role_id.0, }); if let Some(reason) = &self.reason { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -52,5 +54,3 @@ impl<'a> AuditLogReason for DeleteRole<'a> { Ok(self) } } - -poll_req!(DeleteRole<'_>, EmptyBody); diff --git a/http/src/request/guild/role/get_guild_roles.rs b/http/src/request/guild/role/get_guild_roles.rs index 704d8de958c..1b57fac455d 100644 --- a/http/src/request/guild/role/get_guild_roles.rs +++ b/http/src/request/guild/role/get_guild_roles.rs @@ -1,37 +1,30 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::ListBody, + request::Request, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use twilight_model::{guild::Role, id::GuildId}; /// Get the roles of a guild. pub struct GetGuildRoles<'a> { - fut: Option>>, guild_id: GuildId, http: &'a Client, } impl<'a> GetGuildRoles<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { - Self { - fut: None, - guild_id, - http, - } + pub(crate) const fn new(http: &'a Client, guild_id: GuildId) -> Self { + Self { guild_id, http } } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { let request = Request::from_route(Route::GetGuildRoles { guild_id: self.guild_id.0, }); - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + self.http.request(request) } } - -poll_req!(GetGuildRoles<'_>, ListBody); diff --git a/http/src/request/guild/role/update_role.rs b/http/src/request/guild/role/update_role.rs index f74b7454897..04a9ccd702b 100644 --- a/http/src/request/guild/role/update_role.rs +++ b/http/src/request/guild/role/update_role.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{self, AuditLogReason, AuditLogReasonError, NullableField, PendingResponse, Request}, + request::{self, AuditLogReason, AuditLogReasonError, NullableField, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -27,7 +27,6 @@ struct UpdateRoleFields { /// Update a role by guild id and its id. pub struct UpdateRole<'a> { fields: UpdateRoleFields, - fut: Option>, guild_id: GuildId, http: &'a Client, role_id: RoleId, @@ -38,7 +37,6 @@ impl<'a> UpdateRole<'a> { pub(crate) fn new(http: &'a Client, guild_id: GuildId, role_id: RoleId) -> Self { Self { fields: UpdateRoleFields::default(), - fut: None, guild_id, http, role_id, @@ -85,21 +83,30 @@ impl<'a> UpdateRole<'a> { self } - fn start(&mut self) -> Result<(), Error> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::UpdateRole { guild_id: self.guild_id.0, role_id: self.role_id.0, - }) - .json(&self.fields)?; + }); + + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; if let Some(reason) = &self.reason { - request = request.headers(request::audit_header(reason)?); - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -111,5 +118,3 @@ impl<'a> AuditLogReason for UpdateRole<'a> { Ok(self) } } - -poll_req!(UpdateRole<'_>, Role); diff --git a/http/src/request/guild/role/update_role_positions.rs b/http/src/request/guild/role/update_role_positions.rs index 679a6325994..f252242bee0 100644 --- a/http/src/request/guild/role/update_role_positions.rs +++ b/http/src/request/guild/role/update_role_positions.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::ListBody, + request::Request, + response::{marker::ListBody, ResponseFuture}, routing::Route, }; use twilight_model::{ @@ -14,7 +13,6 @@ use twilight_model::{ /// /// The minimum amount of roles to modify, is a swap between two roles. pub struct UpdateRolePositions<'a> { - fut: Option>>, guild_id: GuildId, http: &'a Client, roles: Vec<(RoleId, u64)>, @@ -27,24 +25,25 @@ impl<'a> UpdateRolePositions<'a> { roles: impl Iterator, ) -> Self { Self { - fut: None, guild_id, http, roles: roles.collect(), } } - fn start(&mut self) -> Result<(), Error> { - let request = Request::builder(Route::UpdateRolePositions { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture> { + let mut request = Request::builder(Route::UpdateRolePositions { guild_id: self.guild_id.0, - }) - .json(&self.roles)? - .build(); + }); - self.fut.replace(Box::pin(self.http.request(request))); + request = match request.json(&self.roles) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; - Ok(()) + self.http.request(request.build()) } } - -poll_req!(UpdateRolePositions<'_>, ListBody); diff --git a/http/src/request/guild/update_current_user_nick.rs b/http/src/request/guild/update_current_user_nick.rs index e50b7c86420..602cb04b002 100644 --- a/http/src/request/guild/update_current_user_nick.rs +++ b/http/src/request/guild/update_current_user_nick.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::Request, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use serde::Serialize; @@ -16,7 +15,6 @@ struct UpdateCurrentUserNickFields { /// Changes the user's nickname in a guild. pub struct UpdateCurrentUserNick<'a> { fields: UpdateCurrentUserNickFields, - fut: Option>, guild_id: GuildId, http: &'a Client, } @@ -25,23 +23,24 @@ impl<'a> UpdateCurrentUserNick<'a> { pub(crate) fn new(http: &'a Client, guild_id: GuildId, nick: impl Into) -> Self { Self { fields: UpdateCurrentUserNickFields { nick: nick.into() }, - fut: None, guild_id, http, } } - fn start(&mut self) -> Result<(), Error> { - let request = Request::builder(Route::UpdateNickname { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let mut request = Request::builder(Route::UpdateNickname { guild_id: self.guild_id.0, - }) - .json(&self.fields)? - .build(); + }); - self.fut.replace(Box::pin(self.http.request(request))); + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; - Ok(()) + self.http.request(request.build()) } } - -poll_req!(UpdateCurrentUserNick<'_>, EmptyBody); diff --git a/http/src/request/guild/update_guild.rs b/http/src/request/guild/update_guild.rs index 339846ffd8b..1ca8f121eed 100644 --- a/http/src/request/guild/update_guild.rs +++ b/http/src/request/guild/update_guild.rs @@ -1,10 +1,7 @@ use crate::{ client::Client, - error::Error as HttpError, - request::{ - self, validate, AuditLogReason, AuditLogReasonError, NullableField, PendingResponse, - Request, - }, + request::{self, validate, AuditLogReason, AuditLogReasonError, NullableField, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -114,7 +111,6 @@ struct UpdateGuildFields { /// [the discord docs]: https://discord.com/developers/docs/resources/guild#modify-guild pub struct UpdateGuild<'a> { fields: UpdateGuildFields, - fut: Option>, guild_id: GuildId, http: &'a Client, reason: Option, @@ -124,7 +120,6 @@ impl<'a> UpdateGuild<'a> { pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { Self { fields: UpdateGuildFields::default(), - fut: None, guild_id, http, reason: None, @@ -341,20 +336,29 @@ impl<'a> UpdateGuild<'a> { self } - fn start(&mut self) -> Result<(), HttpError> { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { let mut request = Request::builder(Route::UpdateGuild { guild_id: self.guild_id.0, - }) - .json(&self.fields)?; + }); + + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; if let Some(reason) = &self.reason { - request = request.headers(request::audit_header(reason)?) - } + let header = match request::audit_header(reason) { + Ok(header) => header, + Err(source) => return ResponseFuture::error(source), + }; - self.fut - .replace(Box::pin(self.http.request(request.build()))); + request = request.headers(header); + } - Ok(()) + self.http.request(request.build()) } } @@ -366,5 +370,3 @@ impl<'a> AuditLogReason for UpdateGuild<'a> { Ok(self) } } - -poll_req!(UpdateGuild<'_>, PartialGuild); diff --git a/http/src/request/guild/update_guild_channel_positions.rs b/http/src/request/guild/update_guild_channel_positions.rs index 2756dd3ed2e..b62b015fe9b 100644 --- a/http/src/request/guild/update_guild_channel_positions.rs +++ b/http/src/request/guild/update_guild_channel_positions.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::Request, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use serde::Serialize; @@ -37,7 +36,6 @@ impl From<(ChannelId, u64)> for Position { /// This function accepts an `Iterator` of `(ChannelId, u64)`. It also accepts /// an `Iterator` of `Position`, which has extra fields. pub struct UpdateGuildChannelPositions<'a> { - fut: Option>, guild_id: GuildId, http: &'a Client, positions: Vec, @@ -52,24 +50,25 @@ impl<'a> UpdateGuildChannelPositions<'a> { let positions = channel_positions.map(Into::into).collect(); Self { - fut: None, guild_id, http, positions, } } - fn start(&mut self) -> Result<(), Error> { - let request = Request::builder(Route::UpdateGuildChannels { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let mut request = Request::builder(Route::UpdateGuildChannels { guild_id: self.guild_id.0, - }) - .json(&self.positions)? - .build(); + }); - self.fut.replace(Box::pin(self.http.request(request))); + request = match request.json(&self.positions) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; - Ok(()) + self.http.request(request.build()) } } - -poll_req!(UpdateGuildChannelPositions<'_>, EmptyBody); diff --git a/http/src/request/guild/update_guild_welcome_screen.rs b/http/src/request/guild/update_guild_welcome_screen.rs index c05bd8a2c0c..befe43c9932 100644 --- a/http/src/request/guild/update_guild_welcome_screen.rs +++ b/http/src/request/guild/update_guild_welcome_screen.rs @@ -1,9 +1,4 @@ -use crate::{ - client::Client, - error::Error, - request::{PendingResponse, Request}, - routing::Route, -}; +use crate::{client::Client, request::Request, response::ResponseFuture, routing::Route}; use serde::Serialize; use twilight_model::{ id::GuildId, @@ -27,7 +22,6 @@ struct UpdateGuildWelcomeScreenFields { /// [`MANAGE_GUILD`]: twilight_model::guild::Permissions::MANAGE_GUILD pub struct UpdateGuildWelcomeScreen<'a> { fields: UpdateGuildWelcomeScreenFields, - fut: Option>, guild_id: GuildId, http: &'a Client, } @@ -36,7 +30,6 @@ impl<'a> UpdateGuildWelcomeScreen<'a> { pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { Self { fields: UpdateGuildWelcomeScreenFields::default(), - fut: None, guild_id, http, } @@ -70,17 +63,19 @@ impl<'a> UpdateGuildWelcomeScreen<'a> { self } - fn start(&mut self) -> Result<(), Error> { - let request = Request::builder(Route::UpdateGuildWelcomeScreen { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let mut request = Request::builder(Route::UpdateGuildWelcomeScreen { guild_id: self.guild_id.0, - }) - .json(&self.fields)? - .build(); + }); - self.fut.replace(Box::pin(self.http.request(request))); + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; - Ok(()) + self.http.request(request.build()) } } - -poll_req!(UpdateGuildWelcomeScreen<'_>, WelcomeScreen); diff --git a/http/src/request/guild/update_guild_widget.rs b/http/src/request/guild/update_guild_widget.rs index 0d1660c85d6..bee887648e7 100644 --- a/http/src/request/guild/update_guild_widget.rs +++ b/http/src/request/guild/update_guild_widget.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{NullableField, PendingResponse, Request}, + request::{NullableField, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -21,7 +21,6 @@ struct UpdateGuildWidgetFields { /// Modify the guild widget. pub struct UpdateGuildWidget<'a> { fields: UpdateGuildWidgetFields, - fut: Option>, guild_id: GuildId, http: &'a Client, } @@ -30,7 +29,6 @@ impl<'a> UpdateGuildWidget<'a> { pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self { Self { fields: UpdateGuildWidgetFields::default(), - fut: None, guild_id, http, } @@ -53,17 +51,19 @@ impl<'a> UpdateGuildWidget<'a> { self } - fn start(&mut self) -> Result<(), Error> { - let request = Request::builder(Route::UpdateGuildWidget { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let mut request = Request::builder(Route::UpdateGuildWidget { guild_id: self.guild_id.0, - }) - .json(&self.fields)? - .build(); + }); - self.fut.replace(Box::pin(self.http.request(request))); + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; - Ok(()) + self.http.request(request.build()) } } - -poll_req!(UpdateGuildWidget<'_>, GuildWidget); diff --git a/http/src/request/guild/user/update_current_user_voice_state.rs b/http/src/request/guild/user/update_current_user_voice_state.rs index f958180a6f2..d39342acfb2 100644 --- a/http/src/request/guild/user/update_current_user_voice_state.rs +++ b/http/src/request/guild/user/update_current_user_voice_state.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{NullableField, PendingResponse, Request}, - response::marker::EmptyBody, + request::{NullableField, Request}, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use serde::Serialize; @@ -20,20 +19,18 @@ struct UpdateCurrentUserVoiceStateFields { /// Update the current user's voice state. pub struct UpdateCurrentUserVoiceState<'a> { fields: UpdateCurrentUserVoiceStateFields, - fut: Option>, guild_id: GuildId, http: &'a Client, } impl<'a> UpdateCurrentUserVoiceState<'a> { - pub(crate) fn new(http: &'a Client, guild_id: GuildId, channel_id: ChannelId) -> Self { + pub(crate) const fn new(http: &'a Client, guild_id: GuildId, channel_id: ChannelId) -> Self { Self { fields: UpdateCurrentUserVoiceStateFields { channel_id, suppress: None, request_to_speak_timestamp: None, }, - fut: None, guild_id, http, } @@ -77,17 +74,19 @@ impl<'a> UpdateCurrentUserVoiceState<'a> { self } - fn start(&mut self) -> Result<(), Error> { - let request = Request::builder(Route::UpdateCurrentUserVoiceState { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let mut request = Request::builder(Route::UpdateCurrentUserVoiceState { guild_id: self.guild_id.0, - }) - .json(&self.fields)? - .build(); + }); - self.fut.replace(Box::pin(self.http.request(request))); + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; - Ok(()) + self.http.request(request.build()) } } - -poll_req!(UpdateCurrentUserVoiceState<'_>, EmptyBody); diff --git a/http/src/request/guild/user/update_user_voice_state.rs b/http/src/request/guild/user/update_user_voice_state.rs index 0610a95d5d4..31b9ce8281e 100644 --- a/http/src/request/guild/user/update_user_voice_state.rs +++ b/http/src/request/guild/user/update_user_voice_state.rs @@ -1,8 +1,7 @@ use crate::{ client::Client, - error::Error, - request::{PendingResponse, Request}, - response::marker::EmptyBody, + request::Request, + response::{marker::EmptyBody, ResponseFuture}, routing::Route, }; use serde::Serialize; @@ -18,14 +17,13 @@ struct UpdateUserVoiceStateFields { /// Update another user's voice state. pub struct UpdateUserVoiceState<'a> { fields: UpdateUserVoiceStateFields, - fut: Option>, guild_id: GuildId, http: &'a Client, user_id: UserId, } impl<'a> UpdateUserVoiceState<'a> { - pub(crate) fn new( + pub(crate) const fn new( http: &'a Client, guild_id: GuildId, user_id: UserId, @@ -36,7 +34,6 @@ impl<'a> UpdateUserVoiceState<'a> { channel_id, suppress: None, }, - fut: None, guild_id, http, user_id, @@ -61,18 +58,20 @@ impl<'a> UpdateUserVoiceState<'a> { self } - fn start(&mut self) -> Result<(), Error> { - let request = Request::builder(Route::UpdateUserVoiceState { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let mut request = Request::builder(Route::UpdateUserVoiceState { guild_id: self.guild_id.0, user_id: self.user_id.0, - }) - .json(&self.fields)? - .build(); + }); - self.fut.replace(Box::pin(self.http.request(request))); + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; - Ok(()) + self.http.request(request.build()) } } - -poll_req!(UpdateUserVoiceState<'_>, EmptyBody); diff --git a/http/src/request/mod.rs b/http/src/request/mod.rs index 1562d3d72fc..5493f91f8d4 100644 --- a/http/src/request/mod.rs +++ b/http/src/request/mod.rs @@ -1,26 +1,3 @@ -macro_rules! poll_req { - ($ty: ty, $out: ty) => { - impl std::future::Future for $ty { - type Output = Result<$crate::request::Response<$out>, $crate::error::Error>; - - fn poll( - mut self: std::pin::Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> ::std::task::Poll { - loop { - if let Some(fut) = self.as_mut().fut.as_mut() { - return fut.as_mut().poll(cx); - } - - if let Err(why) = self.as_mut().start() { - return ::std::task::Poll::Ready(Err(why)); - } - } - } - } - }; -} - pub mod application; pub mod channel; pub mod guild; @@ -47,23 +24,14 @@ pub use self::{ multipart::Form, }; -use crate::{ - error::{Error, ErrorType}, - response::Response, -}; +use crate::error::{Error, ErrorType}; use hyper::{ header::{HeaderName, HeaderValue}, Method as HyperMethod, }; use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; use serde::{Serialize, Serializer}; -use std::{future::Future, iter, pin::Pin}; - -/// Response is in-flight and is currently pending. -/// -/// Resolves to a [`Response`] when completed. Responses may or may not have -/// deserializable bodies. -type PendingResponse<'a, T> = Pin, Error>> + Send + 'a>>; +use std::iter; /// Request method. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] diff --git a/http/src/request/template/create_guild_from_template.rs b/http/src/request/template/create_guild_from_template.rs index 2f67b471363..1b5c40a8576 100644 --- a/http/src/request/template/create_guild_from_template.rs +++ b/http/src/request/template/create_guild_from_template.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error as HttpError, - request::{validate, PendingResponse, Request}, + request::{validate, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -82,7 +82,6 @@ struct CreateGuildFromTemplateFields { /// the name is invalid. pub struct CreateGuildFromTemplate<'a> { fields: CreateGuildFromTemplateFields, - fut: Option>, http: &'a Client, template_code: String, } @@ -109,7 +108,6 @@ impl<'a> CreateGuildFromTemplate<'a> { Ok(Self { fields: CreateGuildFromTemplateFields { name, icon: None }, - fut: None, http, template_code, }) @@ -132,17 +130,19 @@ impl<'a> CreateGuildFromTemplate<'a> { self } - fn start(&mut self) -> Result<(), HttpError> { - let request = Request::builder(Route::CreateGuildFromTemplate { - template_code: self.template_code.clone(), - }) - .json(&self.fields)? - .build(); - - self.fut.replace(Box::pin(self.http.request(request))); - - Ok(()) + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture { + let mut request = Request::builder(Route::CreateGuildFromTemplate { + template_code: self.template_code, + }); + + request = match request.json(&self.fields) { + Ok(request) => request, + Err(source) => return ResponseFuture::error(source), + }; + + self.http.request(request.build()) } } - -poll_req!(CreateGuildFromTemplate<'_>, Guild); diff --git a/http/src/request/template/create_template.rs b/http/src/request/template/create_template.rs index c5bee1fb685..a82e0c4b501 100644 --- a/http/src/request/template/create_template.rs +++ b/http/src/request/template/create_template.rs @@ -1,7 +1,7 @@ use crate::{ client::Client, - error::Error as HttpError, - request::{validate, PendingResponse, Request}, + request::{validate, Request}, + response::ResponseFuture, routing::Route, }; use serde::Serialize; @@ -91,7 +91,6 @@ struct CreateTemplateFields { /// invalid. pub struct CreateTemplate<'a> { fields: CreateTemplateFields, - fut: Option>, guild_id: GuildId, http: &'a Client, } @@ -122,7 +121,6 @@ impl<'a> CreateTemplate<'a> { description: None, }, guild_id, - fut: None, http, }) } @@ -151,17 +149,19 @@ impl<'a> CreateTemplate<'a> { Ok(self) } - fn start(&mut self) -> Result<(), HttpError> { - let request = Request::builder(Route::CreateTemplate { + /// Execute the request, returning a future resolving to a [`Response`]. + /// + /// [`Response`]: crate::response::Response + pub fn exec(self) -> ResponseFuture