From fb1cd56a1bd8bef8b0770cbb1c0f3b690abb7a9e Mon Sep 17 00:00:00 2001 From: Tim Vilgot Mikael Fredenberg Date: Sun, 26 Feb 2023 09:08:33 +0100 Subject: [PATCH] refactor!: move `RequestReactionType` to model --- twilight-http/src/client/mod.rs | 10 +- .../channel/reaction/create_reaction.rs | 14 +- .../channel/reaction/delete_all_reaction.rs | 10 +- .../channel/reaction/delete_reaction.rs | 10 +- .../request/channel/reaction/get_reactions.rs | 2 +- .../src/request/channel/reaction/mod.rs | 130 ------------------ twilight-http/src/routing.rs | 12 +- twilight-model/Cargo.toml | 1 + twilight-model/src/http/mod.rs | 4 + twilight-model/src/http/reaction_type.rs | 110 +++++++++++++++ 10 files changed, 148 insertions(+), 155 deletions(-) create mode 100644 twilight-model/src/http/reaction_type.rs diff --git a/twilight-http/src/client/mod.rs b/twilight-http/src/client/mod.rs index 8bf223a1d64..bd6f3557f2a 100644 --- a/twilight-http/src/client/mod.rs +++ b/twilight-http/src/client/mod.rs @@ -16,7 +16,7 @@ use crate::{ }, reaction::{ delete_reaction::TargetUser, CreateReaction, DeleteAllReaction, DeleteAllReactions, - DeleteReaction, GetReactions, RequestReactionType, + DeleteReaction, GetReactions, }, stage::{ CreateStageInstance, DeleteStageInstance, GetStageInstance, UpdateStageInstance, @@ -101,7 +101,7 @@ use twilight_http_ratelimiting::Ratelimiter; use twilight_model::{ channel::{message::AllowedMentions, ChannelType}, guild::{auto_moderation::AutoModerationEventType, scheduled_event::PrivacyLevel, MfaLevel}, - http::permission_overwrite::PermissionOverwrite, + http::{permission_overwrite::PermissionOverwrite, RequestReactionType}, id::{ marker::{ ApplicationMarker, AutoModerationRuleMarker, ChannelMarker, EmojiMarker, GuildMarker, @@ -2582,7 +2582,7 @@ impl Client { let url = format!("{protocol}://{host}/api/v{API_VERSION}/{path}"); tracing::debug!(?url); - let mut builder = hyper::Request::builder().method(method.to_http()).uri(&url); + let mut builder = hyper::Request::builder().method(method.name()).uri(&url); if use_authorization_token { if let Some(token) = self.token.as_deref() { @@ -2658,9 +2658,9 @@ impl Client { .flatten(); Ok(if let Some(ratelimiter) = &self.ratelimiter { - let tx_future = ratelimiter.wait_for_ticket(ratelimit_path); + let rx = ratelimiter.permit(ratelimit_path); - ResponseFuture::ratelimit(invalid_token, inner, self.timeout, tx_future) + ResponseFuture::ratelimit(invalid_token, inner, self.timeout, rx) } else { ResponseFuture::new(Box::pin(time::timeout(self.timeout, inner)), invalid_token) }) diff --git a/twilight-http/src/request/channel/reaction/create_reaction.rs b/twilight-http/src/request/channel/reaction/create_reaction.rs index 716c9c26a9f..8bf524ca35d 100644 --- a/twilight-http/src/request/channel/reaction/create_reaction.rs +++ b/twilight-http/src/request/channel/reaction/create_reaction.rs @@ -1,4 +1,3 @@ -use super::RequestReactionType; use crate::{ client::Client, error::Error, @@ -7,9 +6,12 @@ use crate::{ routing::Route, }; use std::future::IntoFuture; -use twilight_model::id::{ - marker::{ChannelMarker, MessageMarker}, - Id, +use twilight_model::{ + http::RequestReactionType, + id::{ + marker::{ChannelMarker, MessageMarker}, + Id, + }, }; /// Create a reaction in a [`Id`] on a [`Id`]. @@ -89,12 +91,12 @@ mod tests { use super::CreateReaction; use crate::{ - request::{channel::reaction::RequestReactionType, Request, TryIntoRequest}, + request::{Request, TryIntoRequest}, routing::Route, Client, }; use std::error::Error; - use twilight_model::id::Id; + use twilight_model::{http::RequestReactionType, id::Id}; #[test] fn request() -> Result<(), Box> { diff --git a/twilight-http/src/request/channel/reaction/delete_all_reaction.rs b/twilight-http/src/request/channel/reaction/delete_all_reaction.rs index 076f3d1872b..e4911bbb1b3 100644 --- a/twilight-http/src/request/channel/reaction/delete_all_reaction.rs +++ b/twilight-http/src/request/channel/reaction/delete_all_reaction.rs @@ -1,4 +1,3 @@ -use super::RequestReactionType; use crate::{ client::Client, error::Error, @@ -7,9 +6,12 @@ use crate::{ routing::Route, }; use std::future::IntoFuture; -use twilight_model::id::{ - marker::{ChannelMarker, MessageMarker}, - Id, +use twilight_model::{ + http::RequestReactionType, + id::{ + marker::{ChannelMarker, MessageMarker}, + Id, + }, }; /// Remove all reactions of a specified emoji from a message. diff --git a/twilight-http/src/request/channel/reaction/delete_reaction.rs b/twilight-http/src/request/channel/reaction/delete_reaction.rs index 77fee4df2d8..75c69432b80 100644 --- a/twilight-http/src/request/channel/reaction/delete_reaction.rs +++ b/twilight-http/src/request/channel/reaction/delete_reaction.rs @@ -1,4 +1,3 @@ -use super::RequestReactionType; use crate::{ client::Client, error::Error, @@ -7,9 +6,12 @@ use crate::{ routing::Route, }; use std::future::IntoFuture; -use twilight_model::id::{ - marker::{ChannelMarker, MessageMarker, UserMarker}, - Id, +use twilight_model::{ + http::RequestReactionType, + id::{ + marker::{ChannelMarker, MessageMarker, UserMarker}, + Id, + }, }; /// User to delete the reaction of. diff --git a/twilight-http/src/request/channel/reaction/get_reactions.rs b/twilight-http/src/request/channel/reaction/get_reactions.rs index 159a4350f57..64cec32b057 100644 --- a/twilight-http/src/request/channel/reaction/get_reactions.rs +++ b/twilight-http/src/request/channel/reaction/get_reactions.rs @@ -1,4 +1,3 @@ -use super::RequestReactionType; use crate::{ client::Client, error::Error, @@ -8,6 +7,7 @@ use crate::{ }; use std::future::IntoFuture; use twilight_model::{ + http::RequestReactionType, id::{ marker::{ChannelMarker, MessageMarker, UserMarker}, Id, diff --git a/twilight-http/src/request/channel/reaction/mod.rs b/twilight-http/src/request/channel/reaction/mod.rs index 023fff0ba74..576ea692a3c 100644 --- a/twilight-http/src/request/channel/reaction/mod.rs +++ b/twilight-http/src/request/channel/reaction/mod.rs @@ -10,133 +10,3 @@ pub use self::{ delete_all_reactions::DeleteAllReactions, delete_reaction::DeleteReaction, get_reactions::GetReactions, }; -use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; -use std::fmt::{Display, Formatter, Result as FmtResult}; -use twilight_model::id::{marker::EmojiMarker, Id}; - -/// Handle a reaction of either a custom or unicode emoji. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum RequestReactionType<'a> { - /// Reaction of a custom emoji. - Custom { - /// ID of the custom emoji. - id: Id, - /// Name of the custom emoji. - /// - /// This is not strictly required, but may be helpful for Discord to - /// work with. - name: Option<&'a str>, - }, - /// Reaction of a unicode emoji, such as "🌈". - Unicode { - /// Unicode emoji. - name: &'a str, - }, -} - -/// Format a [`RequestReactionType`] into a format acceptable for use in URLs. -/// -/// # Examples -/// -/// Format a custom reaction for use in a URL: -/// -/// ``` -/// use twilight_http::request::channel::reaction::RequestReactionType; -/// use twilight_model::id::Id; -/// -/// let reaction = RequestReactionType::Custom { -/// id: Id::new(123), -/// name: Some("rarity"), -/// }; -/// -/// assert_eq!("rarity:123", reaction.to_string()); -/// ``` -/// -/// Format the transgeneder flag for use in a URL: -/// -/// ``` -/// use twilight_http::request::channel::reaction::RequestReactionType; -/// -/// let reaction = RequestReactionType::Unicode { -/// name: "🏳️‍⚧️" -/// }; -/// -/// assert_eq!( -/// "%F0%9F%8F%B3%EF%B8%8F%E2%80%8D%E2%9A%A7%EF%B8%8F", -/// reaction.to_string(), -/// ); -/// ``` -impl Display for RequestReactionType<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - match self { - RequestReactionType::Custom { id, name } => { - if let Some(name) = name { - f.write_str(name)?; - } else { - f.write_str("e")?; - } - - f.write_str(":")?; - - Display::fmt(id, f) - } - RequestReactionType::Unicode { name } => { - Display::fmt(&utf8_percent_encode(name, NON_ALPHANUMERIC), f) - } - } - } -} - -#[cfg(test)] -mod tests { - // `clippy::non_ascii_literal` can't be allowed on an item level; it can - // only be enabled on a module level. - #![allow(clippy::non_ascii_literal)] - - use super::RequestReactionType; - use static_assertions::{assert_fields, assert_impl_all}; - use std::{ - fmt::{Debug, Display}, - hash::Hash, - }; - use twilight_model::id::Id; - - assert_fields!(RequestReactionType::Custom: id, name); - assert_fields!(RequestReactionType::Unicode: name); - assert_impl_all!(RequestReactionType<'_>: Clone, Copy, Debug, Display, Eq, Hash, PartialEq, Send, Sync); - - #[test] - fn display_custom_with_name() { - let reaction = RequestReactionType::Custom { - id: Id::new(123), - name: Some("foo"), - }; - - assert_eq!("foo:123", reaction.to_string()); - } - - #[test] - fn display_custom_without_name() { - let reaction = RequestReactionType::Custom { - id: Id::new(123), - name: None, - }; - - assert_eq!("e:123", reaction.to_string()); - } - - /// Test that unicode reactions format with percent encoding. - // We can't use the actual flag here - #[test] - fn display_unicode() { - let reaction = RequestReactionType::Unicode { - // Rainbow flag 🏳️‍🌈 - name: "🏳️‍🌈", - }; - - assert_eq!( - "%F0%9F%8F%B3%EF%B8%8F%E2%80%8D%F0%9F%8C%88", - reaction.to_string() - ); - } -} diff --git a/twilight-http/src/routing.rs b/twilight-http/src/routing.rs index 014cae7844f..d4e42a86764 100644 --- a/twilight-http/src/routing.rs +++ b/twilight-http/src/routing.rs @@ -1,9 +1,12 @@ use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; pub use twilight_http_ratelimiting::request::{Path, PathParseError, PathParseErrorType}; -use crate::request::{channel::reaction::RequestReactionType, Method}; +use crate::request::Method; use std::fmt::{Display, Formatter, Result as FmtResult}; -use twilight_model::id::{marker::RoleMarker, Id}; +use twilight_model::{ + http::RequestReactionType, + id::{marker::RoleMarker, Id}, +}; #[derive(Clone, Debug, Eq, Hash, PartialEq)] #[non_exhaustive] @@ -2905,8 +2908,8 @@ impl Display for Route<'_> { #[cfg(test)] mod tests { use super::Route; - use crate::request::{channel::reaction::RequestReactionType, Method}; - use twilight_model::id::Id; + use crate::request::Method; + use twilight_model::{http::RequestReactionType, id::Id}; /// Test a route for each method. #[test] @@ -2967,7 +2970,6 @@ mod tests { const fn emoji() -> RequestReactionType<'static> { RequestReactionType::Custom { id: Id::new(EMOJI_ID), - name: None, } } diff --git a/twilight-model/Cargo.toml b/twilight-model/Cargo.toml index 37bfef0c69e..22f23ad1540 100644 --- a/twilight-model/Cargo.toml +++ b/twilight-model/Cargo.toml @@ -14,6 +14,7 @@ version = "0.15.0" [dependencies] bitflags = { default-features = false, version = "1" } +percent-encoding = { default-features = false, version = "2" } serde = { default-features = false, features = ["derive", "std"], version = "1.0.103" } serde-value = { default-features = false, version = "0.7" } serde_repr = { default-features = false, version = "0.1.5" } diff --git a/twilight-model/src/http/mod.rs b/twilight-model/src/http/mod.rs index 95147b0811e..b1b83ab28de 100644 --- a/twilight-model/src/http/mod.rs +++ b/twilight-model/src/http/mod.rs @@ -3,3 +3,7 @@ pub mod attachment; pub mod interaction; pub mod permission_overwrite; + +mod reaction_type; + +pub use self::reaction_type::RequestReactionType; diff --git a/twilight-model/src/http/reaction_type.rs b/twilight-model/src/http/reaction_type.rs new file mode 100644 index 00000000000..f0665e4b516 --- /dev/null +++ b/twilight-model/src/http/reaction_type.rs @@ -0,0 +1,110 @@ +use crate::id::{marker::EmojiMarker, Id}; +use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; +use std::fmt::{Display, Formatter, Result as FmtResult}; + +/// Specifically for HTTP requests, type of [`Reaction`]. +/// +/// [`Reaction`]: crate::channel::message::Reaction +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum RequestReactionType<'a> { + /// Custom [`Emoji`]. + /// + /// [`Emoji`]: crate::guild::Emoji + Custom { + /// Emoji identifier. + id: Id, + }, + /// Standard [Unicode] emoji value. + /// + /// Unicode reactions must be specified by their unicode value, and *not* + /// their Discord display name. Instead of using ":arrow_right:", use "➡️". + /// + /// [Unicode]: https://unicode.org/emoji/ + Unicode { + /// Unicode name identifier. + name: &'a str, + }, +} + +/// Format a [`RequestReactionType`] into a format acceptable for use in URLs. +/// +/// # Examples +/// +/// Format a custom reaction for use in a URL: +/// +/// ``` +/// use twilight_http::request::channel::reaction::RequestReactionType; +/// use twilight_model::id::Id; +/// +/// let reaction = RequestReactionType::Custom { +/// id: Id::new(123), +/// name: Some("rarity"), +/// }; +/// +/// assert_eq!("rarity:123", reaction.to_string()); +/// ``` +/// +/// Format the transgeneder flag for use in a URL: +/// +/// ``` +/// use twilight_http::request::channel::reaction::RequestReactionType; +/// +/// let reaction = RequestReactionType::Unicode { +/// name: "🏳️‍⚧️" +/// }; +/// +/// assert_eq!( +/// "%F0%9F%8F%B3%EF%B8%8F%E2%80%8D%E2%9A%A7%EF%B8%8F", +/// reaction.to_string(), +/// ); +/// ``` +impl Display for RequestReactionType<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + RequestReactionType::Custom { id } => { + // Discord requires a name, but it need not be correct. Let's use `e`. + f.write_str("e:")?; + + Display::fmt(id, f) + } + RequestReactionType::Unicode { name } => { + Display::fmt(&utf8_percent_encode(name, NON_ALPHANUMERIC), f) + } + } + } +} +#[cfg(test)] +mod tests { + use super::RequestReactionType; + use crate::id::Id; + use static_assertions::{assert_fields, assert_impl_all}; + use std::{ + fmt::{Debug, Display}, + hash::Hash, + }; + + assert_fields!(RequestReactionType::Custom: id); + assert_fields!(RequestReactionType::Unicode: name); + assert_impl_all!(RequestReactionType<'_>: Clone, Copy, Debug, Display, Eq, Hash, PartialEq, Send, Sync); + + #[test] + fn display_custom() { + let reaction = RequestReactionType::Custom { id: Id::new(123) }; + + assert_eq!("e:123", reaction.to_string()); + } + + /// Test that unicode reactions format with percent encoding. + #[test] + fn display_unicode() { + let reaction = RequestReactionType::Unicode { + // Rainbow flag + name: "\u{1F3F3}\u{FE0F}\u{200D}\u{1F308}", + }; + + assert_eq!( + "%F0%9F%8F%B3%EF%B8%8F%E2%80%8D%F0%9F%8C%88", + reaction.to_string() + ); + } +}