use super::{
guild::Member,
id::{ChannelId, GuildId, RoleId, UserId},
user::User,
};
use chrono::{DateTime, Utc};
use serde::de::{self, Deserialize, Deserializer, Visitor, MapAccess, IgnoredAny};
use std::fmt;
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct VoiceRegion {
pub custom: bool,
pub deprecated: bool,
pub id: String,
pub name: String,
pub optimal: bool,
pub vip: bool,
}
#[derive(Clone, Serialize)]
#[non_exhaustive]
pub struct VoiceState {
pub channel_id: Option<ChannelId>,
pub deaf: bool,
pub guild_id: Option<GuildId>,
pub member: Option<Member>,
pub mute: bool,
pub self_deaf: bool,
pub self_mute: bool,
pub self_stream: Option<bool>,
pub self_video: bool,
pub session_id: String,
pub suppress: bool,
pub token: Option<String>,
pub user_id: UserId,
}
impl fmt::Debug for VoiceState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("VoiceState")
.field("channel_id", &self.channel_id)
.field("deaf", &self.deaf)
.field("guild_id", &self.guild_id)
.field("member", &self.member)
.field("mute", &self.mute)
.field("self_deaf", &self.self_deaf)
.field("self_mute", &self.self_mute)
.field("self_stream", &self.self_stream)
.field("self_video", &self.self_video)
.field("session_id", &self.session_id)
.field("suppress", &self.suppress)
.field("user_id", &self.user_id)
.finish()
}
}
impl<'de> Deserialize<'de> for VoiceState {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(Deserialize)]
#[serde(field_identifier, rename_all = "snake_case")]
enum Field {
ChannelId,
Deaf,
GuildId,
Member,
Mute,
SelfDeaf,
SelfMute,
SelfStream,
SelfVideo,
SessionId,
Suppress,
Token,
UserId,
}
#[derive(Deserialize)]
#[non_exhaustive]
struct PartialMember {
deaf: bool,
joined_at: Option<DateTime<Utc>>,
mute: bool,
nick: Option<String>,
roles: Vec<RoleId>,
user: User,
}
struct VoiceStateVisitor;
impl<'de> Visitor<'de> for VoiceStateVisitor {
type Value = VoiceState;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("struct VoiceState")
}
fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> Result<Self::Value, V::Error> {
let mut channel_id = None;
let mut deaf = None;
let mut guild_id = None;
let mut member = None;
let mut mute = None;
let mut self_deaf = None;
let mut self_mute = None;
let mut self_stream = None;
let mut self_video = None;
let mut session_id = None;
let mut suppress = None;
let mut token = None;
let mut user_id = None;
loop {
let key = match map.next_key() {
Ok(Some(key)) => key,
Ok(None) => break,
Err(_) => {
map.next_value::<IgnoredAny>()?;
continue;
}
};
match key {
Field::ChannelId => {
if channel_id.is_some() {
return Err(de::Error::duplicate_field("channel_id"));
}
channel_id = map.next_value()?;
}
Field::Deaf => {
if deaf.is_some() {
return Err(de::Error::duplicate_field("deaf"));
}
deaf = Some(map.next_value()?);
}
Field::GuildId => {
if guild_id.is_some() {
return Err(de::Error::duplicate_field("guild_id"));
}
guild_id = map.next_value()?;
}
Field::Member => {
if member.is_some() {
return Err(de::Error::duplicate_field("member"));
}
let partial_member: Option<PartialMember> = map.next_value()?;
if let Some(partial_member) = partial_member {
member = Some(Member {
deaf: partial_member.deaf,
guild_id: GuildId(0),
joined_at: partial_member.joined_at,
mute: partial_member.mute,
nick: partial_member.nick,
roles: partial_member.roles,
user: partial_member.user,
});
}
}
Field::Mute => {
if mute.is_some() {
return Err(de::Error::duplicate_field("mute"));
}
mute = Some(map.next_value()?);
}
Field::SelfDeaf => {
if self_deaf.is_some() {
return Err(de::Error::duplicate_field("self_deaf"));
}
self_deaf = Some(map.next_value()?);
}
Field::SelfMute => {
if self_mute.is_some() {
return Err(de::Error::duplicate_field("self_mute"));
}
self_mute = Some(map.next_value()?);
}
Field::SelfStream => {
if self_stream.is_some() {
return Err(de::Error::duplicate_field("self_stream"));
}
self_stream = map.next_value()?;
}
Field::SelfVideo => {
if self_video.is_some() {
return Err(de::Error::duplicate_field("self_video"));
}
self_video = Some(map.next_value()?);
}
Field::SessionId => {
if session_id.is_some() {
return Err(de::Error::duplicate_field("session_id"));
}
session_id = Some(map.next_value()?);
}
Field::Suppress => {
if suppress.is_some() {
return Err(de::Error::duplicate_field("suppress"));
}
suppress = Some(map.next_value()?);
}
Field::Token => {
if token.is_some() {
return Err(de::Error::duplicate_field("token"));
}
token = map.next_value()?;
}
Field::UserId => {
if user_id.is_some() {
return Err(de::Error::duplicate_field("user_id"));
}
user_id = Some(map.next_value()?);
}
}
}
let deaf = deaf.ok_or_else(|| de::Error::missing_field("deaf"))?;
let mute = mute.ok_or_else(|| de::Error::missing_field("mute"))?;
let self_deaf = self_deaf.ok_or_else(|| de::Error::missing_field("self_deaf"))?;
let self_mute = self_mute.ok_or_else(|| de::Error::missing_field("self_mute"))?;
let self_video = self_video.ok_or_else(|| de::Error::missing_field("self_video"))?;
let session_id = session_id.ok_or_else(|| de::Error::missing_field("session_id"))?;
let suppress = suppress.ok_or_else(|| de::Error::missing_field("suppress"))?;
let user_id = user_id.ok_or_else(|| de::Error::missing_field("user_id"))?;
if let (Some(guild_id), Some( member)) = (guild_id, member.as_mut()) {
member.guild_id = guild_id;
}
Ok(VoiceState {
channel_id,
deaf,
guild_id,
member,
mute,
self_deaf,
self_mute,
self_stream,
self_video,
session_id,
suppress,
token,
user_id,
})
}
}
const FIELDS: &[&str] = &[
"channel_id",
"deaf",
"guild_id",
"member",
"mute",
"self_deaf",
"self_mute",
"self_stream",
"self_video",
"session_id",
"suppress",
"token",
"user_id",
];
deserializer.deserialize_struct("VoiceState", FIELDS, VoiceStateVisitor)
}
}