diff --git a/twilight-model/src/channel/flags.rs b/twilight-model/src/channel/flags.rs index eeeb5ab50d4..a642ab54b65 100644 --- a/twilight-model/src/channel/flags.rs +++ b/twilight-model/src/channel/flags.rs @@ -1,10 +1,10 @@ use bitflags::bitflags; -use serde::{ - de::{Deserialize, Deserializer}, - ser::{Serialize, Serializer}, -}; +use serde::{Deserialize, Serialize}; bitflags! { + #[allow(clippy::unsafe_derive_deserialize)] + #[derive(Deserialize, Serialize)] + #[serde(transparent)] pub struct ChannelFlags: u64 { /// Channel is pinned in a forum. const PINNED = 1 << 1; @@ -13,21 +13,6 @@ bitflags! { } } -impl<'de> Deserialize<'de> for ChannelFlags { - fn deserialize>(deserializer: D) -> Result { - Ok(Self::from_bits_truncate(u64::deserialize(deserializer)?)) - } -} - -impl Serialize for ChannelFlags { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_u64(self.bits()) - } -} - #[cfg(test)] mod tests { use super::ChannelFlags; @@ -80,7 +65,16 @@ mod tests { &ChannelFlags::PINNED, &[Token::U64(ChannelFlags::PINNED.bits())], ); - // Deserialization truncates unknown bits. - serde_test::assert_de_tokens(&ChannelFlags::empty(), &[Token::U64(1 << 63)]); + // Safety: + // + // Deserialization doesn't truncate unknown bits. + // + // `bitflags` requires unsafe code to create bitflags with unknown bits + // due to an unorthodox definition of unsafe: + // + // + #[allow(unsafe_code)] + let value = unsafe { ChannelFlags::from_bits_unchecked(1 << 63) }; + serde_test::assert_de_tokens(&value, &[Token::U64(1 << 63)]); } } diff --git a/twilight-model/src/channel/message/flags.rs b/twilight-model/src/channel/message/flags.rs index 070f7da5bdd..d734c6e1598 100644 --- a/twilight-model/src/channel/message/flags.rs +++ b/twilight-model/src/channel/message/flags.rs @@ -1,11 +1,11 @@ use bitflags::bitflags; -use serde::{ - de::{Deserialize, Deserializer}, - ser::{Serialize, Serializer}, -}; +use serde::{Deserialize, Serialize}; bitflags! { /// Flags to signal state and modify the look of a message. + #[allow(clippy::unsafe_derive_deserialize)] + #[derive(Deserialize, Serialize)] + #[serde(transparent)] pub struct MessageFlags: u64 { /// Has been published to subscribed channels via Channel Following. const CROSSPOSTED = 1; @@ -34,21 +34,6 @@ bitflags! { } } -impl<'de> Deserialize<'de> for MessageFlags { - fn deserialize>(deserializer: D) -> Result { - Ok(Self::from_bits_truncate(u64::deserialize(deserializer)?)) - } -} - -impl Serialize for MessageFlags { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_u64(self.bits()) - } -} - #[cfg(test)] mod tests { use super::MessageFlags; @@ -111,7 +96,16 @@ mod tests { &MessageFlags::CROSSPOSTED, &[Token::U64(MessageFlags::CROSSPOSTED.bits())], ); - // Deserialization truncates unknown bits. - serde_test::assert_de_tokens(&MessageFlags::empty(), &[Token::U64(1 << 63)]); + // Safety: + // + // Deserialization doesn't truncate unknown bits. + // + // `bitflags` requires unsafe code to create bitflags with unknown bits + // due to an unorthodox definition of unsafe: + // + // + #[allow(unsafe_code)] + let value = unsafe { MessageFlags::from_bits_unchecked(1 << 63) }; + serde_test::assert_de_tokens(&value, &[Token::U64(1 << 63)]); } } diff --git a/twilight-model/src/gateway/presence/activity_flags.rs b/twilight-model/src/gateway/presence/activity_flags.rs index 4199e67f904..b6e84091693 100644 --- a/twilight-model/src/gateway/presence/activity_flags.rs +++ b/twilight-model/src/gateway/presence/activity_flags.rs @@ -1,10 +1,10 @@ use bitflags::bitflags; -use serde::{ - de::{Deserialize, Deserializer}, - ser::{Serialize, Serializer}, -}; +use serde::{Deserialize, Serialize}; bitflags! { + #[allow(clippy::unsafe_derive_deserialize)] + #[derive(Deserialize, Serialize)] + #[serde(transparent)] pub struct ActivityFlags: u64 { const INSTANCE = 1; const JOIN = 1 << 1; @@ -18,21 +18,6 @@ bitflags! { } } -impl<'de> Deserialize<'de> for ActivityFlags { - fn deserialize>(deserializer: D) -> Result { - Ok(Self::from_bits_truncate(u64::deserialize(deserializer)?)) - } -} - -impl Serialize for ActivityFlags { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_u64(self.bits()) - } -} - #[cfg(test)] mod tests { use super::ActivityFlags; @@ -92,7 +77,16 @@ mod tests { &ActivityFlags::EMBEDDED, &[Token::U64(ActivityFlags::EMBEDDED.bits())], ); - // Deserialization truncates unknown bits. - serde_test::assert_de_tokens(&ActivityFlags::empty(), &[Token::U64(1 << 63)]); + // Safety: + // + // Deserialization doesn't truncate unknown bits. + // + // `bitflags` requires unsafe code to create bitflags with unknown bits + // due to an unorthodox definition of unsafe: + // + // + #[allow(unsafe_code)] + let value = unsafe { ActivityFlags::from_bits_unchecked(1 << 63) }; + serde_test::assert_de_tokens(&value, &[Token::U64(1 << 63)]); } } diff --git a/twilight-model/src/guild/permissions.rs b/twilight-model/src/guild/permissions.rs index 39b383da147..e19b2c295c4 100644 --- a/twilight-model/src/guild/permissions.rs +++ b/twilight-model/src/guild/permissions.rs @@ -1,7 +1,8 @@ use bitflags::bitflags; use serde::{ - de::{Deserialize, Deserializer, Error as DeError, Visitor}, - ser::{Serialize, Serializer}, + de::{Deserializer, Error as DeError, Visitor}, + ser::Serializer, + Deserialize, Serialize, }; use std::fmt::{Formatter, Result as FmtResult}; @@ -78,7 +79,19 @@ impl<'de> Visitor<'de> for PermissionsVisitor { } fn visit_u64(self, v: u64) -> Result { - Ok(Permissions::from_bits_truncate(v)) + // Safety: + // + // `bitflags` requires unsafe code to create bitflags with unknown bits + // due to an unorthodox definition of unsafe: + // + // + // + // This is, funnily enough, how bitflags itself implements + // deserializers. + #[allow(unsafe_code)] + let permissions = unsafe { Permissions::from_bits_unchecked(v) }; + + Ok(permissions) } fn visit_str(self, v: &str) -> Result { @@ -191,7 +204,16 @@ mod tests { #[test] fn serde() { serde_test::assert_tokens(&Permissions::CREATE_INVITE, &[Token::Str("1")]); - // Deserialization truncates unknown bits. - serde_test::assert_de_tokens(&Permissions::empty(), &[Token::Str("9223372036854775808")]); + // Safety: + // + // Deserialization doesn't truncate unknown bits. + // + // `bitflags` requires unsafe code to create bitflags with unknown bits + // due to an unorthodox definition of unsafe: + // + // + #[allow(unsafe_code)] + let value = unsafe { Permissions::from_bits_unchecked(1 << 63) }; + serde_test::assert_de_tokens(&value, &[Token::Str("9223372036854775808")]); } } diff --git a/twilight-model/src/guild/system_channel_flags.rs b/twilight-model/src/guild/system_channel_flags.rs index aba67e369b1..068a8dc0fa5 100644 --- a/twilight-model/src/guild/system_channel_flags.rs +++ b/twilight-model/src/guild/system_channel_flags.rs @@ -1,10 +1,10 @@ use bitflags::bitflags; -use serde::{ - de::{Deserialize, Deserializer}, - ser::{Serialize, Serializer}, -}; +use serde::{Deserialize, Serialize}; bitflags! { + #[allow(clippy::unsafe_derive_deserialize)] + #[derive(Deserialize, Serialize)] + #[serde(transparent)] pub struct SystemChannelFlags: u64 { /// Suppress member join notifications. const SUPPRESS_JOIN_NOTIFICATIONS = 1; @@ -21,21 +21,6 @@ bitflags! { } } -impl<'de> Deserialize<'de> for SystemChannelFlags { - fn deserialize>(deserializer: D) -> Result { - Ok(Self::from_bits_truncate(u64::deserialize(deserializer)?)) - } -} - -impl Serialize for SystemChannelFlags { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_u64(self.bits()) - } -} - #[cfg(test)] mod tests { use super::SystemChannelFlags; @@ -109,7 +94,16 @@ mod tests { SystemChannelFlags::SUPPRESS_JOIN_NOTIFICATION_REPLIES.bits(), )], ); - // Deserialization truncates unknown bits. - serde_test::assert_de_tokens(&SystemChannelFlags::empty(), &[Token::U64(1 << 63)]); + // Safety: + // + // Deserialization doesn't truncate unknown bits. + // + // `bitflags` requires unsafe code to create bitflags with unknown bits + // due to an unorthodox definition of unsafe: + // + // + #[allow(unsafe_code)] + let value = unsafe { SystemChannelFlags::from_bits_unchecked(1 << 63) }; + serde_test::assert_de_tokens(&value, &[Token::U64(1 << 63)]); } } diff --git a/twilight-model/src/oauth/application_flags.rs b/twilight-model/src/oauth/application_flags.rs index 3cbe3719d3a..08a3bdcee76 100644 --- a/twilight-model/src/oauth/application_flags.rs +++ b/twilight-model/src/oauth/application_flags.rs @@ -1,10 +1,10 @@ use bitflags::bitflags; -use serde::{ - de::{Deserialize, Deserializer}, - ser::{Serialize, Serializer}, -}; +use serde::{Deserialize, Serialize}; bitflags! { + #[allow(clippy::unsafe_derive_deserialize)] + #[derive(Deserialize, Serialize)] + #[serde(transparent)] pub struct ApplicationFlags: u64 { /// Intent required for bots in 100 guilds or more to receive /// [`PresenceUpdate`] events. @@ -48,21 +48,6 @@ bitflags! { } } -impl<'de> Deserialize<'de> for ApplicationFlags { - fn deserialize>(deserializer: D) -> Result { - Ok(Self::from_bits_truncate(u64::deserialize(deserializer)?)) - } -} - -impl Serialize for ApplicationFlags { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_u64(self.bits()) - } -} - #[cfg(test)] mod tests { use super::ApplicationFlags; @@ -131,7 +116,16 @@ mod tests { &ApplicationFlags::GATEWAY_MESSAGE_CONTENT, &[Token::U64(ApplicationFlags::GATEWAY_MESSAGE_CONTENT.bits())], ); - // Deserialization truncates unknown bits. - serde_test::assert_de_tokens(&ApplicationFlags::empty(), &[Token::U64(1 << 63)]); + // Safety: + // + // Deserialization doesn't truncate unknown bits. + // + // `bitflags` requires unsafe code to create bitflags with unknown bits + // due to an unorthodox definition of unsafe: + // + // + #[allow(unsafe_code)] + let value = unsafe { ApplicationFlags::from_bits_unchecked(1 << 63) }; + serde_test::assert_de_tokens(&value, &[Token::U64(1 << 63)]); } } diff --git a/twilight-model/src/user/flags.rs b/twilight-model/src/user/flags.rs index fc48f191d85..e49a71a6b43 100644 --- a/twilight-model/src/user/flags.rs +++ b/twilight-model/src/user/flags.rs @@ -1,10 +1,10 @@ use bitflags::bitflags; -use serde::{ - de::{Deserialize, Deserializer}, - ser::{Serialize, Serializer}, -}; +use serde::{Deserialize, Serialize}; bitflags! { + #[allow(clippy::unsafe_derive_deserialize)] + #[derive(Deserialize, Serialize)] + #[serde(transparent)] pub struct UserFlags: u64 { /// Discord Employee. const STAFF = 1; @@ -45,21 +45,6 @@ bitflags! { } } -impl<'de> Deserialize<'de> for UserFlags { - fn deserialize>(deserializer: D) -> Result { - Ok(Self::from_bits_truncate(u64::deserialize(deserializer)?)) - } -} - -impl Serialize for UserFlags { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_u64(self.bits()) - } -} - #[cfg(test)] mod tests { #![allow(deprecated)] @@ -129,7 +114,16 @@ mod tests { &UserFlags::PARTNER, &[Token::U64(UserFlags::PARTNER.bits())], ); - // Deserialization truncates unknown bits. - serde_test::assert_de_tokens(&UserFlags::empty(), &[Token::U64(1 << 63)]); + // Safety: + // + // Deserialization doesn't truncate unknown bits. + // + // `bitflags` requires unsafe code to create bitflags with unknown bits + // due to an unorthodox definition of unsafe: + // + // + #[allow(unsafe_code)] + let value = unsafe { UserFlags::from_bits_unchecked(1 << 63) }; + serde_test::assert_de_tokens(&value, &[Token::U64(1 << 63)]); } }