use crate::{
client::Client,
error::Error as HttpError,
request::{validate, Pending, Request},
routing::Route,
};
use hyper::body::Bytes;
use serde::de::DeserializeSeed;
use std::{
error::Error,
fmt::{Display, Formatter, Result as FmtResult},
future::Future,
pin::Pin,
task::{Context, Poll},
};
use twilight_model::{
guild::member::{Member, MemberDeserializer},
id::{GuildId, UserId},
};
#[cfg(not(feature = "simd-json"))]
use serde_json::Value;
#[cfg(feature = "simd-json")]
use simd_json::value::OwnedValue as Value;
#[derive(Debug)]
pub struct GetGuildMembersError {
kind: GetGuildMembersErrorType,
}
impl GetGuildMembersError {
#[must_use = "retrieving the type has no effect if left unused"]
pub const fn kind(&self) -> &GetGuildMembersErrorType {
&self.kind
}
#[allow(clippy::unused_self)]
#[must_use = "consuming the error and retrieving the source has no effect if left unused"]
pub fn into_source(self) -> Option<Box<dyn Error + Send + Sync>> {
None
}
#[must_use = "consuming the error into its parts has no effect if left unused"]
pub fn into_parts(
self,
) -> (
GetGuildMembersErrorType,
Option<Box<dyn Error + Send + Sync>>,
) {
(self.kind, None)
}
}
impl Display for GetGuildMembersError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match &self.kind {
GetGuildMembersErrorType::LimitInvalid { .. } => f.write_str("the limit is invalid"),
}
}
}
impl Error for GetGuildMembersError {}
#[derive(Debug)]
#[non_exhaustive]
pub enum GetGuildMembersErrorType {
LimitInvalid {
limit: u64,
},
}
#[derive(Default)]
struct GetGuildMembersFields {
after: Option<UserId>,
limit: Option<u64>,
presences: Option<bool>,
}
pub struct GetGuildMembers<'a> {
fields: GetGuildMembersFields,
fut: Option<Pending<'a, Bytes>>,
guild_id: GuildId,
http: &'a Client,
}
impl<'a> GetGuildMembers<'a> {
pub(crate) fn new(http: &'a Client, guild_id: GuildId) -> Self {
Self {
fields: GetGuildMembersFields::default(),
fut: None,
guild_id,
http,
}
}
pub fn after(mut self, after: UserId) -> Self {
self.fields.after.replace(after);
self
}
pub fn limit(mut self, limit: u64) -> Result<Self, GetGuildMembersError> {
if !validate::get_guild_members_limit(limit) {
return Err(GetGuildMembersError {
kind: GetGuildMembersErrorType::LimitInvalid { limit },
});
}
self.fields.limit.replace(limit);
Ok(self)
}
pub fn presences(mut self, presences: bool) -> Self {
self.fields.presences.replace(presences);
self
}
fn start(&mut self) -> Result<(), HttpError> {
let request = Request::from_route(Route::GetGuildMembers {
after: self.fields.after.map(|x| x.0),
guild_id: self.guild_id.0,
limit: self.fields.limit,
presences: self.fields.presences,
});
self.fut.replace(Box::pin(self.http.request_bytes(request)));
Ok(())
}
}
impl Future for GetGuildMembers<'_> {
type Output = Result<Vec<Member>, HttpError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.fut.is_none() {
self.as_mut().start()?;
}
let fut = self.fut.as_mut().expect("future is created");
match fut.as_mut().poll(cx) {
Poll::Ready(res) => {
let bytes = res?;
let mut members = Vec::new();
let mut bytes = bytes.as_ref().to_vec();
let values =
crate::json::from_slice::<Vec<Value>>(&mut bytes).map_err(HttpError::json)?;
for value in values {
let member_deserializer = MemberDeserializer::new(self.guild_id);
members.push(
member_deserializer
.deserialize(value)
.map_err(HttpError::json)?,
);
}
Poll::Ready(Ok(members))
}
Poll::Pending => Poll::Pending,
}
}
}