twilight_model/gateway/payload/outgoing/
request_guild_members.rs1use crate::{
2    gateway::opcode::OpCode,
3    id::{
4        marker::{GuildMarker, UserMarker},
5        Id,
6    },
7};
8use serde::{Deserialize, Serialize};
9use std::{
10    error::Error,
11    fmt::{Display, Formatter, Result as FmtResult},
12};
13
14#[derive(Debug)]
18pub struct UserIdsError {
19    kind: UserIdsErrorType,
20}
21
22impl UserIdsError {
23    #[must_use = "retrieving the type has no effect if left unused"]
25    pub const fn kind(&self) -> &UserIdsErrorType {
26        &self.kind
27    }
28
29    #[allow(clippy::unused_self)]
31    #[must_use = "consuming the error and retrieving the source has no effect if left unused"]
32    pub fn into_source(self) -> Option<Box<dyn Error + Send + Sync>> {
33        None
34    }
35
36    #[must_use = "consuming the error into its parts has no effect if left unused"]
38    pub fn into_parts(self) -> (UserIdsErrorType, Option<Box<dyn Error + Send + Sync>>) {
39        (self.kind, None)
40    }
41
42    const fn too_many(ids: Vec<Id<UserMarker>>) -> Self {
43        Self {
44            kind: UserIdsErrorType::TooMany { ids },
45        }
46    }
47}
48
49impl Display for UserIdsError {
50    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
51        match &self.kind {
52            UserIdsErrorType::TooMany { ids } => {
53                Display::fmt(&ids.len(), f)?;
54                f.write_str(" user IDs were provided when only a maximum of 100 is allowed")
55            }
56        }
57    }
58}
59
60impl Error for UserIdsError {}
61
62#[derive(Debug)]
64#[non_exhaustive]
65pub enum UserIdsErrorType {
66    TooMany {
68        ids: Vec<Id<UserMarker>>,
70    },
71}
72
73#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
74pub struct RequestGuildMembers {
75    pub d: RequestGuildMembersInfo,
76    pub op: OpCode,
77}
78
79impl RequestGuildMembers {
80    pub const fn builder(guild_id: Id<GuildMarker>) -> RequestGuildMembersBuilder {
85        RequestGuildMembersBuilder::new(guild_id)
86    }
87}
88
89#[derive(Clone, Debug, Eq, PartialEq)]
90pub struct RequestGuildMembersBuilder {
91    guild_id: Id<GuildMarker>,
92    nonce: Option<String>,
93    presences: Option<bool>,
94}
95
96impl RequestGuildMembersBuilder {
97    pub const fn new(guild_id: Id<GuildMarker>) -> Self {
100        Self {
101            guild_id,
102            nonce: None,
103            presences: None,
104        }
105    }
106
107    #[must_use = "has no effect if not built into a RequestGuildMembers"]
111    pub fn nonce(self, nonce: impl Into<String>) -> Self {
112        self._nonce(nonce.into())
113    }
114
115    fn _nonce(mut self, nonce: String) -> Self {
116        self.nonce.replace(nonce);
117
118        self
119    }
120
121    #[must_use = "has no effect if not built into a RequestGuildMembers"]
125    pub fn presences(mut self, presences: bool) -> Self {
126        self.presences.replace(presences);
127
128        self
129    }
130
131    pub fn query(self, query: impl Into<String>, limit: Option<u64>) -> RequestGuildMembers {
159        self._query(query.into(), limit)
160    }
161
162    fn _query(self, query: String, limit: Option<u64>) -> RequestGuildMembers {
163        RequestGuildMembers {
164            d: RequestGuildMembersInfo {
165                guild_id: self.guild_id,
166                limit: Some(limit.unwrap_or_default()),
167                nonce: self.nonce,
168                presences: self.presences,
169                query: Some(query),
170                user_ids: None,
171            },
172            op: OpCode::RequestGuildMembers,
173        }
174    }
175
176    #[allow(clippy::missing_const_for_fn)]
201    pub fn user_id(self, user_id: Id<UserMarker>) -> RequestGuildMembers {
202        RequestGuildMembers {
203            d: RequestGuildMembersInfo {
204                guild_id: self.guild_id,
205                limit: None,
206                nonce: self.nonce,
207                presences: self.presences,
208                query: None,
209                user_ids: Some(RequestGuildMemberId::One(user_id)),
210            },
211            op: OpCode::RequestGuildMembers,
212        }
213    }
214
215    pub fn user_ids(
247        self,
248        user_ids: impl Into<Vec<Id<UserMarker>>>,
249    ) -> Result<RequestGuildMembers, UserIdsError> {
250        self._user_ids(user_ids.into())
251    }
252
253    fn _user_ids(self, user_ids: Vec<Id<UserMarker>>) -> Result<RequestGuildMembers, UserIdsError> {
254        if user_ids.len() > 100 {
255            return Err(UserIdsError::too_many(user_ids));
256        }
257
258        Ok(RequestGuildMembers {
259            d: RequestGuildMembersInfo {
260                guild_id: self.guild_id,
261                limit: None,
262                nonce: self.nonce,
263                presences: self.presences,
264                query: None,
265                user_ids: Some(RequestGuildMemberId::Multiple(user_ids)),
266            },
267            op: OpCode::RequestGuildMembers,
268        })
269    }
270}
271
272#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
273pub struct RequestGuildMembersInfo {
274    pub guild_id: Id<GuildMarker>,
276    #[serde(skip_serializing_if = "Option::is_none")]
277    pub limit: Option<u64>,
279    #[serde(skip_serializing_if = "Option::is_none")]
280    pub nonce: Option<String>,
281    #[serde(skip_serializing_if = "Option::is_none")]
282    pub presences: Option<bool>,
283    #[serde(skip_serializing_if = "Option::is_none")]
284    pub query: Option<String>,
285    #[serde(skip_serializing_if = "Option::is_none")]
286    pub user_ids: Option<RequestGuildMemberId<Id<UserMarker>>>,
287}
288
289#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
291#[serde(untagged)]
292pub enum RequestGuildMemberId<T> {
293    One(T),
295    Multiple(Vec<T>),
297}
298
299impl<T> From<T> for RequestGuildMemberId<T> {
300    fn from(id: T) -> Self {
301        Self::One(id)
302    }
303}
304
305impl<T> From<Vec<T>> for RequestGuildMemberId<T> {
306    fn from(ids: Vec<T>) -> Self {
307        Self::Multiple(ids)
308    }
309}
310
311#[cfg(test)]
312mod tests {
313    use super::RequestGuildMembersBuilder;
314    use static_assertions::assert_impl_all;
315    use std::fmt::Debug;
316
317    assert_impl_all!(
318        RequestGuildMembersBuilder: Clone,
319        Debug,
320        Eq,
321        PartialEq,
322        Send,
323        Sync
324    );
325}