Adds about one billion (+- a few hundred million) missing derives for
all sorts of types.

The biggest change in this PR is, how structs holding a property
`Shared<T>` types implement `PartialEq`. In previous versions of this
crate, if a `Shared<T>` was part of a struct, this or these properties
would be ignored in == comparisons. This is because `Shared<T>` is
defined as `Arc<RwLock<T>>` - meaning you'd have to lock the `RwLock` to
make a comparison. From now on, instead of ignoring these properties or
locking the inner `RwLock`, the pointer values of the `Arc<T>`'s get
compared. This is a cheap and exact way of ensuring `Eq` for types,
which have an inner `Shared<T>`.
This commit is contained in:
Flori 2024-07-20 18:07:20 +02:00 committed by GitHub
commit 1285d702d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
75 changed files with 1037 additions and 565 deletions

View File

@ -10,7 +10,7 @@ use crate::{
}; };
/// Useful metadata for working with [`types::Reaction`], bundled together nicely. /// Useful metadata for working with [`types::Reaction`], bundled together nicely.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Copy, Hash, PartialOrd, Ord)]
pub struct ReactionMeta { pub struct ReactionMeta {
pub message_id: types::Snowflake, pub message_id: types::Snowflake,
pub channel_id: types::Snowflake, pub channel_id: types::Snowflake,

View File

@ -14,7 +14,7 @@ use tokio_tungstenite::{
use crate::gateway::{GatewayMessage, RawGatewayMessage}; use crate::gateway::{GatewayMessage, RawGatewayMessage};
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
pub struct TungsteniteBackend; pub struct TungsteniteBackend;
// These could be made into inherent associated types when that's stabilized // These could be made into inherent associated types when that's stabilized

View File

@ -154,7 +154,7 @@ impl GatewayHandle {
/// Sends a call sync to the server /// Sends a call sync to the server
pub async fn send_call_sync(&self, to_send: types::CallSync) { pub async fn send_call_sync(&self, to_send: types::CallSync) {
let to_send_value = serde_json::to_value(&to_send).unwrap(); let to_send_value = serde_json::to_value(to_send).unwrap();
trace!("GW: Sending Call Sync.."); trace!("GW: Sending Call Sync..");

View File

@ -2,7 +2,6 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this // License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
use async_trait::async_trait;
pub mod backends; pub mod backends;
pub mod events; pub mod events;
@ -20,7 +19,7 @@ pub use message::*;
pub use options::*; pub use options::*;
use crate::errors::GatewayError; use crate::errors::GatewayError;
use crate::types::{Snowflake, WebSocketEvent}; use crate::types::{Snowflake};
use std::any::Any; use std::any::Any;
use std::collections::HashMap; use std::collections::HashMap;

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this // License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
#[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Debug, Default)] #[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Debug, Default, Copy)]
/// Options passed when initializing the gateway connection. /// Options passed when initializing the gateway connection.
/// ///
/// E.g. compression /// E.g. compression
@ -26,7 +26,6 @@ impl GatewayOptions {
/// ///
/// Returns the new url /// Returns the new url
pub(crate) fn add_to_url(&self, url: String) -> String { pub(crate) fn add_to_url(&self, url: String) -> String {
let mut url = url; let mut url = url;
let mut parameters = Vec::with_capacity(2); let mut parameters = Vec::with_capacity(2);
@ -54,8 +53,7 @@ impl GatewayOptions {
if !has_parameters { if !has_parameters {
url = format!("{}?{}", url, parameter); url = format!("{}?{}", url, parameter);
has_parameters = true; has_parameters = true;
} } else {
else {
url = format!("{}&{}", url, parameter); url = format!("{}&{}", url, parameter);
} }
} }
@ -85,7 +83,7 @@ impl GatewayTransportCompression {
pub(crate) fn to_url_parameter(self) -> Option<String> { pub(crate) fn to_url_parameter(self) -> Option<String> {
match self { match self {
Self::None => None, Self::None => None,
Self::ZLibStream => Some(String::from("compress=zlib-stream")) Self::ZLibStream => Some(String::from("compress=zlib-stream")),
} }
} }
} }
@ -102,7 +100,7 @@ pub enum GatewayEncoding {
/// Should be lighter and faster than json. /// Should be lighter and faster than json.
/// ///
/// !! Chorus does not implement ETF yet !! /// !! Chorus does not implement ETF yet !!
ETF ETF,
} }
impl GatewayEncoding { impl GatewayEncoding {
@ -112,7 +110,7 @@ impl GatewayEncoding {
pub(crate) fn to_url_parameter(self) -> String { pub(crate) fn to_url_parameter(self) -> String {
match self { match self {
Self::Json => String::from("encoding=json"), Self::Json => String::from("encoding=json"),
Self::ETF => String::from("encoding=etf") Self::ETF => String::from("encoding=etf"),
} }
} }
} }

View File

@ -35,24 +35,6 @@ pub struct Instance {
pub gateway_options: GatewayOptions, pub gateway_options: GatewayOptions,
} }
impl PartialEq for Instance {
fn eq(&self, other: &Self) -> bool {
self.urls == other.urls
&& self.instance_info == other.instance_info
&& self.limits_information == other.limits_information
}
}
impl std::hash::Hash for Instance {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.urls.hash(state);
self.instance_info.hash(state);
if let Some(inf) = &self.limits_information {
inf.hash(state);
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq)] #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq)]
pub struct LimitsInformation { pub struct LimitsInformation {
pub ratelimits: HashMap<LimitType, Limit>, pub ratelimits: HashMap<LimitType, Limit>,
@ -69,6 +51,7 @@ impl std::hash::Hash for LimitsInformation {
} }
} }
#[cfg(not(tarpaulin_include))]
impl PartialEq for LimitsInformation { impl PartialEq for LimitsInformation {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.ratelimits.iter().eq(other.ratelimits.iter()) self.ratelimits.iter().eq(other.ratelimits.iter())
@ -175,14 +158,6 @@ pub struct ChorusUser {
pub gateway: GatewayHandle, pub gateway: GatewayHandle,
} }
impl PartialEq for ChorusUser {
fn eq(&self, other: &Self) -> bool {
self.token == other.token
&& self.limits == other.limits
&& self.gateway.url == other.gateway.url
}
}
impl ChorusUser { impl ChorusUser {
pub fn token(&self) -> String { pub fn token(&self) -> String {
self.token.clone() self.token.clone()

View File

@ -98,7 +98,6 @@ This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read
)] )]
#![allow(clippy::module_inception)] #![allow(clippy::module_inception)]
#![deny( #![deny(
missing_debug_implementations,
clippy::extra_unused_lifetimes, clippy::extra_unused_lifetimes,
clippy::from_over_into, clippy::from_over_into,
clippy::needless_borrow, clippy::needless_borrow,
@ -110,7 +109,9 @@ This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read
clippy::unimplemented, clippy::unimplemented,
clippy::dbg_macro, clippy::dbg_macro,
clippy::print_stdout, clippy::print_stdout,
clippy::print_stderr clippy::print_stderr,
missing_debug_implementations,
missing_copy_implementations
)] )]
#[cfg(all(feature = "rt", feature = "rt_multi_thread"))] #[cfg(all(feature = "rt", feature = "rt_multi_thread"))]
compile_error!("feature \"rt\" and feature \"rt_multi_thread\" cannot be enabled at the same time"); compile_error!("feature \"rt\" and feature \"rt_multi_thread\" cannot be enabled at the same time");

View File

@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
use crate::types::config::types::subconfigs::defaults::{guild::GuildDefaults, user::UserDefaults}; use crate::types::config::types::subconfigs::defaults::{guild::GuildDefaults, user::UserDefaults};
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Copy)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct DefaultsConfiguration { pub struct DefaultsConfiguration {
pub guild: GuildDefaults, pub guild: GuildDefaults,

View File

@ -4,7 +4,9 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Copy, Hash, PartialOrd, Ord,
)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct LoginConfiguration { pub struct LoginConfiguration {
pub require_captcha: bool, pub require_captcha: bool,

View File

@ -4,7 +4,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd, Copy, Hash)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct MetricsConfiguration { pub struct MetricsConfiguration {
pub timeout: u64, pub timeout: u64,

View File

@ -4,7 +4,9 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Copy, Hash, PartialOrd, Ord,
)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct PasswordResetConfiguration { pub struct PasswordResetConfiguration {
pub require_captcha: bool, pub require_captcha: bool,

View File

@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
use crate::types::{ExplicitContentFilterLevel, MessageNotificationLevel}; use crate::types::{ExplicitContentFilterLevel, MessageNotificationLevel};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, Hash, PartialOrd, Ord)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct GuildDefaults { pub struct GuildDefaults {
pub max_presences: u64, pub max_presences: u64,

View File

@ -4,7 +4,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, Hash, PartialOrd, Ord)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct UserDefaults { pub struct UserDefaults {
pub premium: bool, pub premium: bool,

View File

@ -4,7 +4,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct DiscoverConfiguration { pub struct DiscoverConfiguration {
pub show_all_guilds: bool, pub show_all_guilds: bool,

View File

@ -4,7 +4,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct ChannelLimits { pub struct ChannelLimits {
pub max_pins: u16, pub max_pins: u16,

View File

@ -4,7 +4,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)]
pub struct GlobalRateLimit { pub struct GlobalRateLimit {
pub limit: u16, pub limit: u16,
pub window: u64, pub window: u64,
@ -21,7 +21,7 @@ impl Default for GlobalRateLimit {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct GlobalRateLimits { pub struct GlobalRateLimits {
pub register: GlobalRateLimit, pub register: GlobalRateLimit,

View File

@ -4,7 +4,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, Hash, PartialOrd, Ord)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct GuildLimits { pub struct GuildLimits {
pub max_roles: u16, pub max_roles: u16,

View File

@ -4,7 +4,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct MessageLimits { pub struct MessageLimits {
pub max_characters: u32, pub max_characters: u32,

View File

@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
use crate::types::config::types::subconfigs::limits::ratelimits::RateLimitOptions; use crate::types::config::types::subconfigs::limits::ratelimits::RateLimitOptions;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)]
pub struct AuthRateLimit { pub struct AuthRateLimit {
pub login: RateLimitOptions, pub login: RateLimitOptions,
pub register: RateLimitOptions, pub register: RateLimitOptions,

View File

@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
pub mod auth; pub mod auth;
pub mod route; pub mod route;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, PartialOrd, Ord, Copy)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct RateLimitOptions { pub struct RateLimitOptions {
pub bot: Option<u64>, pub bot: Option<u64>,

View File

@ -8,7 +8,7 @@ use crate::types::config::types::subconfigs::limits::ratelimits::{
auth::AuthRateLimit, RateLimitOptions, auth::AuthRateLimit, RateLimitOptions,
}; };
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Copy, PartialOrd, Ord)]
pub struct RouteRateLimit { pub struct RouteRateLimit {
pub guild: RateLimitOptions, pub guild: RateLimitOptions,
pub webhook: RateLimitOptions, pub webhook: RateLimitOptions,

View File

@ -50,14 +50,14 @@ impl Default for RateLimits {
impl RateLimits { impl RateLimits {
pub fn to_hash_map(&self) -> HashMap<LimitType, RateLimitOptions> { pub fn to_hash_map(&self) -> HashMap<LimitType, RateLimitOptions> {
let mut map = HashMap::new(); let mut map = HashMap::new();
map.insert(LimitType::AuthLogin, self.routes.auth.login.clone()); map.insert(LimitType::AuthLogin, self.routes.auth.login);
map.insert(LimitType::AuthRegister, self.routes.auth.register.clone()); map.insert(LimitType::AuthRegister, self.routes.auth.register);
map.insert(LimitType::ChannelBaseline, self.routes.channel.clone()); map.insert(LimitType::ChannelBaseline, self.routes.channel);
map.insert(LimitType::Error, self.error.clone()); map.insert(LimitType::Error, self.error);
map.insert(LimitType::Global, self.global.clone()); map.insert(LimitType::Global, self.global);
map.insert(LimitType::Ip, self.ip.clone()); map.insert(LimitType::Ip, self.ip);
map.insert(LimitType::WebhookBaseline, self.routes.webhook.clone()); map.insert(LimitType::WebhookBaseline, self.routes.webhook);
map.insert(LimitType::GuildBaseline, self.routes.guild.clone()); map.insert(LimitType::GuildBaseline, self.routes.guild);
map map
} }
} }

View File

@ -4,7 +4,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord, Copy, Hash)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct UserLimits { pub struct UserLimits {
pub max_guilds: u64, pub max_guilds: u64,

View File

@ -4,13 +4,13 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, PartialOrd, Copy)]
pub struct LatLong { pub struct LatLong {
pub latitude: f64, pub latitude: f64,
pub longitude: f64, pub longitude: f64,
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, PartialOrd)]
pub struct Region { pub struct Region {
pub id: String, pub id: String,
pub name: String, pub name: String,

View File

@ -4,7 +4,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)]
pub struct DateOfBirthConfiguration { pub struct DateOfBirthConfiguration {
pub required: bool, pub required: bool,
pub minimum: u8, pub minimum: u8,

View File

@ -4,7 +4,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct PasswordConfiguration { pub struct PasswordConfiguration {
pub required: bool, pub required: bool,

View File

@ -4,7 +4,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, Hash, PartialOrd, Ord)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct TwoFactorConfiguration { pub struct TwoFactorConfiguration {
pub generate_backup_codes: bool, pub generate_backup_codes: bool,

View File

@ -4,7 +4,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct TemplateConfiguration { pub struct TemplateConfiguration {
pub enabled: bool, pub enabled: bool,

View File

@ -7,10 +7,13 @@ use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::types::Shared;
use crate::types::utils::Snowflake; use crate::types::utils::Snowflake;
use crate::types::Shared;
use crate::types::{Team, User}; use crate::types::{Team, User};
#[allow(unused_imports)]
use super::{arc_rwlock_ptr_eq, option_arc_rwlock_ptr_eq};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// # Reference /// # Reference
@ -59,6 +62,61 @@ pub struct Application {
pub team: Option<Team>, pub team: Option<Team>,
} }
#[cfg(not(tarpaulin_include))]
impl PartialEq for Application {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
&& self.name == other.name
&& self.icon == other.icon
&& self.description == other.description
&& self.summary == other.summary
&& self.r#type == other.r#type
&& self.hook == other.hook
&& self.bot_public == other.bot_public
&& self.bot_require_code_grant == other.bot_require_code_grant
&& self.verify_key == other.verify_key
&& arc_rwlock_ptr_eq(&self.owner, &other.owner)
&& self.flags == other.flags
&& self.redirect_uris == other.redirect_uris
&& self.rpc_application_state == other.rpc_application_state
&& self.store_application_state == other.store_application_state
&& self.verification_state == other.verification_state
&& self.interactions_endpoint_url == other.interactions_endpoint_url
&& self.integration_public == other.integration_public
&& self.integration_require_code_grant == other.integration_require_code_grant
&& self.discoverability_state == other.discoverability_state
&& self.discovery_eligibility_flags == other.discovery_eligibility_flags
&& self.tags == other.tags
&& self.cover_image == other.cover_image
&& compare_install_params(&self.install_params, &other.install_params)
&& self.terms_of_service_url == other.terms_of_service_url
&& self.privacy_policy_url == other.privacy_policy_url
&& self.team == other.team
}
}
#[cfg(not(tarpaulin_include))]
#[cfg(feature = "sqlx")]
fn compare_install_params(
a: &Option<sqlx::types::Json<InstallParams>>,
b: &Option<sqlx::types::Json<InstallParams>>,
) -> bool {
match (a, b) {
(Some(a), Some(b)) => a.encode_to_string() == b.encode_to_string(),
(None, None) => true,
_ => false,
}
}
#[cfg(not(tarpaulin_include))]
#[cfg(not(feature = "sqlx"))]
fn compare_install_params(
a: &Option<Shared<InstallParams>>,
b: &Option<Shared<InstallParams>>,
) -> bool {
option_arc_rwlock_ptr_eq(a, b)
}
impl Default for Application { impl Default for Application {
fn default() -> Self { fn default() -> Self {
Self { Self {
@ -207,7 +265,9 @@ pub struct GuildApplicationCommandPermissions {
pub permissions: Vec<Shared<ApplicationCommandPermission>>, pub permissions: Vec<Shared<ApplicationCommandPermission>>,
} }
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] #[derive(
Debug, Default, Clone, PartialEq, Serialize, Deserialize, Copy, Eq, Hash, PartialOrd, Ord,
)]
/// See <https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permissions-structure> /// See <https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permissions-structure>
pub struct ApplicationCommandPermission { pub struct ApplicationCommandPermission {
pub id: Snowflake, pub id: Snowflake,
@ -217,7 +277,19 @@ pub struct ApplicationCommandPermission {
pub permission: bool, pub permission: bool,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, PartialEq, Eq, Hash)] #[derive(
Serialize_repr,
Deserialize_repr,
Debug,
Default,
Clone,
PartialEq,
Eq,
Hash,
Copy,
PartialOrd,
Ord,
)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[repr(u8)] #[repr(u8)]
/// See <https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permission-type> /// See <https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permission-type>

View File

@ -2,11 +2,16 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this // License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
#[allow(unused_imports)]
use super::option_vec_arc_rwlock_ptr_eq;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::types::{AutoModerationRuleTriggerType, IntegrationType, PermissionOverwriteType, Shared};
use crate::types::utils::Snowflake; use crate::types::utils::Snowflake;
use crate::types::{
AutoModerationRuleTriggerType, IntegrationType, PermissionOverwriteType, Shared,
};
#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
@ -27,6 +32,55 @@ pub struct AuditLogEntry {
pub reason: Option<String>, pub reason: Option<String>,
} }
impl PartialEq for AuditLogEntry {
fn eq(&self, other: &Self) -> bool {
self.target_id == other.target_id
&& self.user_id == other.user_id
&& self.id == other.id
&& self.action_type == other.action_type
&& compare_options(&self.options, &other.options)
&& self.reason == other.reason
&& compare_changes(&self.changes, &other.changes)
}
}
#[cfg(not(tarpaulin_include))]
#[cfg(feature = "sqlx")]
fn compare_options(
a: &Option<sqlx::types::Json<AuditEntryInfo>>,
b: &Option<sqlx::types::Json<AuditEntryInfo>>,
) -> bool {
match (a, b) {
(Some(a), Some(b)) => a.encode_to_string() == b.encode_to_string(),
(None, None) => true,
_ => false,
}
}
#[cfg(not(tarpaulin_include))]
#[cfg(not(feature = "sqlx"))]
fn compare_options(a: &Option<AuditEntryInfo>, b: &Option<AuditEntryInfo>) -> bool {
a == b
}
#[cfg(not(tarpaulin_include))]
#[cfg(feature = "sqlx")]
fn compare_changes(
a: &sqlx::types::Json<Option<Vec<Shared<AuditLogChange>>>>,
b: &sqlx::types::Json<Option<Vec<Shared<AuditLogChange>>>>,
) -> bool {
a.encode_to_string() == b.encode_to_string()
}
#[cfg(not(tarpaulin_include))]
#[cfg(not(feature = "sqlx"))]
fn compare_changes(
a: &Option<Vec<Shared<AuditLogChange>>>,
b: &Option<Vec<Shared<AuditLogChange>>>,
) -> bool {
option_vec_arc_rwlock_ptr_eq(a, b)
}
#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
/// See <https://discord.com/developers/docs/resources/audit-log#audit-log-change-object> /// See <https://discord.com/developers/docs/resources/audit-log#audit-log-change-object>
pub struct AuditLogChange { pub struct AuditLogChange {
@ -35,8 +89,19 @@ pub struct AuditLogChange {
pub key: String, pub key: String,
} }
#[derive(
#[derive(Default, Serialize_repr, Deserialize_repr, Debug, Clone, Copy)] Default,
Serialize_repr,
Deserialize_repr,
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
)]
#[repr(u8)] #[repr(u8)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
/// # Reference: /// # Reference:
@ -170,10 +235,10 @@ pub enum AuditLogActionType {
/// Voice channel status was updated /// Voice channel status was updated
VoiceChannelStatusUpdate = 192, VoiceChannelStatusUpdate = 192,
/// Voice channel status was deleted /// Voice channel status was deleted
VoiceChannelStatusDelete = 193 VoiceChannelStatusDelete = 193,
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
pub struct AuditEntryInfo { pub struct AuditEntryInfo {
pub application_id: Option<Snowflake>, pub application_id: Option<Snowflake>,
pub auto_moderation_rule_name: Option<String>, pub auto_moderation_rule_name: Option<String>,
@ -193,5 +258,5 @@ pub struct AuditEntryInfo {
pub role_name: Option<String>, pub role_name: Option<String>,
#[serde(rename = "type")] #[serde(rename = "type")]
pub overwrite_type: Option<PermissionOverwriteType>, pub overwrite_type: Option<PermissionOverwriteType>,
pub status: Option<String> pub status: Option<String>,
} }

View File

@ -2,9 +2,9 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this // License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
use crate::types::Shared;
#[cfg(feature = "client")] #[cfg(feature = "client")]
use crate::gateway::Updateable; use crate::gateway::Updateable;
use crate::types::Shared;
#[cfg(feature = "client")] #[cfg(feature = "client")]
use chorus_macros::Updateable; use chorus_macros::Updateable;
@ -31,7 +31,7 @@ pub struct AutoModerationRule {
pub exempt_channels: Vec<Snowflake>, pub exempt_channels: Vec<Snowflake>,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default, Copy)]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
/// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-event-types> /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-event-types>
@ -40,7 +40,9 @@ pub enum AutoModerationRuleEventType {
MessageSend = 1, MessageSend = 1,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] #[derive(
Serialize_repr, Deserialize_repr, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy,
)]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
/// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-types> /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-types>
@ -52,7 +54,7 @@ pub enum AutoModerationRuleTriggerType {
MentionSpam = 5, MentionSpam = 5,
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
#[serde(untagged)] #[serde(untagged)]
/// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata> /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata>
pub enum AutoModerationRuleTriggerMetadata { pub enum AutoModerationRuleTriggerMetadata {
@ -63,7 +65,7 @@ pub enum AutoModerationRuleTriggerMetadata {
None, None,
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
/// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata> /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata>
pub struct AutoModerationRuleTriggerMetadataForKeyword { pub struct AutoModerationRuleTriggerMetadataForKeyword {
pub keyword_filter: Vec<String>, pub keyword_filter: Vec<String>,
@ -71,14 +73,14 @@ pub struct AutoModerationRuleTriggerMetadataForKeyword {
pub allow_list: Vec<String>, pub allow_list: Vec<String>,
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
/// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata> /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata>
pub struct AutoModerationRuleTriggerMetadataForKeywordPreset { pub struct AutoModerationRuleTriggerMetadataForKeywordPreset {
pub presets: Vec<AutoModerationRuleKeywordPresetType>, pub presets: Vec<AutoModerationRuleKeywordPresetType>,
pub allow_list: Vec<String>, pub allow_list: Vec<String>,
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy)]
/// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata> /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata>
pub struct AutoModerationRuleTriggerMetadataForMentionSpam { pub struct AutoModerationRuleTriggerMetadataForMentionSpam {
/// Max 50 /// Max 50
@ -86,7 +88,9 @@ pub struct AutoModerationRuleTriggerMetadataForMentionSpam {
pub mention_raid_protection_enabled: bool, pub mention_raid_protection_enabled: bool,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] #[derive(
Serialize_repr, Deserialize_repr, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy,
)]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
/// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-keyword-preset-types> /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-keyword-preset-types>
@ -105,7 +109,9 @@ pub struct AutoModerationAction {
pub metadata: Option<Shared<AutoModerationActionMetadata>>, pub metadata: Option<Shared<AutoModerationActionMetadata>>,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] #[derive(
Serialize_repr, Deserialize_repr, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy, Hash
)]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
/// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-types> /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-types>
@ -116,7 +122,7 @@ pub enum AutoModerationActionType {
Timeout = 3, Timeout = 3,
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
#[serde(untagged)] #[serde(untagged)]
/// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata> /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata>
pub enum AutoModerationActionMetadata { pub enum AutoModerationActionMetadata {
@ -127,19 +133,19 @@ pub enum AutoModerationActionMetadata {
None, None,
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
/// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata> /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata>
pub struct AutoModerationActionMetadataForBlockMessage { pub struct AutoModerationActionMetadataForBlockMessage {
pub custom_message: Option<String>, pub custom_message: Option<String>,
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy)]
/// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata> /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata>
pub struct AutoModerationActionMetadataForSendAlertMessage { pub struct AutoModerationActionMetadataForSendAlertMessage {
pub channel_id: Snowflake, pub channel_id: Snowflake,
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy)]
/// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata> /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata>
pub struct AutoModerationActionMetadataForTimeout { pub struct AutoModerationActionMetadataForTimeout {
/// Max 2419200 /// Max 2419200

View File

@ -9,10 +9,9 @@ use std::fmt::{Debug, Formatter};
use std::str::FromStr; use std::str::FromStr;
use crate::types::{ use crate::types::{
PermissionFlags, Shared,
entities::{GuildMember, User}, entities::{GuildMember, User},
utils::Snowflake, utils::Snowflake,
serde::string_or_u64 PermissionFlags, Shared,
}; };
#[cfg(feature = "client")] #[cfg(feature = "client")]
@ -28,6 +27,10 @@ use crate::gateway::Updateable;
use chorus_macros::{observe_option_vec, Composite, Updateable}; use chorus_macros::{observe_option_vec, Composite, Updateable};
use serde::de::{Error, Visitor}; use serde::de::{Error, Visitor};
#[cfg(feature = "sqlx")]
use sqlx::types::Json;
use super::{option_arc_rwlock_ptr_eq, option_vec_arc_rwlock_ptr_eq};
#[derive(Default, Debug, Serialize, Deserialize, Clone)] #[derive(Default, Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
@ -97,14 +100,22 @@ pub struct Channel {
pub video_quality_mode: Option<i32>, pub video_quality_mode: Option<i32>,
} }
#[cfg(not(tarpaulin_include))]
#[allow(clippy::nonminimal_bool)]
impl PartialEq for Channel { impl PartialEq for Channel {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.application_id == other.application_id self.application_id == other.application_id
&& self.applied_tags == other.applied_tags
&& self.applied_tags == other.applied_tags
&& self.available_tags == other.available_tags
&& self.available_tags == other.available_tags
&& self.bitrate == other.bitrate && self.bitrate == other.bitrate
&& self.channel_type == other.channel_type && self.channel_type == other.channel_type
&& self.created_at == other.created_at && self.created_at == other.created_at
&& self.default_auto_archive_duration == other.default_auto_archive_duration && self.default_auto_archive_duration == other.default_auto_archive_duration
&& self.default_forum_layout == other.default_forum_layout && self.default_forum_layout == other.default_forum_layout
&& self.default_reaction_emoji == other.default_reaction_emoji
&& self.default_reaction_emoji == other.default_reaction_emoji
&& self.default_sort_order == other.default_sort_order && self.default_sort_order == other.default_sort_order
&& self.default_thread_rate_limit_per_user == other.default_thread_rate_limit_per_user && self.default_thread_rate_limit_per_user == other.default_thread_rate_limit_per_user
&& self.flags == other.flags && self.flags == other.flags
@ -114,16 +125,23 @@ impl PartialEq for Channel {
&& self.last_message_id == other.last_message_id && self.last_message_id == other.last_message_id
&& self.last_pin_timestamp == other.last_pin_timestamp && self.last_pin_timestamp == other.last_pin_timestamp
&& self.managed == other.managed && self.managed == other.managed
&& self.member == other.member
&& self.member_count == other.member_count && self.member_count == other.member_count
&& self.message_count == other.message_count && self.message_count == other.message_count
&& self.name == other.name && self.name == other.name
&& self.nsfw == other.nsfw && self.nsfw == other.nsfw
&& self.owner_id == other.owner_id && self.owner_id == other.owner_id
&& self.parent_id == other.parent_id && self.parent_id == other.parent_id
&& compare_permission_overwrites(
&self.permission_overwrites,
&other.permission_overwrites,
)
&& self.permissions == other.permissions && self.permissions == other.permissions
&& self.position == other.position && self.position == other.position
&& self.rate_limit_per_user == other.rate_limit_per_user && self.rate_limit_per_user == other.rate_limit_per_user
&& option_vec_arc_rwlock_ptr_eq(&self.recipients, &other.recipients)
&& self.rtc_region == other.rtc_region && self.rtc_region == other.rtc_region
&& self.thread_metadata == other.thread_metadata
&& self.topic == other.topic && self.topic == other.topic
&& self.total_message_sent == other.total_message_sent && self.total_message_sent == other.total_message_sent
&& self.user_limit == other.user_limit && self.user_limit == other.user_limit
@ -131,7 +149,29 @@ impl PartialEq for Channel {
} }
} }
#[derive(Debug, Deserialize, Serialize, Clone)] #[cfg(not(tarpaulin_include))]
#[cfg(feature = "sqlx")]
fn compare_permission_overwrites(
a: &Option<Json<Vec<PermissionOverwrite>>>,
b: &Option<Json<Vec<PermissionOverwrite>>>,
) -> bool {
match (a, b) {
(Some(a), Some(b)) => a.encode_to_string() == b.encode_to_string(),
(None, None) => true,
_ => false,
}
}
#[cfg(not(tarpaulin_include))]
#[cfg(not(feature = "sqlx"))]
fn compare_permission_overwrites(
a: &Option<Vec<Shared<PermissionOverwrite>>>,
b: &Option<Vec<Shared<PermissionOverwrite>>>,
) -> bool {
option_vec_arc_rwlock_ptr_eq(a, b)
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
/// A tag that can be applied to a thread in a [ChannelType::GuildForum] or [ChannelType::GuildMedia] channel. /// A tag that can be applied to a thread in a [ChannelType::GuildForum] or [ChannelType::GuildMedia] channel.
/// ///
/// # Reference /// # Reference
@ -158,8 +198,7 @@ pub struct PermissionOverwrite {
pub deny: PermissionFlags, pub deny: PermissionFlags,
} }
#[derive(Debug, Serialize_repr, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
#[derive(Debug, Serialize_repr, Clone, PartialEq, Eq, PartialOrd)]
#[repr(u8)] #[repr(u8)]
/// # Reference /// # Reference
/// ///
@ -200,33 +239,47 @@ impl<'de> Visitor<'de> for PermissionOverwriteTypeVisitor {
formatter.write_str("a valid permission overwrite type") formatter.write_str("a valid permission overwrite type")
} }
fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E> where E: Error { fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
where
E: Error,
{
Ok(PermissionOverwriteType::from(v)) Ok(PermissionOverwriteType::from(v))
} }
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> where E: Error { fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: Error,
{
self.visit_u8(v as u8) self.visit_u8(v as u8)
} }
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> where E: Error { fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
PermissionOverwriteType::from_str(v) where
.map_err(E::custom) E: Error,
{
PermissionOverwriteType::from_str(v).map_err(E::custom)
} }
fn visit_string<E>(self, v: String) -> Result<Self::Value, E> where E: Error { fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: Error,
{
self.visit_str(v.as_str()) self.visit_str(v.as_str())
} }
} }
impl<'de> Deserialize<'de> for PermissionOverwriteType { impl<'de> Deserialize<'de> for PermissionOverwriteType {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let val = deserializer.deserialize_any(PermissionOverwriteTypeVisitor)?; let val = deserializer.deserialize_any(PermissionOverwriteTypeVisitor)?;
Ok(val) Ok(val)
} }
} }
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
/// # Reference /// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/channel#thread-metadata-object> /// See <https://discord-userdoccers.vercel.app/resources/channel#thread-metadata-object>
pub struct ThreadMetadata { pub struct ThreadMetadata {
@ -249,6 +302,17 @@ pub struct ThreadMember {
pub member: Option<Shared<GuildMember>>, pub member: Option<Shared<GuildMember>>,
} }
#[cfg(not(tarpaulin_include))]
impl PartialEq for ThreadMember {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
&& self.user_id == other.user_id
&& self.join_timestamp == other.join_timestamp
&& self.flags == other.flags
&& option_arc_rwlock_ptr_eq(&self.member, &other.member)
}
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd)]
/// Specifies the emoji to use as the default way to react to a [ChannelType::GuildForum] or [ChannelType::GuildMedia] channel post. /// Specifies the emoji to use as the default way to react to a [ChannelType::GuildForum] or [ChannelType::GuildMedia] channel post.
/// ///
@ -329,11 +393,10 @@ pub enum ChannelType {
Unhandled = 255, Unhandled = 255,
} }
/// # Reference /// # Reference
/// See <https://docs.discord.sex/resources/message#followed-channel-object> /// See <https://docs.discord.sex/resources/message#followed-channel-object>
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Copy, Hash, PartialOrd, Ord)]
pub struct FollowedChannel { pub struct FollowedChannel {
pub channel_id: Snowflake, pub channel_id: Snowflake,
pub webhook_id: Snowflake pub webhook_id: Snowflake,
} }

View File

@ -6,9 +6,9 @@ use std::fmt::Debug;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::{PartialEmoji, Shared};
use crate::types::entities::User; use crate::types::entities::User;
use crate::types::Snowflake; use crate::types::Snowflake;
use crate::types::{PartialEmoji, Shared};
#[cfg(feature = "client")] #[cfg(feature = "client")]
use crate::gateway::GatewayHandle; use crate::gateway::GatewayHandle;
@ -22,6 +22,8 @@ use crate::gateway::Updateable;
#[cfg(feature = "client")] #[cfg(feature = "client")]
use chorus_macros::{Composite, Updateable}; use chorus_macros::{Composite, Updateable};
use super::option_arc_rwlock_ptr_eq;
#[derive(Debug, Clone, Deserialize, Serialize, Default)] #[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[cfg_attr(feature = "client", derive(Updateable, Composite))] #[cfg_attr(feature = "client", derive(Updateable, Composite))]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
@ -42,35 +44,26 @@ pub struct Emoji {
pub available: Option<bool>, pub available: Option<bool>,
} }
impl std::hash::Hash for Emoji { #[cfg(not(tarpaulin_include))]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { #[allow(clippy::nonminimal_bool)]
self.id.hash(state);
self.name.hash(state);
self.roles.hash(state);
self.roles.hash(state);
self.require_colons.hash(state);
self.managed.hash(state);
self.animated.hash(state);
self.available.hash(state);
}
}
impl PartialEq for Emoji { impl PartialEq for Emoji {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
!(self.id != other.id self.id == other.id
|| self.name != other.name && self.name == other.name
|| self.roles != other.roles && self.roles == other.roles
|| self.require_colons != other.require_colons && self.roles == other.roles
|| self.managed != other.managed && option_arc_rwlock_ptr_eq(&self.user, &other.user)
|| self.animated != other.animated && self.require_colons == other.require_colons
|| self.available != other.available) && self.managed == other.managed
&& self.animated == other.animated
&& self.available == other.available
} }
} }
impl From<PartialEmoji> for Emoji { impl From<PartialEmoji> for Emoji {
fn from(value: PartialEmoji) -> Self { fn from(value: PartialEmoji) -> Self {
Self { Self {
id: value.id.unwrap_or_default(), // TODO: this should be handled differently id: value.id.unwrap_or_default(), // TODO: Make this method an impl to TryFrom<> instead
name: Some(value.name), name: Some(value.name),
roles: None, roles: None,
user: None, user: None,

View File

@ -3,21 +3,22 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
use std::fmt::Debug; use std::fmt::Debug;
use std::hash::Hash;
use bitflags::bitflags; use bitflags::bitflags;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::types::Shared;
use crate::types::types::guild_configuration::GuildFeaturesList; use crate::types::types::guild_configuration::GuildFeaturesList;
use crate::types::Shared;
use crate::types::{ use crate::types::{
entities::{Channel, Emoji, RoleObject, Sticker, User, VoiceState, Webhook}, entities::{Channel, Emoji, RoleObject, Sticker, User, VoiceState, Webhook},
interfaces::WelcomeScreenObject, interfaces::WelcomeScreenObject,
utils::Snowflake, utils::Snowflake,
}; };
use super::PublicUser; use super::{option_arc_rwlock_ptr_eq, vec_arc_rwlock_ptr_eq, PublicUser};
#[cfg(feature = "client")] #[cfg(feature = "client")]
use crate::gateway::Updateable; use crate::gateway::Updateable;
@ -126,59 +127,8 @@ pub struct Guild {
pub widget_enabled: Option<bool>, pub widget_enabled: Option<bool>,
} }
impl std::hash::Hash for Guild { #[cfg(not(tarpaulin_include))]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { impl PartialEq for Guild {
self.afk_channel_id.hash(state);
self.afk_timeout.hash(state);
self.application_id.hash(state);
self.approximate_member_count.hash(state);
self.approximate_presence_count.hash(state);
self.banner.hash(state);
self.bans.hash(state);
self.default_message_notifications.hash(state);
self.description.hash(state);
self.discovery_splash.hash(state);
self.explicit_content_filter.hash(state);
self.features.hash(state);
self.icon.hash(state);
self.icon_hash.hash(state);
self.id.hash(state);
self.invites.hash(state);
self.joined_at.hash(state);
self.large.hash(state);
self.max_members.hash(state);
self.max_presences.hash(state);
self.max_stage_video_channel_users.hash(state);
self.max_video_channel_users.hash(state);
self.mfa_level.hash(state);
self.name.hash(state);
self.nsfw_level.hash(state);
self.owner.hash(state);
self.owner_id.hash(state);
self.permissions.hash(state);
self.preferred_locale.hash(state);
self.premium_progress_bar_enabled.hash(state);
self.premium_subscription_count.hash(state);
self.premium_tier.hash(state);
self.primary_category_id.hash(state);
self.public_updates_channel_id.hash(state);
self.region.hash(state);
self.rules_channel.hash(state);
self.rules_channel_id.hash(state);
self.splash.hash(state);
self.stickers.hash(state);
self.system_channel_flags.hash(state);
self.system_channel_id.hash(state);
self.vanity_url_code.hash(state);
self.verification_level.hash(state);
self.welcome_screen.hash(state);
self.welcome_screen.hash(state);
self.widget_channel_id.hash(state);
self.widget_enabled.hash(state);
}
}
impl std::cmp::PartialEq for Guild {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.afk_channel_id == other.afk_channel_id self.afk_channel_id == other.afk_channel_id
&& self.afk_timeout == other.afk_timeout && self.afk_timeout == other.afk_timeout
@ -187,14 +137,17 @@ impl std::cmp::PartialEq for Guild {
&& self.approximate_presence_count == other.approximate_presence_count && self.approximate_presence_count == other.approximate_presence_count
&& self.banner == other.banner && self.banner == other.banner
&& self.bans == other.bans && self.bans == other.bans
&& vec_arc_rwlock_ptr_eq(&self.channels, &other.channels)
&& self.default_message_notifications == other.default_message_notifications && self.default_message_notifications == other.default_message_notifications
&& self.description == other.description && self.description == other.description
&& self.discovery_splash == other.discovery_splash && self.discovery_splash == other.discovery_splash
&& vec_arc_rwlock_ptr_eq(&self.emojis, &other.emojis)
&& self.explicit_content_filter == other.explicit_content_filter && self.explicit_content_filter == other.explicit_content_filter
&& self.features == other.features && self.features == other.features
&& self.icon == other.icon && self.icon == other.icon
&& self.icon_hash == other.icon_hash && self.icon_hash == other.icon_hash
&& self.id == other.id && self.id == other.id
&& self.invites == other.invites
&& self.joined_at == other.joined_at && self.joined_at == other.joined_at
&& self.large == other.large && self.large == other.large
&& self.max_members == other.max_members && self.max_members == other.max_members
@ -214,6 +167,7 @@ impl std::cmp::PartialEq for Guild {
&& self.primary_category_id == other.primary_category_id && self.primary_category_id == other.primary_category_id
&& self.public_updates_channel_id == other.public_updates_channel_id && self.public_updates_channel_id == other.public_updates_channel_id
&& self.region == other.region && self.region == other.region
&& vec_arc_rwlock_ptr_eq(&self.roles, &other.roles)
&& self.rules_channel == other.rules_channel && self.rules_channel == other.rules_channel
&& self.rules_channel_id == other.rules_channel_id && self.rules_channel_id == other.rules_channel_id
&& self.splash == other.splash && self.splash == other.splash
@ -222,6 +176,8 @@ impl std::cmp::PartialEq for Guild {
&& self.system_channel_id == other.system_channel_id && self.system_channel_id == other.system_channel_id
&& self.vanity_url_code == other.vanity_url_code && self.vanity_url_code == other.vanity_url_code
&& self.verification_level == other.verification_level && self.verification_level == other.verification_level
&& vec_arc_rwlock_ptr_eq(&self.voice_states, &other.voice_states)
&& vec_arc_rwlock_ptr_eq(&self.webhooks, &other.webhooks)
&& self.welcome_screen == other.welcome_screen && self.welcome_screen == other.welcome_screen
&& self.welcome_screen == other.welcome_screen && self.welcome_screen == other.welcome_screen
&& self.widget_channel_id == other.widget_channel_id && self.widget_channel_id == other.widget_channel_id
@ -261,32 +217,36 @@ pub struct GuildInvite {
pub vanity_url: Option<bool>, pub vanity_url: Option<bool>,
} }
impl std::hash::Hash for GuildInvite { #[cfg(not(tarpaulin_include))]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { impl PartialEq for GuildInvite {
self.code.hash(state); fn eq(&self, other: &Self) -> bool {
self.temporary.hash(state); self.code == other.code
self.uses.hash(state); && self.temporary == other.temporary
self.max_uses.hash(state); && self.uses == other.uses
self.max_age.hash(state); && self.max_uses == other.max_uses
self.created_at.hash(state); && self.max_age == other.max_age
self.expires_at.hash(state); && self.created_at == other.created_at
self.guild_id.hash(state); && self.expires_at == other.expires_at
self.channel_id.hash(state); && self.guild_id == other.guild_id
self.inviter_id.hash(state); && option_arc_rwlock_ptr_eq(&self.guild, &other.guild)
self.target_user_id.hash(state); && self.channel_id == other.channel_id
self.target_user.hash(state); && option_arc_rwlock_ptr_eq(&self.channel, &other.channel)
self.target_user_type.hash(state); && self.inviter_id == other.inviter_id
self.vanity_url.hash(state); && option_arc_rwlock_ptr_eq(&self.inviter, &other.inviter)
&& self.target_user_id == other.target_user_id
&& self.target_user == other.target_user
&& self.target_user_type == other.target_user_type
&& self.vanity_url == other.vanity_url
} }
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Hash)] #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Hash, Eq, PartialOrd, Ord, Copy)]
pub struct UnavailableGuild { pub struct UnavailableGuild {
pub id: Snowflake, pub id: Snowflake,
pub unavailable: bool, pub unavailable: bool,
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
pub struct GuildCreateResponse { pub struct GuildCreateResponse {
pub id: Snowflake, pub id: Snowflake,
} }
@ -312,7 +272,29 @@ pub struct GuildScheduledEvent {
pub image: Option<String>, pub image: Option<String>,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone)] #[cfg(not(tarpaulin_include))]
impl PartialEq for GuildScheduledEvent {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
&& self.guild_id == other.guild_id
&& self.channel_id == other.channel_id
&& self.creator_id == other.creator_id
&& self.name == other.name
&& self.description == other.description
&& self.scheduled_start_time == other.scheduled_start_time
&& self.scheduled_end_time == other.scheduled_end_time
&& self.privacy_level == other.privacy_level
&& self.status == other.status
&& self.entity_type == other.entity_type
&& self.entity_id == other.entity_id
&& self.entity_metadata == other.entity_metadata
&& option_arc_rwlock_ptr_eq(&self.creator, &other.creator)
&& self.user_count == other.user_count
&& self.image == other.image
}
}
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, PartialEq, Copy)]
#[repr(u8)] #[repr(u8)]
/// See <https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-privacy-level> /// See <https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-privacy-level>
pub enum GuildScheduledEventPrivacyLevel { pub enum GuildScheduledEventPrivacyLevel {
@ -320,7 +302,7 @@ pub enum GuildScheduledEventPrivacyLevel {
GuildOnly = 2, GuildOnly = 2,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone)] #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, PartialEq, Copy)]
#[repr(u8)] #[repr(u8)]
/// See <https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-status> /// See <https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-status>
pub enum GuildScheduledEventStatus { pub enum GuildScheduledEventStatus {
@ -331,7 +313,19 @@ pub enum GuildScheduledEventStatus {
Canceled = 4, Canceled = 4,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone)] #[derive(
Serialize_repr,
Deserialize_repr,
Debug,
Default,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Copy,
Hash,
)]
#[repr(u8)] #[repr(u8)]
/// See <https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-types> /// See <https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-types>
pub enum GuildScheduledEventEntityType { pub enum GuildScheduledEventEntityType {
@ -341,7 +335,7 @@ pub enum GuildScheduledEventEntityType {
External = 3, External = 3,
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
/// See <https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-metadata> /// See <https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-metadata>
pub struct GuildScheduledEventEntityMetadata { pub struct GuildScheduledEventEntityMetadata {
pub location: Option<String>, pub location: Option<String>,
@ -356,7 +350,19 @@ pub struct VoiceRegion {
custom: bool, custom: bool,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)] #[derive(
Serialize_repr,
Deserialize_repr,
Debug,
Default,
Clone,
Eq,
PartialEq,
Hash,
Copy,
PartialOrd,
Ord,
)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
@ -367,7 +373,19 @@ pub enum MessageNotificationLevel {
OnlyMentions = 1, OnlyMentions = 1,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)] #[derive(
Serialize_repr,
Deserialize_repr,
Debug,
Default,
Clone,
Eq,
PartialEq,
Hash,
Copy,
PartialOrd,
Ord,
)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
@ -379,7 +397,19 @@ pub enum ExplicitContentFilterLevel {
AllMembers = 2, AllMembers = 2,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)] #[derive(
Serialize_repr,
Deserialize_repr,
Debug,
Default,
Clone,
Eq,
PartialEq,
Hash,
Copy,
PartialOrd,
Ord,
)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
@ -393,7 +423,19 @@ pub enum VerificationLevel {
VeryHigh = 4, VeryHigh = 4,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)] #[derive(
Serialize_repr,
Deserialize_repr,
Debug,
Default,
Clone,
Eq,
PartialEq,
Hash,
Copy,
PartialOrd,
Ord,
)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
@ -404,7 +446,19 @@ pub enum MFALevel {
Elevated = 1, Elevated = 1,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)] #[derive(
Serialize_repr,
Deserialize_repr,
Debug,
Default,
Clone,
Eq,
PartialEq,
Hash,
Copy,
PartialOrd,
Ord,
)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
@ -417,7 +471,19 @@ pub enum NSFWLevel {
AgeRestricted = 3, AgeRestricted = 3,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)] #[derive(
Serialize_repr,
Deserialize_repr,
Debug,
Default,
Clone,
Eq,
PartialEq,
Hash,
Copy,
PartialOrd,
Ord,
)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]

View File

@ -5,8 +5,10 @@
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::{GuildMemberFlags, PermissionFlags, Shared};
use crate::types::{entities::PublicUser, Snowflake}; use crate::types::{entities::PublicUser, Snowflake};
use crate::types::{GuildMemberFlags, PermissionFlags, Shared};
use super::option_arc_rwlock_ptr_eq;
#[derive(Debug, Deserialize, Default, Serialize, Clone)] #[derive(Debug, Deserialize, Default, Serialize, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
@ -31,3 +33,21 @@ pub struct GuildMember {
pub permissions: PermissionFlags, pub permissions: PermissionFlags,
pub communication_disabled_until: Option<DateTime<Utc>>, pub communication_disabled_until: Option<DateTime<Utc>>,
} }
#[cfg(not(tarpaulin_include))]
impl PartialEq for GuildMember {
fn eq(&self, other: &Self) -> bool {
self.nick == other.nick
&& self.avatar == other.avatar
&& self.roles == other.roles
&& self.joined_at == other.joined_at
&& self.premium_since == other.premium_since
&& self.deaf == other.deaf
&& self.mute == other.mute
&& self.flags == other.flags
&& self.pending == other.pending
&& self.permissions == other.permissions
&& self.communication_disabled_until == other.communication_disabled_until
&& option_arc_rwlock_ptr_eq(&self.user, &other.user)
}
}

View File

@ -6,9 +6,9 @@ use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::{ use crate::types::{
Shared,
entities::{Application, User}, entities::{Application, User},
utils::Snowflake, utils::Snowflake,
Shared,
}; };
#[derive(Default, Debug, Deserialize, Serialize, Clone)] #[derive(Default, Debug, Deserialize, Serialize, Clone)]
@ -44,7 +44,9 @@ pub struct IntegrationAccount {
pub name: String, pub name: String,
} }
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)] #[derive(
Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash,
)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[cfg_attr(feature = "sqlx", sqlx(rename_all = "snake_case"))] #[cfg_attr(feature = "sqlx", sqlx(rename_all = "snake_case"))]

View File

@ -8,14 +8,16 @@ use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::types::{ use crate::types::{
Shared,
entities::{ entities::{
Application, Attachment, Channel, Emoji, GuildMember, PublicUser, RoleSubscriptionData, Application, Attachment, Channel, Emoji, GuildMember, PublicUser, RoleSubscriptionData,
Sticker, StickerItem, User, Sticker, StickerItem, User,
}, },
utils::Snowflake, utils::Snowflake,
Shared,
}; };
use super::option_arc_rwlock_ptr_eq;
#[derive(Debug, Serialize, Deserialize, Default, Clone)] #[derive(Debug, Serialize, Deserialize, Default, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// Represents a message sent in a channel. /// Represents a message sent in a channel.
@ -83,6 +85,7 @@ pub struct Message {
pub role_subscription_data: Option<RoleSubscriptionData>, pub role_subscription_data: Option<RoleSubscriptionData>,
} }
#[cfg(not(tarpaulin_include))]
impl PartialEq for Message { impl PartialEq for Message {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.id == other.id self.id == other.id
@ -99,26 +102,31 @@ impl PartialEq for Message {
&& self.attachments == other.attachments && self.attachments == other.attachments
&& self.embeds == other.embeds && self.embeds == other.embeds
&& self.embeds == other.embeds && self.embeds == other.embeds
&& self.reactions == other.reactions
&& self.reactions == other.reactions
&& self.nonce == other.nonce && self.nonce == other.nonce
&& self.pinned == other.pinned && self.pinned == other.pinned
&& self.webhook_id == other.webhook_id && self.webhook_id == other.webhook_id
&& self.message_type == other.message_type && self.message_type == other.message_type
&& self.activity == other.activity && self.activity == other.activity
&& self.activity == other.activity && self.activity == other.activity
&& self.application == other.application
&& self.application_id == other.application_id && self.application_id == other.application_id
&& self.message_reference == other.message_reference && self.message_reference == other.message_reference
&& self.message_reference == other.message_reference && self.message_reference == other.message_reference
&& self.flags == other.flags && self.flags == other.flags
&& self.referenced_message == other.referenced_message && self.referenced_message == other.referenced_message
&& self.interaction == other.interaction
&& self.thread == other.thread && self.thread == other.thread
&& self.components == other.components && self.components == other.components
&& self.components == other.components
&& self.sticker_items == other.sticker_items && self.sticker_items == other.sticker_items
// && self.position == other.position && self.stickers == other.stickers
&& self.role_subscription_data == other.role_subscription_data && self.role_subscription_data == other.role_subscription_data
} }
} }
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Eq, Ord, PartialOrd)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Eq, Ord, PartialOrd, Copy)]
/// # Reference /// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/message#message-reference-object> /// See <https://discord-userdoccers.vercel.app/resources/message#message-reference-object>
pub struct MessageReference { pub struct MessageReference {
@ -130,7 +138,7 @@ pub struct MessageReference {
pub fail_if_not_exists: Option<bool>, pub fail_if_not_exists: Option<bool>,
} }
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Eq, Ord, PartialOrd)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Eq, Ord, PartialOrd, Copy)]
pub enum MessageReferenceType { pub enum MessageReferenceType {
/// A standard reference used by replies and system messages /// A standard reference used by replies and system messages
Default = 0, Default = 0,
@ -148,7 +156,18 @@ pub struct MessageInteraction {
pub member: Option<Shared<GuildMember>>, pub member: Option<Shared<GuildMember>>,
} }
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize, Eq, PartialOrd, Ord)] #[cfg(not(tarpaulin_include))]
impl PartialEq for MessageInteraction {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
&& self.interaction_type == other.interaction_type
&& self.name == other.name
&& self.user == other.user
&& option_arc_rwlock_ptr_eq(&self.member, &other.member)
}
}
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize, Eq, PartialOrd, Ord, Hash)]
pub struct AllowedMention { pub struct AllowedMention {
parse: Vec<AllowedMentionType>, parse: Vec<AllowedMentionType>,
roles: Vec<Snowflake>, roles: Vec<Snowflake>,
@ -156,7 +175,7 @@ pub struct AllowedMention {
replied_user: bool, replied_user: bool,
} }
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, Eq, PartialOrd, Ord)] #[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, Eq, PartialOrd, Ord, Hash)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum AllowedMentionType { pub enum AllowedMentionType {
Roles, Roles,
@ -173,7 +192,7 @@ pub struct ChannelMention {
name: String, name: String,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd, Eq, Hash, Ord)]
pub struct Embed { pub struct Embed {
title: Option<String>, title: Option<String>,
#[serde(rename = "type")] #[serde(rename = "type")]
@ -191,7 +210,7 @@ pub struct Embed {
fields: Option<Vec<EmbedField>>, fields: Option<Vec<EmbedField>>,
} }
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum EmbedType { pub enum EmbedType {
#[deprecated] #[deprecated]
@ -206,17 +225,17 @@ pub enum EmbedType {
Link, Link,
PostPreview, PostPreview,
Rich, Rich,
Video Video,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EmbedFooter { pub struct EmbedFooter {
text: String, text: String,
icon_url: Option<String>, icon_url: Option<String>,
proxy_icon_url: Option<String>, proxy_icon_url: Option<String>,
} }
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord)] #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord, Hash)]
pub struct EmbedImage { pub struct EmbedImage {
url: String, url: String,
proxy_url: String, proxy_url: String,
@ -224,7 +243,7 @@ pub struct EmbedImage {
width: Option<i32>, width: Option<i32>,
} }
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord)] #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord, Hash)]
pub struct EmbedThumbnail { pub struct EmbedThumbnail {
url: String, url: String,
proxy_url: Option<String>, proxy_url: Option<String>,
@ -232,7 +251,7 @@ pub struct EmbedThumbnail {
width: Option<i32>, width: Option<i32>,
} }
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord)] #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord, Hash)]
struct EmbedVideo { struct EmbedVideo {
url: Option<String>, url: Option<String>,
proxy_url: Option<String>, proxy_url: Option<String>,
@ -240,13 +259,13 @@ struct EmbedVideo {
width: Option<i32>, width: Option<i32>,
} }
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord)] #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord, Hash)]
pub struct EmbedProvider { pub struct EmbedProvider {
name: Option<String>, name: Option<String>,
url: Option<String>, url: Option<String>,
} }
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord)] #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord, Hash)]
pub struct EmbedAuthor { pub struct EmbedAuthor {
name: String, name: String,
url: Option<String>, url: Option<String>,
@ -254,7 +273,7 @@ pub struct EmbedAuthor {
proxy_icon_url: Option<String>, proxy_icon_url: Option<String>,
} }
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord)] #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord, Hash)]
pub struct EmbedField { pub struct EmbedField {
name: String, name: String,
value: String, value: String,
@ -273,7 +292,7 @@ pub struct Reaction {
pub emoji: Emoji, pub emoji: Emoji,
#[cfg(feature = "sqlx")] #[cfg(feature = "sqlx")]
#[serde(skip)] #[serde(skip)]
pub user_ids: Vec<Snowflake> pub user_ids: Vec<Snowflake>,
} }
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, Eq, PartialOrd, Ord)] #[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, Eq, PartialOrd, Ord)]
@ -297,7 +316,9 @@ pub struct MessageActivity {
pub party_id: Option<String>, pub party_id: Option<String>,
} }
#[derive(Debug, Default, PartialEq, Clone, Copy, Serialize_repr, Deserialize_repr, Eq, PartialOrd, Ord)] #[derive(
Debug, Default, PartialEq, Clone, Copy, Serialize_repr, Deserialize_repr, Eq, PartialOrd, Ord,
)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[repr(u8)] #[repr(u8)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
@ -393,7 +414,7 @@ pub enum MessageType {
CustomGift = 41, CustomGift = 41,
GuildGamingStatsPrompt = 42, GuildGamingStatsPrompt = 42,
/// A message sent when a user purchases a guild product /// A message sent when a user purchases a guild product
PurchaseNotification = 44 PurchaseNotification = 44,
} }
bitflags! { bitflags! {
@ -437,10 +458,10 @@ pub struct PartialEmoji {
pub id: Option<Snowflake>, pub id: Option<Snowflake>,
pub name: String, pub name: String,
#[serde(default)] #[serde(default)]
pub animated: bool pub animated: bool,
} }
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, PartialOrd)] #[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, PartialOrd, Ord, Eq, Hash)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[repr(u8)] #[repr(u8)]

View File

@ -141,3 +141,47 @@ impl<T: Sized> IntoShared for T {
Arc::new(RwLock::new(self)) Arc::new(RwLock::new(self))
} }
} }
/// Internal function to compare two `Shared<T>`s by comparing their pointers.
#[cfg_attr(not(feature = "client"), allow(unused_variables))]
pub(crate) fn arc_rwlock_ptr_eq<T>(a: &Shared<T>, b: &Shared<T>) -> bool {
#[cfg(feature = "client")]
{
Shared::ptr_eq(a, b)
}
#[cfg(not(feature = "client"))]
{
true
}
}
/// Internal function to compare two `Vec<Shared<T>>`s by comparing their pointers.
pub(crate) fn vec_arc_rwlock_ptr_eq<T>(a: &[Shared<T>], b: &[Shared<T>]) -> bool {
for (a, b) in a.iter().zip(b.iter()) {
if !arc_rwlock_ptr_eq(a, b) {
return false;
}
}
true
}
/// Internal function to compare two `Option<Shared<T>>`s by comparing their pointers.
pub(crate) fn option_arc_rwlock_ptr_eq<T>(a: &Option<Shared<T>>, b: &Option<Shared<T>>) -> bool {
match (a, b) {
(Some(a), Some(b)) => arc_rwlock_ptr_eq(a, b),
(None, None) => true,
_ => false,
}
}
/// Internal function to compare two `Option<Vec<Shared<T>>>`s by comparing their pointers.
pub(crate) fn option_vec_arc_rwlock_ptr_eq<T>(
a: &Option<Vec<Shared<T>>>,
b: &Option<Vec<Shared<T>>>,
) -> bool {
match (a, b) {
(Some(a), Some(b)) => vec_arc_rwlock_ptr_eq(a, b),
(None, None) => true,
_ => false,
}
}

View File

@ -11,7 +11,9 @@ use crate::types::Snowflake;
/// The different types of ratelimits that can be applied to a request. Includes "Baseline"-variants /// The different types of ratelimits that can be applied to a request. Includes "Baseline"-variants
/// for when the Snowflake is not yet known. /// for when the Snowflake is not yet known.
/// See <https://discord.com/developers/docs/topics/rate-limits#rate-limits> for more information. /// See <https://discord.com/developers/docs/topics/rate-limits#rate-limits> for more information.
#[derive(Clone, Copy, Eq, PartialEq, Debug, Default, Hash, Serialize, Deserialize)] #[derive(
Clone, Copy, Eq, PartialEq, Debug, Default, Hash, Serialize, Deserialize, PartialOrd, Ord,
)]
pub enum LimitType { pub enum LimitType {
AuthRegister, AuthRegister,
AuthLogin, AuthLogin,
@ -29,7 +31,7 @@ pub enum LimitType {
/// A struct that represents the current ratelimits, either instance-wide or user-wide. /// A struct that represents the current ratelimits, either instance-wide or user-wide.
/// See <https://discord.com/developers/docs/topics/rate-limits#rate-limits> for more information. /// See <https://discord.com/developers/docs/topics/rate-limits#rate-limits> for more information.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)]
pub struct Limit { pub struct Limit {
pub bucket: LimitType, pub bucket: LimitType,
pub limit: u64, pub limit: u64,

View File

@ -8,7 +8,7 @@ use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::types::{Shared, Snowflake}; use crate::types::{Shared, Snowflake};
use super::PublicUser; use super::{arc_rwlock_ptr_eq, PublicUser};
#[derive(Debug, Deserialize, Serialize, Clone, Default)] #[derive(Debug, Deserialize, Serialize, Clone, Default)]
/// See <https://discord-userdoccers.vercel.app/resources/user#relationship-structure> /// See <https://discord-userdoccers.vercel.app/resources/user#relationship-structure>
@ -21,16 +21,30 @@ pub struct Relationship {
pub since: Option<DateTime<Utc>>, pub since: Option<DateTime<Utc>>,
} }
#[cfg(not(tarpaulin_include))]
impl PartialEq for Relationship { impl PartialEq for Relationship {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.id == other.id self.id == other.id
&& self.relationship_type == other.relationship_type && self.relationship_type == other.relationship_type
&& self.since == other.since
&& self.nickname == other.nickname && self.nickname == other.nickname
&& arc_rwlock_ptr_eq(&self.user, &other.user)
&& self.since == other.since
} }
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default, Eq, PartialEq)] #[derive(
Serialize_repr,
Deserialize_repr,
Debug,
Clone,
Default,
Eq,
PartialEq,
PartialOrd,
Ord,
Copy,
Hash,
)]
#[repr(u8)] #[repr(u8)]
/// See <https://discord-userdoccers.vercel.app/resources/user#relationship-type> /// See <https://discord-userdoccers.vercel.app/resources/user#relationship-type>
pub enum RelationshipType { pub enum RelationshipType {

View File

@ -51,7 +51,7 @@ pub struct RoleSubscriptionData {
pub is_renewal: bool, pub is_renewal: bool,
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash)] #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)]
/// See <https://discord.com/developers/docs/topics/permissions#role-object-role-tags-structure> /// See <https://discord.com/developers/docs/topics/permissions#role-object-role-tags-structure>
pub struct RoleTags { pub struct RoleTags {
#[serde(default)] #[serde(default)]

View File

@ -21,7 +21,7 @@ pub struct StageInstance {
pub guild_scheduled_event_id: Option<Snowflake>, pub guild_scheduled_event_id: Option<Snowflake>,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
/// See <https://discord.com/developers/docs/resources/stage-instance#stage-instance-object-privacy-level> /// See <https://discord.com/developers/docs/resources/stage-instance#stage-instance-object-privacy-level>

View File

@ -7,6 +7,8 @@ use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::types::{entities::User, utils::Snowflake, Shared}; use crate::types::{entities::User, utils::Snowflake, Shared};
use super::option_arc_rwlock_ptr_eq;
#[derive(Debug, Serialize, Deserialize, Clone, Default)] #[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// Represents a sticker that can be sent in messages. /// Represents a sticker that can be sent in messages.
@ -33,22 +35,7 @@ pub struct Sticker {
pub sort_value: Option<u8>, pub sort_value: Option<u8>,
} }
impl std::hash::Hash for Sticker { #[cfg(not(tarpaulin_include))]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
self.pack_id.hash(state);
self.name.hash(state);
self.description.hash(state);
self.tags.hash(state);
self.asset.hash(state);
self.sticker_type.hash(state);
self.format_type.hash(state);
self.available.hash(state);
self.guild_id.hash(state);
self.sort_value.hash(state);
}
}
impl PartialEq for Sticker { impl PartialEq for Sticker {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.id == other.id self.id == other.id
@ -61,65 +48,16 @@ impl PartialEq for Sticker {
&& self.format_type == other.format_type && self.format_type == other.format_type
&& self.available == other.available && self.available == other.available
&& self.guild_id == other.guild_id && self.guild_id == other.guild_id
&& option_arc_rwlock_ptr_eq(&self.user, &other.user)
&& self.sort_value == other.sort_value && self.sort_value == other.sort_value
} }
} }
impl PartialOrd for Sticker {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match self.id.partial_cmp(&other.id) {
Some(core::cmp::Ordering::Equal) => {}
ord => return ord,
}
match self.pack_id.partial_cmp(&other.pack_id) {
Some(core::cmp::Ordering::Equal) => {}
ord => return ord,
}
match self.name.partial_cmp(&other.name) {
Some(core::cmp::Ordering::Equal) => {}
ord => return ord,
}
match self.description.partial_cmp(&other.description) {
Some(core::cmp::Ordering::Equal) => {}
ord => return ord,
}
match self.tags.partial_cmp(&other.tags) {
Some(core::cmp::Ordering::Equal) => {}
ord => return ord,
}
match self.asset.partial_cmp(&other.asset) {
Some(core::cmp::Ordering::Equal) => {}
ord => return ord,
}
match self.sticker_type.partial_cmp(&other.sticker_type) {
Some(core::cmp::Ordering::Equal) => {}
ord => return ord,
}
match self.format_type.partial_cmp(&other.format_type) {
Some(core::cmp::Ordering::Equal) => {}
ord => return ord,
}
match self.available.partial_cmp(&other.available) {
Some(core::cmp::Ordering::Equal) => {}
ord => return ord,
}
match self.guild_id.partial_cmp(&other.guild_id) {
Some(core::cmp::Ordering::Equal) => {}
ord => return ord,
}
self.sort_value.partial_cmp(&other.sort_value)
}
}
impl Sticker { impl Sticker {
pub fn tags(&self) -> Vec<String> { pub fn tags(&self) -> Vec<String> {
self.tags self.tags.as_ref().map_or(vec![], |s| {
.as_ref() s.split(',').map(|tag| tag.trim().to_string()).collect()
.map_or(vec![], |s| })
s.split(',')
.map(|tag| tag.trim().to_string())
.collect()
)
} }
} }
@ -136,7 +74,9 @@ pub struct StickerItem {
pub format_type: StickerFormatType, pub format_type: StickerFormatType,
} }
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Hash, Serialize_repr, Deserialize_repr)] #[derive(
Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Hash, Serialize_repr, Deserialize_repr,
)]
#[repr(u8)] #[repr(u8)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[serde(rename = "SCREAMING_SNAKE_CASE")] #[serde(rename = "SCREAMING_SNAKE_CASE")]
@ -150,7 +90,9 @@ pub enum StickerType {
Guild = 2, Guild = 2,
} }
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Hash, Serialize_repr, Deserialize_repr)] #[derive(
Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Hash, Serialize_repr, Deserialize_repr,
)]
#[repr(u8)] #[repr(u8)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
/// # Reference /// # Reference
@ -169,7 +111,10 @@ pub enum StickerFormatType {
impl StickerFormatType { impl StickerFormatType {
pub fn is_animated(&self) -> bool { pub fn is_animated(&self) -> bool {
matches!(self, StickerFormatType::APNG | StickerFormatType::LOTTIE | StickerFormatType::GIF) matches!(
self,
StickerFormatType::APNG | StickerFormatType::LOTTIE | StickerFormatType::GIF
)
} }
pub const fn to_mime(&self) -> &'static str { pub const fn to_mime(&self) -> &'static str {

View File

@ -5,8 +5,10 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::entities::User; use crate::types::entities::User;
use crate::types::Snowflake;
use crate::types::Shared; use crate::types::Shared;
use crate::types::Snowflake;
use super::arc_rwlock_ptr_eq;
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
@ -19,6 +21,17 @@ pub struct Team {
pub owner_user_id: Snowflake, pub owner_user_id: Snowflake,
} }
#[cfg(not(tarpaulin_include))]
impl PartialEq for Team {
fn eq(&self, other: &Self) -> bool {
self.icon == other.icon
&& self.id == other.id
&& self.members == other.members
&& self.name == other.name
&& self.owner_user_id == other.owner_user_id
}
}
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
pub struct TeamMember { pub struct TeamMember {
pub membership_state: u8, pub membership_state: u8,
@ -26,3 +39,13 @@ pub struct TeamMember {
pub team_id: Snowflake, pub team_id: Snowflake,
pub user: Shared<User>, pub user: Shared<User>,
} }
#[cfg(not(tarpaulin_include))]
impl PartialEq for TeamMember {
fn eq(&self, other: &Self) -> bool {
self.membership_state == other.membership_state
&& self.permissions == other.permissions
&& self.team_id == other.team_id
&& arc_rwlock_ptr_eq(&self.user, &other.user)
}
}

View File

@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use crate::types::Shared; use crate::types::Shared;
use serde_aux::field_attributes::deserialize_option_number_from_string; use serde_aux::field_attributes::deserialize_option_number_from_string;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, Copy, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
pub enum UserStatus { pub enum UserStatus {
@ -26,7 +26,7 @@ impl std::fmt::Display for UserStatus {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, Copy, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
pub enum UserTheme { pub enum UserTheme {
@ -136,7 +136,7 @@ pub struct CustomStatus {
pub text: Option<String>, pub text: Option<String>,
} }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)]
pub struct FriendSourceFlags { pub struct FriendSourceFlags {
pub all: bool, pub all: bool,
} }

View File

@ -25,6 +25,8 @@ use crate::types::{
utils::Snowflake, utils::Snowflake,
}; };
use super::option_arc_rwlock_ptr_eq;
/// The VoiceState struct. Note, that Discord does not have an `id` field for this, whereas Spacebar /// The VoiceState struct. Note, that Discord does not have an `id` field for this, whereas Spacebar
/// does. /// does.
/// ///
@ -54,6 +56,28 @@ pub struct VoiceState {
pub id: Option<Snowflake>, // Only exists on Spacebar pub id: Option<Snowflake>, // Only exists on Spacebar
} }
#[cfg(not(tarpaulin_include))]
impl PartialEq for VoiceState {
fn eq(&self, other: &Self) -> bool {
self.guild_id == other.guild_id
&& self.guild == other.guild
&& self.channel_id == other.channel_id
&& self.user_id == other.user_id
&& option_arc_rwlock_ptr_eq(&self.member, &other.member)
&& self.session_id == other.session_id
&& self.token == other.token
&& self.deaf == other.deaf
&& self.mute == other.mute
&& self.self_deaf == other.self_deaf
&& self.self_mute == other.self_mute
&& self.self_stream == other.self_stream
&& self.self_video == other.self_video
&& self.suppress == other.suppress
&& self.request_to_speak_timestamp == other.request_to_speak_timestamp
&& self.id == other.id
}
}
#[cfg(feature = "client")] #[cfg(feature = "client")]
impl Updateable for VoiceState { impl Updateable for VoiceState {
#[cfg(not(tarpaulin_include))] #[cfg(not(tarpaulin_include))]

View File

@ -25,6 +25,8 @@ use crate::types::{
utils::Snowflake, utils::Snowflake,
}; };
use super::option_arc_rwlock_ptr_eq;
/// See <https://docs.spacebar.chat/routes/#cmp--schemas-webhook> /// See <https://docs.spacebar.chat/routes/#cmp--schemas-webhook>
#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[cfg_attr(feature = "client", derive(Updateable, Composite))] #[cfg_attr(feature = "client", derive(Updateable, Composite))]
@ -49,7 +51,26 @@ pub struct Webhook {
pub url: Option<String>, pub url: Option<String>,
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy)] #[cfg(not(tarpaulin_include))]
impl PartialEq for Webhook {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
&& self.webhook_type == other.webhook_type
&& self.name == other.name
&& self.avatar == other.avatar
&& self.token == other.token
&& self.guild_id == other.guild_id
&& self.channel_id == other.channel_id
&& self.application_id == other.application_id
&& option_arc_rwlock_ptr_eq(&self.user, &other.user)
&& option_arc_rwlock_ptr_eq(&self.source_guild, &other.source_guild)
&& self.url == other.url
}
}
#[derive(
Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
)]
#[repr(u8)] #[repr(u8)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
pub enum WebhookType { pub enum WebhookType {

View File

@ -23,16 +23,16 @@ pub enum Error {
Guild(#[from] GuildError), Guild(#[from] GuildError),
#[error("Invalid flags value: {0}")] #[error("Invalid flags value: {0}")]
InvalidFlags(u64) InvalidFlags(u64),
} }
#[derive(Debug, PartialEq, Eq, thiserror::Error)] #[derive(Debug, PartialEq, Eq, thiserror::Error, Copy, Clone)]
pub enum GuildError { pub enum GuildError {
#[error("Invalid Guild Feature")] #[error("Invalid Guild Feature")]
InvalidGuildFeature, InvalidGuildFeature,
} }
#[derive(Debug, PartialEq, Eq, thiserror::Error)] #[derive(Debug, PartialEq, Eq, thiserror::Error, Copy, Clone)]
pub enum FieldFormatError { pub enum FieldFormatError {
#[error("Password must be between 1 and 72 characters.")] #[error("Password must be between 1 and 72 characters.")]
PasswordError, PasswordError,

View File

@ -39,7 +39,19 @@ pub struct CallUpdate {
pub channel_id: Snowflake, pub channel_id: Snowflake,
} }
#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq, WebSocketEvent)] #[derive(
Debug,
Deserialize,
Serialize,
Default,
Clone,
PartialEq,
Eq,
WebSocketEvent,
Copy,
PartialOrd,
Ord,
)]
/// Officially Undocumented; /// Officially Undocumented;
/// Deletes a ringing call; /// Deletes a ringing call;
/// Ex: {"t":"CALL_DELETE","s":8,"op":0,"d":{"channel_id":"837609115475771392"}} /// Ex: {"t":"CALL_DELETE","s":8,"op":0,"d":{"channel_id":"837609115475771392"}}
@ -47,7 +59,19 @@ pub struct CallDelete {
pub channel_id: Snowflake, pub channel_id: Snowflake,
} }
#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq, WebSocketEvent)] #[derive(
Debug,
Deserialize,
Serialize,
Default,
Clone,
PartialEq,
Eq,
WebSocketEvent,
Copy,
PartialOrd,
Ord,
)]
/// Officially Undocumented; /// Officially Undocumented;
/// See <https://unofficial-discord-docs.vercel.app/gateway/op13>; /// See <https://unofficial-discord-docs.vercel.app/gateway/op13>;
/// ///
@ -55,4 +79,3 @@ pub struct CallDelete {
pub struct CallSync { pub struct CallSync {
pub channel_id: Snowflake, pub channel_id: Snowflake,
} }

View File

@ -20,7 +20,7 @@ use crate::types::IntoShared;
#[cfg(feature = "client")] #[cfg(feature = "client")]
use crate::types::Guild; use crate::types::Guild;
#[derive(Debug, Default, Deserialize, Serialize, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, WebSocketEvent, Copy, PartialEq, Clone, Eq, Hash, PartialOrd, Ord)]
/// See <https://discord.com/developers/docs/topics/gateway-events#channel-pins-update> /// See <https://discord.com/developers/docs/topics/gateway-events#channel-pins-update>
pub struct ChannelPinsUpdate { pub struct ChannelPinsUpdate {
pub guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
@ -86,7 +86,7 @@ pub struct ChannelUnreadUpdate {
pub guild_id: Snowflake, pub guild_id: Snowflake,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
/// Contains very few fields from [Channel] /// Contains very few fields from [Channel]
/// See also [ChannelUnreadUpdate] /// See also [ChannelUnreadUpdate]
pub struct ChannelUnreadUpdateObject { pub struct ChannelUnreadUpdateObject {

View File

@ -9,8 +9,8 @@ use serde::{Deserialize, Serialize};
use crate::types::entities::{Guild, PublicUser, UnavailableGuild}; use crate::types::entities::{Guild, PublicUser, UnavailableGuild};
use crate::types::events::WebSocketEvent; use crate::types::events::WebSocketEvent;
use crate::types::{ use crate::types::{
AuditLogEntry, Emoji, GuildMember, GuildScheduledEvent, JsonField, RoleObject, AuditLogEntry, Emoji, GuildMember, GuildScheduledEvent, JsonField, RoleObject, Snowflake,
Snowflake, SourceUrlField, Sticker, SourceUrlField, Sticker,
}; };
use super::PresenceUpdate; use super::PresenceUpdate;
@ -18,11 +18,21 @@ use super::PresenceUpdate;
#[cfg(feature = "client")] #[cfg(feature = "client")]
use super::UpdateMessage; use super::UpdateMessage;
#[cfg(feature = "client")] #[cfg(feature = "client")]
use crate::types::Shared;
#[cfg(feature = "client")]
use crate::types::IntoShared; use crate::types::IntoShared;
#[cfg(feature = "client")]
use crate::types::Shared;
#[derive(Debug, Deserialize, Serialize, Default, Clone, SourceUrlField, JsonField, WebSocketEvent)] #[derive(
Debug,
Deserialize,
Serialize,
Default,
Clone,
SourceUrlField,
JsonField,
WebSocketEvent,
PartialEq,
)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-create>; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-create>;
/// Received to give data about a guild; /// Received to give data about a guild;
// This one is particularly painful, it can be a Guild object with an extra field or an unavailable guild object // This one is particularly painful, it can be a Guild object with an extra field or an unavailable guild object
@ -49,7 +59,7 @@ impl UpdateMessage<Guild> for GuildCreate {
fn update(&mut self, _: Shared<Guild>) {} fn update(&mut self, _: Shared<Guild>) {}
} }
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
#[serde(untagged)] #[serde(untagged)]
pub enum GuildCreateDataOption { pub enum GuildCreateDataOption {
UnavailableGuild(UnavailableGuild), UnavailableGuild(UnavailableGuild),
@ -62,7 +72,31 @@ impl Default for GuildCreateDataOption {
} }
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Clone, PartialEq)]
pub enum GuildEvents {
Create(GuildCreate),
Update(GuildUpdate),
Delete(GuildDelete),
BanAdd(GuildBanAdd),
BanRemove(GuildBanRemove),
EmojisUpdate(GuildEmojisUpdate),
StickersUpdate(GuildStickersUpdate),
IntegrationsUpdate(GuildIntegrationsUpdate),
MemberAdd(GuildMemberAdd),
MemberRemove(GuildMemberRemove),
MemberUpdate(GuildMemberUpdate),
MembersChunk(GuildMembersChunk),
RoleCreate(GuildRoleCreate),
RoleUpdate(GuildRoleUpdate),
RoleDelete(GuildRoleDelete),
ScheduledEventCreate(GuildScheduledEventCreate),
ScheduledEventUpdate(GuildScheduledEventUpdate),
ScheduledEventDelete(GuildScheduledEventDelete),
ScheduledEventUserAdd(GuildScheduledEventUserAdd),
ScheduledEventUserRemove(GuildScheduledEventUserRemove),
AuditLogEntryCreate(GuildAuditLogEntryCreate),
}
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-ban-add-guild-ban-add-event-fields>; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-ban-add-guild-ban-add-event-fields>;
/// Received to give info about a user being banned from a guild; /// Received to give info about a user being banned from a guild;
pub struct GuildBanAdd { pub struct GuildBanAdd {
@ -70,7 +104,7 @@ pub struct GuildBanAdd {
pub user: PublicUser, pub user: PublicUser,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-ban-remove>; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-ban-remove>;
/// Received to give info about a user being unbanned from a guild; /// Received to give info about a user being unbanned from a guild;
pub struct GuildBanRemove { pub struct GuildBanRemove {
@ -78,7 +112,17 @@ pub struct GuildBanRemove {
pub user: PublicUser, pub user: PublicUser,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, SourceUrlField, JsonField, WebSocketEvent)] #[derive(
Debug,
Default,
Deserialize,
Serialize,
Clone,
SourceUrlField,
JsonField,
WebSocketEvent,
PartialEq,
)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-update>; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-update>;
/// Received to give info about a guild being updated; /// Received to give info about a guild being updated;
pub struct GuildUpdate { pub struct GuildUpdate {
@ -98,7 +142,17 @@ impl UpdateMessage<Guild> for GuildUpdate {
} }
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, SourceUrlField, JsonField, WebSocketEvent)] #[derive(
Debug,
Default,
Deserialize,
Serialize,
Clone,
SourceUrlField,
JsonField,
WebSocketEvent,
PartialEq,
)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-delete>; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-delete>;
/// Received to tell the client about a guild being deleted; /// Received to tell the client about a guild being deleted;
pub struct GuildDelete { pub struct GuildDelete {
@ -119,7 +173,7 @@ impl UpdateMessage<Guild> for GuildDelete {
fn update(&mut self, _: Shared<Guild>) {} fn update(&mut self, _: Shared<Guild>) {}
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-audit-log-entry-create>; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-audit-log-entry-create>;
/// Received to the client about an audit log entry being added; /// Received to the client about an audit log entry being added;
pub struct GuildAuditLogEntryCreate { pub struct GuildAuditLogEntryCreate {
@ -127,7 +181,7 @@ pub struct GuildAuditLogEntryCreate {
pub entry: AuditLogEntry, pub entry: AuditLogEntry,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-emojis-update>; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-emojis-update>;
/// Received to tell the client about a change to a guild's emoji list; /// Received to tell the client about a change to a guild's emoji list;
pub struct GuildEmojisUpdate { pub struct GuildEmojisUpdate {
@ -135,7 +189,7 @@ pub struct GuildEmojisUpdate {
pub emojis: Vec<Emoji>, pub emojis: Vec<Emoji>,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-stickers-update>; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-stickers-update>;
/// Received to tell the client about a change to a guild's sticker list; /// Received to tell the client about a change to a guild's sticker list;
pub struct GuildStickersUpdate { pub struct GuildStickersUpdate {
@ -143,13 +197,13 @@ pub struct GuildStickersUpdate {
pub stickers: Vec<Sticker>, pub stickers: Vec<Sticker>,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq, Copy, Eq, Hash, PartialOrd, Ord)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-integrations-update> /// See <https://discord.com/developers/docs/topics/gateway-events#guild-integrations-update>
pub struct GuildIntegrationsUpdate { pub struct GuildIntegrationsUpdate {
pub guild_id: Snowflake, pub guild_id: Snowflake,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-member-add>; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-member-add>;
/// Received to tell the client about a user joining a guild; /// Received to tell the client about a user joining a guild;
pub struct GuildMemberAdd { pub struct GuildMemberAdd {
@ -158,7 +212,7 @@ pub struct GuildMemberAdd {
pub guild_id: Snowflake, pub guild_id: Snowflake,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-member-remove>; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-member-remove>;
/// Received to tell the client about a user leaving a guild; /// Received to tell the client about a user leaving a guild;
pub struct GuildMemberRemove { pub struct GuildMemberRemove {
@ -166,7 +220,7 @@ pub struct GuildMemberRemove {
pub user: PublicUser, pub user: PublicUser,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-member-update> /// See <https://discord.com/developers/docs/topics/gateway-events#guild-member-update>
pub struct GuildMemberUpdate { pub struct GuildMemberUpdate {
pub guild_id: Snowflake, pub guild_id: Snowflake,
@ -182,7 +236,7 @@ pub struct GuildMemberUpdate {
pub communication_disabled_until: Option<DateTime<Utc>>, pub communication_disabled_until: Option<DateTime<Utc>>,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-members-chunk> /// See <https://discord.com/developers/docs/topics/gateway-events#guild-members-chunk>
pub struct GuildMembersChunk { pub struct GuildMembersChunk {
pub guild_id: Snowflake, pub guild_id: Snowflake,
@ -194,7 +248,17 @@ pub struct GuildMembersChunk {
pub nonce: Option<String>, pub nonce: Option<String>,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField, WebSocketEvent)] #[derive(
Debug,
Default,
Deserialize,
Serialize,
Clone,
JsonField,
SourceUrlField,
WebSocketEvent,
PartialEq,
)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-role-create> /// See <https://discord.com/developers/docs/topics/gateway-events#guild-role-create>
pub struct GuildRoleCreate { pub struct GuildRoleCreate {
pub guild_id: Snowflake, pub guild_id: Snowflake,
@ -214,13 +278,21 @@ impl UpdateMessage<Guild> for GuildRoleCreate {
fn update(&mut self, object_to_update: Shared<Guild>) { fn update(&mut self, object_to_update: Shared<Guild>) {
let mut object_to_update = object_to_update.write().unwrap(); let mut object_to_update = object_to_update.write().unwrap();
object_to_update object_to_update.roles.push(self.role.clone().into_shared());
.roles
.push(self.role.clone().into_shared());
} }
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField, WebSocketEvent)] #[derive(
Debug,
Default,
Deserialize,
Serialize,
Clone,
JsonField,
SourceUrlField,
WebSocketEvent,
PartialEq,
)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-role-update> /// See <https://discord.com/developers/docs/topics/gateway-events#guild-role-update>
pub struct GuildRoleUpdate { pub struct GuildRoleUpdate {
pub guild_id: Snowflake, pub guild_id: Snowflake,
@ -244,35 +316,35 @@ impl UpdateMessage<RoleObject> for GuildRoleUpdate {
} }
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-role-delete> /// See <https://discord.com/developers/docs/topics/gateway-events#guild-role-delete>
pub struct GuildRoleDelete { pub struct GuildRoleDelete {
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub role_id: Snowflake, pub role_id: Snowflake,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-create> /// See <https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-create>
pub struct GuildScheduledEventCreate { pub struct GuildScheduledEventCreate {
#[serde(flatten)] #[serde(flatten)]
pub event: GuildScheduledEvent, pub event: GuildScheduledEvent,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-update> /// See <https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-update>
pub struct GuildScheduledEventUpdate { pub struct GuildScheduledEventUpdate {
#[serde(flatten)] #[serde(flatten)]
pub event: GuildScheduledEvent, pub event: GuildScheduledEvent,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-delete> /// See <https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-delete>
pub struct GuildScheduledEventDelete { pub struct GuildScheduledEventDelete {
#[serde(flatten)] #[serde(flatten)]
pub event: GuildScheduledEvent, pub event: GuildScheduledEvent,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq, Copy, Eq, Hash, PartialOrd, Ord)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-user-add> /// See <https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-user-add>
pub struct GuildScheduledEventUserAdd { pub struct GuildScheduledEventUserAdd {
pub guild_scheduled_event_id: Snowflake, pub guild_scheduled_event_id: Snowflake,
@ -280,7 +352,7 @@ pub struct GuildScheduledEventUserAdd {
pub guild_id: Snowflake, pub guild_id: Snowflake,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq, Copy, Eq, Hash, PartialOrd, Ord)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-user-remove> /// See <https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-user-remove>
pub struct GuildScheduledEventUserRemove { pub struct GuildScheduledEventUserRemove {
pub guild_scheduled_event_id: Snowflake, pub guild_scheduled_event_id: Snowflake,

View File

@ -5,13 +5,13 @@
use crate::types::events::WebSocketEvent; use crate::types::events::WebSocketEvent;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Default, Deserialize, Serialize, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, WebSocketEvent, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct GatewayHeartbeat { pub struct GatewayHeartbeat {
pub op: u8, pub op: u8,
pub d: Option<u64>, pub d: Option<u64>,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct GatewayHeartbeatAck { pub struct GatewayHeartbeatAck {
pub op: i32, pub op: i32,
} }

View File

@ -7,13 +7,13 @@ use chorus_macros::WebSocketEvent;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// Received on gateway init, tells the client how often to send heartbeats; /// Received on gateway init, tells the client how often to send heartbeats;
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent, Copy, Hash, PartialOrd, Ord)]
pub struct GatewayHello { pub struct GatewayHello {
pub op: i32, pub op: i32,
pub d: HelloData, pub d: HelloData,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, Copy, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, Copy, WebSocketEvent, Hash, PartialOrd, Ord)]
/// Contains info on how often the client should send heartbeats to the server; /// Contains info on how often the client should send heartbeats to the server;
pub struct HelloData { pub struct HelloData {
/// How often a client should send heartbeats, in milliseconds /// How often a client should send heartbeats, in milliseconds

View File

@ -23,7 +23,7 @@ pub struct IntegrationUpdate {
pub guild_id: Snowflake, pub guild_id: Snowflake,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] #[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
/// See <https://discord.com/developers/docs/topics/gateway-events#integration-delete> /// See <https://discord.com/developers/docs/topics/gateway-events#integration-delete>
pub struct IntegrationDelete { pub struct IntegrationDelete {
pub id: Snowflake, pub id: Snowflake,

View File

@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
use super::WebSocketEvent; use super::WebSocketEvent;
#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] #[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)]
/// Your session is now invalid. /// Your session is now invalid.
/// ///
/// Either reauthenticate and reidentify or resume if possible. /// Either reauthenticate and reidentify or resume if possible.

View File

@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
use crate::types::{ use crate::types::{
entities::{Emoji, GuildMember, Message, PublicUser}, entities::{Emoji, GuildMember, Message, PublicUser},
Snowflake, WebSocketEvent Snowflake, WebSocketEvent,
}; };
use chorus_macros::WebSocketEvent; use chorus_macros::WebSocketEvent;
@ -51,7 +51,20 @@ pub struct MessageUpdate {
pub mentions: Option<Vec<MessageCreateUser>>, pub mentions: Option<Vec<MessageCreateUser>>,
} }
#[derive(Debug, Serialize, Deserialize, Default, Clone, WebSocketEvent)] #[derive(
Debug,
Serialize,
Deserialize,
Default,
Clone,
WebSocketEvent,
Copy,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
)]
/// # Reference /// # Reference
/// See <https://discord.com/developers/docs/topics/gateway-events#message-delete> /// See <https://discord.com/developers/docs/topics/gateway-events#message-delete>
pub struct MessageDelete { pub struct MessageDelete {
@ -60,7 +73,19 @@ pub struct MessageDelete {
pub guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
} }
#[derive(Debug, Serialize, Deserialize, Default, Clone, WebSocketEvent)] #[derive(
Debug,
Serialize,
Deserialize,
Default,
Clone,
WebSocketEvent,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
)]
/// # Reference /// # Reference
/// See <https://discord.com/developers/docs/topics/gateway-events#message-delete-bulk> /// See <https://discord.com/developers/docs/topics/gateway-events#message-delete-bulk>
pub struct MessageDeleteBulk { pub struct MessageDeleteBulk {
@ -92,7 +117,20 @@ pub struct MessageReactionRemove {
pub emoji: Emoji, pub emoji: Emoji,
} }
#[derive(Debug, Serialize, Deserialize, Default, Clone, WebSocketEvent)] #[derive(
Debug,
Serialize,
Deserialize,
Default,
Clone,
WebSocketEvent,
Copy,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
)]
/// # Reference /// # Reference
/// See <https://discord.com/developers/docs/topics/gateway-events#message-reaction-remove-all> /// See <https://discord.com/developers/docs/topics/gateway-events#message-reaction-remove-all>
pub struct MessageReactionRemoveAll { pub struct MessageReactionRemoveAll {
@ -131,4 +169,3 @@ pub struct MessageACK {
pub flags: Option<serde_json::Value>, pub flags: Option<serde_json::Value>,
pub channel_id: Snowflake, pub channel_id: Snowflake,
} }

View File

@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
use super::WebSocketEvent; use super::WebSocketEvent;
#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] #[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
/// "The reconnect event is dispatched when a client should reconnect to the Gateway (and resume their existing session, if they have one). This event usually occurs during deploys to migrate sessions gracefully off old hosts" /// "The reconnect event is dispatched when a client should reconnect to the Gateway (and resume their existing session, if they have one). This event usually occurs during deploys to migrate sessions gracefully off old hosts"
/// ///
/// # Reference /// # Reference

View File

@ -13,7 +13,7 @@ pub struct RelationshipAdd {
pub should_notify: bool, pub should_notify: bool,
} }
#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] #[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)]
/// See <https://github.com/spacebarchat/server/issues/203> /// See <https://github.com/spacebarchat/server/issues/203>
pub struct RelationshipRemove { pub struct RelationshipRemove {
pub id: Snowflake, pub id: Snowflake,

View File

@ -13,7 +13,7 @@ use chorus_macros::WebSocketEvent;
/// Essentially, what allows us to send UDP data and lights up the green circle around your avatar. /// Essentially, what allows us to send UDP data and lights up the green circle around your avatar.
/// ///
/// See <https://discord-userdoccers.vercel.app/topics/voice-connections#speaking-structure> /// See <https://discord-userdoccers.vercel.app/topics/voice-connections#speaking-structure>
#[derive(Debug, Deserialize, Serialize, Clone, Default, WebSocketEvent)] #[derive(Debug, Deserialize, Serialize, Clone, Default, WebSocketEvent, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)]
pub struct Speaking { pub struct Speaking {
/// Data about the audio we're transmitting. /// Data about the audio we're transmitting.
/// ///

View File

@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use crate::types::{Snowflake, WebSocketEvent}; use crate::types::{Snowflake, WebSocketEvent};
use chorus_macros::WebSocketEvent; use chorus_macros::WebSocketEvent;
#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] #[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
/// See <https://discord.com/developers/docs/topics/gateway-events#webhooks-update> /// See <https://discord.com/developers/docs/topics/gateway-events#webhooks-update>
pub struct WebhooksUpdate { pub struct WebhooksUpdate {
pub guild_id: Snowflake, pub guild_id: Snowflake,

View File

@ -20,7 +20,7 @@ pub struct Interaction {
pub version: i32, pub version: i32,
} }
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize, Eq, PartialOrd, Ord, Hash, Copy)]
pub enum InteractionType { pub enum InteractionType {
#[default] #[default]
SelfCommand = 0, SelfCommand = 0,
@ -28,7 +28,7 @@ pub enum InteractionType {
ApplicationCommand = 2, ApplicationCommand = 2,
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Copy, Eq, Hash, PartialOrd, Ord)]
pub enum InteractionResponseType { pub enum InteractionResponseType {
SelfCommandResponse = 0, SelfCommandResponse = 0,
Pong = 1, Pong = 1,
@ -38,7 +38,7 @@ pub enum InteractionResponseType {
AcknowledgeWithSource = 5, AcknowledgeWithSource = 5,
} }
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize, Eq, Hash, PartialOrd, Ord)]
pub struct InteractionApplicationCommandCallbackData { pub struct InteractionApplicationCommandCallbackData {
pub tts: bool, pub tts: bool,
pub content: String, pub content: String,

View File

@ -6,7 +6,7 @@
use poem::{http::StatusCode, IntoResponse, Response}; use poem::{http::StatusCode, IntoResponse, Response};
use serde_json::{json, Value}; use serde_json::{json, Value};
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error, Copy, Clone, PartialEq, Eq, Hash)]
pub enum APIError { pub enum APIError {
#[error(transparent)] #[error(transparent)]
Auth(#[from] AuthError), Auth(#[from] AuthError),
@ -20,7 +20,7 @@ impl APIError {
} }
} }
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AuthError { pub enum AuthError {
#[error("INVALID_LOGIN")] #[error("INVALID_LOGIN")]
InvalidLogin, InvalidLogin,

View File

@ -1,5 +1,8 @@
use crate::types::{
ApplicationCommand, AuditLogActionType, AuditLogEntry, AutoModerationRule, Channel,
GuildScheduledEvent, Integration, Snowflake, User, Webhook,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::{ApplicationCommand, AuditLogActionType, AuditLogEntry, AutoModerationRule, Channel, GuildScheduledEvent, Integration, Snowflake, User, Webhook};
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
pub struct AuditLogObject { pub struct AuditLogObject {
@ -13,11 +16,13 @@ pub struct AuditLogObject {
pub webhooks: Vec<Webhook>, pub webhooks: Vec<Webhook>,
} }
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(
Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default,
)]
pub struct GetAuditLogsQuery { pub struct GetAuditLogsQuery {
pub before: Option<Snowflake>, pub before: Option<Snowflake>,
pub after: Option<Snowflake>, pub after: Option<Snowflake>,
pub limit: Option<u8>, pub limit: Option<u8>,
pub user_id: Option<Snowflake>, pub user_id: Option<Snowflake>,
pub action_type: Option<AuditLogActionType> pub action_type: Option<AuditLogActionType>,
} }

View File

@ -169,7 +169,7 @@ pub struct AddChannelRecipientSchema {
} }
/// See <https://discord-userdoccers.vercel.app/resources/channel#add-channel-recipient> /// See <https://discord-userdoccers.vercel.app/resources/channel#add-channel-recipient>
#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq)] #[derive(Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Copy, Hash)]
pub struct ModifyChannelPositionsSchema { pub struct ModifyChannelPositionsSchema {
pub id: Snowflake, pub id: Snowflake,
pub position: Option<u32>, pub position: Option<u32>,
@ -178,7 +178,7 @@ pub struct ModifyChannelPositionsSchema {
} }
/// See <https://docs.discord.sex/resources/channel#follow-channel> /// See <https://docs.discord.sex/resources/channel#follow-channel>
#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq)] #[derive(Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Copy, Hash)]
pub struct AddFollowingChannelSchema { pub struct AddFollowingChannelSchema {
pub webhook_channel_id: Snowflake, pub webhook_channel_id: Snowflake,
} }

View File

@ -2,16 +2,20 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this // License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
use std::collections::HashMap;
use bitflags::bitflags; use bitflags::bitflags;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use crate::types::entities::Channel; use crate::types::entities::Channel;
use crate::types::types::guild_configuration::GuildFeatures; use crate::types::types::guild_configuration::GuildFeatures;
use crate::types::{Emoji, ExplicitContentFilterLevel, GenericSearchQueryWithLimit, MessageNotificationLevel, Snowflake, Sticker, StickerFormatType, SystemChannelFlags, VerificationLevel, WelcomeScreenChannel}; use crate::types::{
Emoji, ExplicitContentFilterLevel, GenericSearchQueryWithLimit, MessageNotificationLevel,
Snowflake, Sticker, StickerFormatType, SystemChannelFlags, VerificationLevel,
WelcomeScreenChannel,
};
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] #[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
/// Represents the schema which needs to be sent to create a Guild. /// Represents the schema which needs to be sent to create a Guild.
/// See: <https://docs.spacebar.chat/routes/#cmp--schemas-guildcreateschema> /// See: <https://docs.spacebar.chat/routes/#cmp--schemas-guildcreateschema>
@ -25,6 +29,19 @@ pub struct GuildCreateSchema {
pub rules_channel_id: Option<String>, pub rules_channel_id: Option<String>,
} }
#[cfg(not(tarpaulin_include))]
impl PartialEq for GuildCreateSchema {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
&& self.region == other.region
&& self.icon == other.icon
&& self.channels == other.channels
&& self.guild_template_code == other.guild_template_code
&& self.system_channel_id == other.system_channel_id
&& self.rules_channel_id == other.rules_channel_id
}
}
#[derive(Debug, Deserialize, Serialize, Default, Clone, Copy, Eq, PartialEq)] #[derive(Debug, Deserialize, Serialize, Default, Clone, Copy, Eq, PartialEq)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
/// Represents the schema which needs to be sent to create a Guild Ban. /// Represents the schema which needs to be sent to create a Guild Ban.
@ -77,7 +94,7 @@ pub struct GuildModifySchema {
pub premium_progress_bar_enabled: Option<bool>, pub premium_progress_bar_enabled: Option<bool>,
} }
#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq, Ord, PartialOrd)] #[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
pub struct GetUserGuildSchema { pub struct GetUserGuildSchema {
pub before: Option<Snowflake>, pub before: Option<Snowflake>,
pub after: Option<Snowflake>, pub after: Option<Snowflake>,
@ -152,7 +169,7 @@ impl Default for GuildMemberSearchSchema {
} }
} }
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Eq, Ord)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Eq, Ord, Copy, Hash)]
pub struct GuildGetMembersQuery { pub struct GuildGetMembersQuery {
pub limit: Option<u16>, pub limit: Option<u16>,
pub after: Option<Snowflake>, pub after: Option<Snowflake>,
@ -206,7 +223,7 @@ pub struct ModifyGuildMemberProfileSchema {
pub emoji_id: Option<Snowflake>, pub emoji_id: Option<Snowflake>,
} }
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Eq, Ord)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Eq, Ord, Copy, Hash)]
/// The limit argument is a number between 1 and 1000. /// The limit argument is a number between 1 and 1000.
pub struct GuildBansQuery { pub struct GuildBansQuery {
pub before: Option<Snowflake>, pub before: Option<Snowflake>,
@ -214,7 +231,6 @@ pub struct GuildBansQuery {
pub limit: Option<u16>, pub limit: Option<u16>,
} }
/// Max query length is 32 characters. /// Max query length is 32 characters.
/// The limit argument is a number between 1 and 10, defaults to 10. /// The limit argument is a number between 1 and 10, defaults to 10.
pub type GuildBansSearchQuery = GenericSearchQueryWithLimit; pub type GuildBansSearchQuery = GenericSearchQueryWithLimit;
@ -262,7 +278,7 @@ pub struct GuildDiscoveryNsfwProperties {
pub description_banned_keywords: Vec<String>, pub description_banned_keywords: Vec<String>,
} }
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Copy)]
/// Activity metrics are recalculated weekly, as an 8-week rolling average. If they are not yet eligible to be calculated, all fields will be null. /// Activity metrics are recalculated weekly, as an 8-week rolling average. If they are not yet eligible to be calculated, all fields will be null.
/// ///
/// # Reference: /// # Reference:
@ -283,7 +299,7 @@ pub struct EmojiCreateSchema {
/// See <https://docs.discord.sex/reference#cdn-data> /// See <https://docs.discord.sex/reference#cdn-data>
pub image: String, pub image: String,
#[serde(default)] #[serde(default)]
pub roles: Vec<Snowflake> pub roles: Vec<Snowflake>,
} }
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
@ -291,7 +307,7 @@ pub struct EmojiCreateSchema {
/// See <https://docs.discord.sex/resources/emoji#modify-guild-emoji> /// See <https://docs.discord.sex/resources/emoji#modify-guild-emoji>
pub struct EmojiModifySchema { pub struct EmojiModifySchema {
pub name: Option<String>, pub name: Option<String>,
pub roles: Option<Vec<Snowflake>> pub roles: Option<Vec<Snowflake>>,
} }
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
@ -303,10 +319,10 @@ pub struct GuildPruneQuerySchema {
#[serde(default, skip_serializing_if = "Option::is_none")] #[serde(default, skip_serializing_if = "Option::is_none")]
pub compute_prune_count: Option<bool>, pub compute_prune_count: Option<bool>,
#[serde(default)] #[serde(default)]
pub include_roles: Vec<Snowflake> pub include_roles: Vec<Snowflake>,
} }
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Copy)]
/// # Reference: /// # Reference:
/// See <https://docs.discord.sex/resources/guild#get-guild-prune> /// See <https://docs.discord.sex/resources/guild#get-guild-prune>
pub struct GuildPruneResult { pub struct GuildPruneResult {
@ -325,7 +341,7 @@ pub struct GuildCreateStickerSchema {
pub tags: Option<String>, pub tags: Option<String>,
pub file_data: Vec<u8>, pub file_data: Vec<u8>,
#[serde(skip)] #[serde(skip)]
pub sticker_format_type: StickerFormatType pub sticker_format_type: StickerFormatType,
} }
impl GuildCreateStickerSchema { impl GuildCreateStickerSchema {
@ -333,7 +349,10 @@ impl GuildCreateStickerSchema {
pub async fn from_multipart(mut multipart: poem::web::Multipart) -> Result<Self, poem::Error> { pub async fn from_multipart(mut multipart: poem::web::Multipart) -> Result<Self, poem::Error> {
let mut _self = GuildCreateStickerSchema::default(); let mut _self = GuildCreateStickerSchema::default();
while let Some(field) = multipart.next_field().await? { while let Some(field) = multipart.next_field().await? {
let name = field.name().ok_or(poem::Error::from_string("All fields must be named", poem::http::StatusCode::BAD_REQUEST))?; let name = field.name().ok_or(poem::Error::from_string(
"All fields must be named",
poem::http::StatusCode::BAD_REQUEST,
))?;
match name { match name {
"name" => { "name" => {
_self.name = field.text().await?; _self.name = field.text().await?;
@ -346,17 +365,35 @@ impl GuildCreateStickerSchema {
} }
"file_data" => { "file_data" => {
if _self.name.is_empty() { if _self.name.is_empty() {
_self.name = field.file_name().map(String::from).ok_or(poem::Error::from_string("File name must be set", poem::http::StatusCode::BAD_REQUEST))?; _self.name =
field
.file_name()
.map(String::from)
.ok_or(poem::Error::from_string(
"File name must be set",
poem::http::StatusCode::BAD_REQUEST,
))?;
} }
_self.sticker_format_type = StickerFormatType::from_mime(field.content_type().ok_or(poem::Error::from_string("Content type must be set", poem::http::StatusCode::BAD_REQUEST))?).ok_or(poem::Error::from_string("Unknown sticker format", poem::http::StatusCode::BAD_REQUEST))?; _self.sticker_format_type = StickerFormatType::from_mime(
field.content_type().ok_or(poem::Error::from_string(
"Content type must be set",
poem::http::StatusCode::BAD_REQUEST,
))?,
)
.ok_or(poem::Error::from_string(
"Unknown sticker format",
poem::http::StatusCode::BAD_REQUEST,
))?;
_self.file_data = field.bytes().await?; _self.file_data = field.bytes().await?;
} }
_ => {} _ => {}
} }
} }
if _self.name.is_empty() || _self.file_data.is_empty() { if _self.name.is_empty() || _self.file_data.is_empty() {
return Err(poem::Error::from_string("At least the name and file_data are required", poem::http::StatusCode::BAD_REQUEST)); return Err(poem::Error::from_string(
"At least the name and file_data are required",
poem::http::StatusCode::BAD_REQUEST,
));
} }
Ok(_self) Ok(_self)
@ -366,7 +403,12 @@ impl GuildCreateStickerSchema {
pub fn to_multipart(&self) -> reqwest::multipart::Form { pub fn to_multipart(&self) -> reqwest::multipart::Form {
let mut form = reqwest::multipart::Form::new() let mut form = reqwest::multipart::Form::new()
.text("name", self.name.clone()) .text("name", self.name.clone())
.part("file_data", reqwest::multipart::Part::bytes(self.file_data.clone()).mime_str(self.sticker_format_type.to_mime()).unwrap()); .part(
"file_data",
reqwest::multipart::Part::bytes(self.file_data.clone())
.mime_str(self.sticker_format_type.to_mime())
.unwrap(),
);
if let Some(description) = &self.description { if let Some(description) = &self.description {
form = form.text("description", description.to_owned()); form = form.text("description", description.to_owned());
@ -388,7 +430,7 @@ pub struct GuildModifyStickerSchema {
#[serde(default)] #[serde(default)]
pub description: Option<String>, pub description: Option<String>,
#[serde(default)] #[serde(default)]
pub tags: Option<String> pub tags: Option<String>,
} }
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
@ -408,5 +450,5 @@ pub struct GuildTemplateCreateSchema {
/// Name of the template (1-100 characters) /// Name of the template (1-100 characters)
pub name: String, pub name: String,
/// Description of the template (max 120 characters) /// Description of the template (max 120 characters)
pub description: Option<String> pub description: Option<String>,
} }

View File

@ -7,7 +7,9 @@ use serde::{Deserialize, Serialize};
use crate::types::entities::{ use crate::types::entities::{
AllowedMention, Component, Embed, MessageReference, PartialDiscordFileAttachment, AllowedMention, Component, Embed, MessageReference, PartialDiscordFileAttachment,
}; };
use crate::types::{Attachment, EmbedType, Message, MessageFlags, MessageType, ReactionType, Snowflake}; use crate::types::{
Attachment, EmbedType, Message, MessageFlags, MessageType, ReactionType, Snowflake,
};
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)] #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
@ -25,7 +27,7 @@ pub struct MessageSendSchema {
pub attachments: Option<Vec<PartialDiscordFileAttachment>>, pub attachments: Option<Vec<PartialDiscordFileAttachment>>,
} }
#[derive(Debug)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum MessageSearchEndpoint { pub enum MessageSearchEndpoint {
GuildChannel(Snowflake), GuildChannel(Snowflake),
Channel(Snowflake), Channel(Snowflake),
@ -102,7 +104,7 @@ impl std::default::Default for MessageSearchQuery {
} }
} }
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum AuthorType { pub enum AuthorType {
User, User,
@ -116,7 +118,7 @@ pub enum AuthorType {
NotWebhook, NotWebhook,
} }
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum HasType { pub enum HasType {
Image, Image,
@ -148,15 +150,19 @@ pub enum HasType {
NotSnapshot, NotSnapshot,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(
Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash,
)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum SortType { pub enum SortType {
#[default] #[default]
Timestamp, Timestamp,
Relevance Relevance,
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(
Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash,
)]
pub enum SortOrder { pub enum SortOrder {
#[default] #[default]
#[serde(rename = "desc")] #[serde(rename = "desc")]
@ -198,10 +204,10 @@ pub struct MessageModifySchema {
pub attachments: Option<Vec<Attachment>>, pub attachments: Option<Vec<Attachment>>,
} }
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Copy, Eq, Hash, Ord)]
pub struct ReactionQuerySchema { pub struct ReactionQuerySchema {
pub after: Option<Snowflake>, pub after: Option<Snowflake>,
pub limit: Option<u32>, pub limit: Option<u32>,
#[serde(rename = "type")] #[serde(rename = "type")]
pub reaction_type: Option<ReactionType> pub reaction_type: Option<ReactionType>,
} }

View File

@ -2,10 +2,10 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this // License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
use serde::{Deserialize, Serialize};
use crate::types::{PermissionFlags, Snowflake}; use crate::types::{PermissionFlags, Snowflake};
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
/// Represents the schema which needs to be sent to create or modify a Role. /// Represents the schema which needs to be sent to create or modify a Role.
/// See: [https://docs.spacebar.chat/routes/#cmp--schemas-rolemodifyschema](https://docs.spacebar.chat/routes/#cmp--schemas-rolemodifyschema) /// See: [https://docs.spacebar.chat/routes/#cmp--schemas-rolemodifyschema](https://docs.spacebar.chat/routes/#cmp--schemas-rolemodifyschema)
@ -20,7 +20,7 @@ pub struct RoleCreateModifySchema {
pub position: Option<i32>, pub position: Option<i32>,
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
/// Represents the schema which needs to be sent to update a roles' position. /// Represents the schema which needs to be sent to update a roles' position.
/// See: [https://docs.spacebar.chat/routes/#cmp--schemas-rolepositionupdateschema](https://docs.spacebar.chat/routes/#cmp--schemas-rolepositionupdateschema) /// See: [https://docs.spacebar.chat/routes/#cmp--schemas-rolepositionupdateschema](https://docs.spacebar.chat/routes/#cmp--schemas-rolepositionupdateschema)

View File

@ -1,8 +1,8 @@
use crate::types::Snowflake;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::Snowflake;
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Copy)]
/// # Reference: /// # Reference:
/// See <https://docs.discord.sex/resources/voice#json-params> /// See <https://docs.discord.sex/resources/voice#json-params>
pub struct VoiceStateUpdateSchema { pub struct VoiceStateUpdateSchema {

View File

@ -1,13 +1,12 @@
use core::fmt;
use chrono::{LocalResult, NaiveDateTime}; use chrono::{LocalResult, NaiveDateTime};
use serde::{de, Deserialize, Deserializer}; use core::fmt;
use serde::de::Error; use serde::de::Error;
use serde::{de, Deserialize, Deserializer};
#[doc(hidden)] #[doc(hidden)]
#[derive(Debug)] #[derive(Debug, Copy, Clone)]
pub struct SecondsStringTimestampVisitor; pub struct SecondsStringTimestampVisitor;
/// Ser/de to/from timestamps in seconds /// Ser/de to/from timestamps in seconds
/// ///
/// Intended for use with `serde`'s `with` attribute. /// Intended for use with `serde`'s `with` attribute.
@ -37,12 +36,12 @@ pub struct SecondsStringTimestampVisitor;
/// ``` /// ```
pub mod ts_seconds_str { pub mod ts_seconds_str {
use core::fmt;
use chrono::{DateTime, LocalResult, Utc};
use super::SecondsStringTimestampVisitor;
use serde::{de, ser};
use chrono::TimeZone;
use super::serde_from; use super::serde_from;
use super::SecondsStringTimestampVisitor;
use chrono::TimeZone;
use chrono::{DateTime, LocalResult, Utc};
use core::fmt;
use serde::{de, ser};
/// Serialize a UTC datetime into an integer number of seconds since the epoch /// Serialize a UTC datetime into an integer number of seconds since the epoch
/// ///
@ -113,7 +112,10 @@ pub mod ts_seconds_str {
where where
E: de::Error, E: de::Error,
{ {
serde_from(Utc.timestamp_opt(value.parse::<i64>().map_err(|e| E::custom(e))?, 0), &value) serde_from(
Utc.timestamp_opt(value.parse::<i64>().map_err(|e| E::custom(e))?, 0),
&value,
)
} }
} }
} }
@ -146,10 +148,10 @@ pub mod ts_seconds_str {
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
pub mod ts_seconds_option_str { pub mod ts_seconds_option_str {
use core::fmt;
use chrono::{DateTime, Utc};
use serde::{de, ser};
use super::SecondsStringTimestampVisitor; use super::SecondsStringTimestampVisitor;
use chrono::{DateTime, Utc};
use core::fmt;
use serde::{de, ser};
/// Serialize a UTC datetime into an integer number of seconds since the epoch or none /// Serialize a UTC datetime into an integer number of seconds since the epoch or none
/// ///
@ -255,9 +257,7 @@ pub(crate) fn serde_from<T, E, V>(me: LocalResult<T>, _ts: &V) -> Result<T, E>
// TODO: Make actual error type // TODO: Make actual error type
match me { match me {
LocalResult::None => Err(E::custom("value is not a legal timestamp")), LocalResult::None => Err(E::custom("value is not a legal timestamp")),
LocalResult::Ambiguous(_min, _max) => { LocalResult::Ambiguous(_min, _max) => Err(E::custom("value is an ambiguous timestamp")),
Err(E::custom("value is an ambiguous timestamp"))
}
LocalResult::Single(val) => Ok(val), LocalResult::Single(val) => Ok(val),
} }
} }
@ -270,9 +270,11 @@ enum StringOrU64 {
} }
pub fn string_or_u64<'de, D>(d: D) -> Result<u64, D::Error> pub fn string_or_u64<'de, D>(d: D) -> Result<u64, D::Error>
where D: Deserializer<'de> { where
D: Deserializer<'de>,
{
match StringOrU64::deserialize(d)? { match StringOrU64::deserialize(d)? {
StringOrU64::String(s) => s.parse::<u64>().map_err(D::Error::custom), StringOrU64::String(s) => s.parse::<u64>().map_err(D::Error::custom),
StringOrU64::U64(u) => Ok(u) StringOrU64::U64(u) => Ok(u),
} }
} }

View File

@ -6,7 +6,7 @@ use std::net::SocketAddr;
use crate::errors::VoiceUdpError; use crate::errors::VoiceUdpError;
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
pub struct TokioBackend; pub struct TokioBackend;
pub type TokioSocket = tokio::net::UdpSocket; pub type TokioSocket = tokio::net::UdpSocket;

View File

@ -168,8 +168,7 @@ async fn create_dm() {
dm_channel dm_channel
.recipients .recipients
.as_ref() .as_ref()
.unwrap() .unwrap().first()
.get(0)
.unwrap() .unwrap()
.read() .read()
.unwrap() .unwrap()
@ -242,8 +241,7 @@ async fn remove_add_person_from_to_dm() {
dm_channel dm_channel
.recipients .recipients
.as_ref() .as_ref()
.unwrap() .unwrap().first()
.get(0)
.unwrap() .unwrap()
.read() .read()
.unwrap() .unwrap()

View File

@ -206,7 +206,7 @@ async fn test_recursive_self_updating_structs() {
let guild = bundle.user.gateway.observe(bundle.guild.clone()).await; let guild = bundle.user.gateway.observe(bundle.guild.clone()).await;
let inner_guild = guild.read().unwrap().clone(); let inner_guild = guild.read().unwrap().clone();
let guild_roles = inner_guild.roles; let guild_roles = inner_guild.roles;
let guild_role_inner = guild_roles.get(0).unwrap().read().unwrap().clone(); let guild_role_inner = guild_roles.first().unwrap().read().unwrap().clone();
assert_eq!(guild_role_inner.name, "yippieee".to_string()); assert_eq!(guild_role_inner.name, "yippieee".to_string());
common::teardown(bundle).await; common::teardown(bundle).await;
} }

View File

@ -114,7 +114,7 @@ async fn search_messages() {
.await .await
.unwrap(); .unwrap();
assert!(!query_result.is_empty()); assert!(!query_result.is_empty());
assert_eq!(query_result.get(0).unwrap().id, message.id); assert_eq!(query_result.first().unwrap().id, message.id);
} }
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
@ -139,8 +139,7 @@ async fn test_stickies() {
assert_eq!( assert_eq!(
Message::get_sticky(channel.id, &mut bundle.user) Message::get_sticky(channel.id, &mut bundle.user)
.await .await
.unwrap() .unwrap().first()
.get(0)
.unwrap() .unwrap()
.id, .id,
message.id message.id

View File

@ -50,7 +50,7 @@ async fn test_get_relationships() {
.unwrap(); .unwrap();
let relationships = user.get_relationships().await.unwrap(); let relationships = user.get_relationships().await.unwrap();
assert_eq!( assert_eq!(
relationships.get(0).unwrap().id, relationships.first().unwrap().id,
other_user.object.read().unwrap().id other_user.object.read().unwrap().id
); );
common::teardown(bundle).await common::teardown(bundle).await
@ -71,20 +71,20 @@ async fn test_modify_relationship_friends() {
.unwrap(); .unwrap();
let relationships = user.get_relationships().await.unwrap(); let relationships = user.get_relationships().await.unwrap();
assert_eq!( assert_eq!(
relationships.get(0).unwrap().id, relationships.first().unwrap().id,
other_user.object.read().unwrap().id other_user.object.read().unwrap().id
); );
assert_eq!( assert_eq!(
relationships.get(0).unwrap().relationship_type, relationships.first().unwrap().relationship_type,
RelationshipType::Incoming RelationshipType::Incoming
); );
let relationships = other_user.get_relationships().await.unwrap(); let relationships = other_user.get_relationships().await.unwrap();
assert_eq!( assert_eq!(
relationships.get(0).unwrap().id, relationships.first().unwrap().id,
user.object.read().unwrap().id user.object.read().unwrap().id
); );
assert_eq!( assert_eq!(
relationships.get(0).unwrap().relationship_type, relationships.first().unwrap().relationship_type,
RelationshipType::Outgoing RelationshipType::Outgoing
); );
let _ = user let _ = user
@ -95,7 +95,7 @@ async fn test_modify_relationship_friends() {
.get_relationships() .get_relationships()
.await .await
.unwrap() .unwrap()
.get(0) .first()
.unwrap() .unwrap()
.relationship_type, .relationship_type,
RelationshipType::Friends RelationshipType::Friends
@ -124,11 +124,11 @@ async fn test_modify_relationship_block() {
assert_eq!(relationships, Vec::<Relationship>::new()); assert_eq!(relationships, Vec::<Relationship>::new());
let relationships = other_user.get_relationships().await.unwrap(); let relationships = other_user.get_relationships().await.unwrap();
assert_eq!( assert_eq!(
relationships.get(0).unwrap().id, relationships.first().unwrap().id,
user.object.read().unwrap().id user.object.read().unwrap().id
); );
assert_eq!( assert_eq!(
relationships.get(0).unwrap().relationship_type, relationships.first().unwrap().relationship_type,
RelationshipType::Blocked RelationshipType::Blocked
); );
other_user.remove_relationship(user_id).await.unwrap(); other_user.remove_relationship(user_id).await.unwrap();

View File

@ -953,45 +953,7 @@ mod entities {
} }
mod guild { mod guild {
use std::hash::{Hash, Hasher}; use chorus::types::Guild;
use chorus::types::{Guild, GuildInvite};
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
#[cfg_attr(not(target_arch = "wasm32"), test)]
fn guild_hash() {
let id: u64 = 1;
let mut guild1 = Guild::default();
let mut guild2 = Guild::default();
guild1.id = id.into();
guild2.id = id.into();
let mut hasher1 = std::collections::hash_map::DefaultHasher::new();
guild1.hash(&mut hasher1);
let mut hasher2 = std::collections::hash_map::DefaultHasher::new();
guild2.hash(&mut hasher2);
assert_eq!(hasher1.finish(), hasher2.finish());
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
#[cfg_attr(not(target_arch = "wasm32"), test)]
fn guild_invite_hash() {
let id: u64 = 1;
let mut invite1 = GuildInvite::default();
let mut invite2 = GuildInvite::default();
invite1.channel_id = id.into();
invite2.channel_id = id.into();
invite1.guild_id = id.into();
invite2.guild_id = id.into();
let mut hasher1 = std::collections::hash_map::DefaultHasher::new();
invite1.hash(&mut hasher1);
let mut hasher2 = std::collections::hash_map::DefaultHasher::new();
invite2.hash(&mut hasher2);
assert_eq!(hasher1.finish(), hasher2.finish());
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
#[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(not(target_arch = "wasm32"), test)]
@ -1006,38 +968,6 @@ mod entities {
} }
} }
mod relationship {
use chorus::types::{IntoShared, Relationship, User};
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
#[cfg_attr(not(target_arch = "wasm32"), test)]
fn relationship_partial_eq() {
let user = User::default();
// These 2 users are different, because they do not have the same Snowflake "id".
let user_2 = User::default();
let relationship_1 = Relationship {
id: 32_u64.into(),
relationship_type: chorus::types::RelationshipType::Friends,
nickname: Some("Xenia".to_string()),
user: user.into_public_user().into_shared(),
since: None,
};
let relationship_2 = Relationship {
id: 32_u64.into(),
relationship_type: chorus::types::RelationshipType::Friends,
nickname: Some("Xenia".to_string()),
user: user_2.into_public_user().into_shared(),
since: None,
};
// This should succeed, even though the two users' IDs are different. This is because
// `User` is only `PartialEq`, and the actual user object is not checked, since the
// `RwLock` would have to be locked.
assert_eq!(relationship_1, relationship_2);
}
}
mod message { mod message {
use chorus::types::{Message, Snowflake}; use chorus::types::{Message, Snowflake};