brawl_api/model/
clubs.rs

1//! Models for the `/clubs/:tag` Brawl Stars API endpoint.
2//! Included by the feature `"clubs"`; removing that feature will disable the usage of this module.
3
4#[cfg(feature = "async")]
5use async_trait::async_trait;
6
7use serde::{self, Serialize, Deserialize};
8
9use crate::traits::{PropFetchable, FetchFrom, GetFetchProp};
10use crate::error::Result;
11
12#[cfg(feature = "async")]
13use crate::util::a_fetch_route;
14
15#[cfg(feature = "players")]
16use super::players::PlayerClub;
17use crate::http::Client;
18use crate::serde::{
19    serialize_smt_pointer, deserialize_number_from_string, deserialize_default_smt_pointer,
20    oxffffff_default,
21};
22use crate::http::routes::Route;
23use crate::util::{auto_hashtag, fetch_route};
24
25use std::fmt::{Display, Formatter};
26use crate::model::rankings::ClubRanking;
27use std::cmp::Ordering;
28
29pub use members::ClubMembers;
30
31/// The type of club (whether it's open, invite-only, or closed).
32#[non_exhaustive]
33#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
34#[serde(rename_all = "camelCase")]
35pub enum ClubType {
36    Open,
37    InviteOnly,
38    Closed,
39}
40
41impl Default for ClubType {
42    /// Defaults to [`ClubType::Open`] (new clubs start open).
43    ///
44    /// # Examples
45    ///
46    /// ```rust
47    /// use brawl_api::ClubType;
48    ///
49    /// assert_eq!(ClubType::default(), ClubType::Open);
50    /// ```
51    ///
52    /// [`ClubType::Open`]: ./enum.ClubType.html#variant.Open
53    fn default() -> ClubType { ClubType::Open }
54}
55
56impl Display for ClubType {
57    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
58        write!(
59            f, "{}",
60            match self {
61                ClubType::Open => "Open",
62                ClubType::InviteOnly => "InviteOnly",
63                ClubType::Closed => "Closed",
64            }
65        )
66    }
67}
68
69/// A struct representing a Brawl Stars club, with all of its data.
70/// Use [`Club::fetch`] to fetch one based on tag.
71///
72/// [`Club::fetch`]: ./struct.Club.html#method.fetch
73#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
74#[serde(rename_all = "camelCase")]
75pub struct Club {
76
77    /// The club's tag. **Note: this includes the initial '#'.**
78    #[serde(default)]
79    pub tag: String,
80
81    /// The club's name.
82    #[serde(default)]
83    pub name: String,
84
85    /// The club's description.
86    #[serde(default)]
87    pub description: Option<String>,
88
89    /// The club's trophies.
90    #[serde(default)]
91    pub trophies: usize,
92
93    /// The amount of trophies required to enter on this club, or 0 if it allows any amount.
94    #[serde(default)]
95    pub required_trophies: usize,
96
97    /// The members in this club, as a vector of [`ClubMember`] (note that the [`ClubMembers`]
98    /// struct is simply a smart pointer for `Vec<ClubMember>`).
99    ///
100    /// [`ClubMember`]: struct.ClubMember.html
101    /// [`ClubMembers`]: ./members/struct.ClubMembers.html
102    #[serde(default)]
103    #[serde(serialize_with="serialize_smt_pointer")]
104    #[serde(deserialize_with="deserialize_default_smt_pointer")]
105    pub members: ClubMembers, // Vec<ClubMember>,
106
107    /// The type of club (see [`ClubType`] docs).
108    ///
109    /// [`ClubType`]: ./enum.ClubType.html
110    #[serde(rename = "type")]
111    #[serde(default)]
112    pub club_type: ClubType
113}
114
115impl Default for Club {
116
117
118    /// Returns an instance of `Club` with initial values.
119    ///
120    /// # Examples
121    ///
122    /// ```rust
123    /// use brawl_api::{Club, ClubType, ClubMembers};
124    ///
125    /// assert_eq!(
126    ///     Club::default(),
127    ///     Club {
128    ///         tag: String::from(""),
129    ///         name: String::from(""),
130    ///         description: None,
131    ///         trophies: 0,
132    ///         required_trophies: 0,
133    ///         members: ClubMembers::default(),
134    ///         club_type: ClubType::Open,
135    ///     }
136    /// );
137    /// ```
138    fn default() -> Club {
139        Club {
140            tag: String::from(""),
141            name: String::from(""),
142            description: None,
143            trophies: 0,
144            required_trophies: 0,
145            members: ClubMembers::default(),
146            club_type: ClubType::Open,
147        }
148    }
149}
150
151impl GetFetchProp for Club {
152    type Property = str;
153
154    fn get_fetch_prop(&self) -> &str { &self.tag }
155
156    fn get_route(tag: &str) -> Route { Route::Club(auto_hashtag(tag)) }
157}
158
159#[cfg_attr(feature = "async", async_trait)]
160impl PropFetchable for Club {
161    type Property = str;
162
163    /// (Sync) Fetches a club from its tag.
164    ///
165    /// # Errors
166    ///
167    /// This function may error:
168    /// - While requesting (will return an [`Error::Request`]);
169    /// - After receiving a bad status code (API or other error - returns an [`Error::Status`]);
170    /// - After a ratelimit is indicated by the API, while also specifying when it is lifted ([`Error::Ratelimited`]);
171    /// - While parsing incoming JSON (will return an [`Error::Json`]).
172    ///
173    /// (All of those, of course, wrapped inside an `Err`.)
174    ///
175    /// # Examples
176    ///
177    /// ```rust,ignore
178    /// use brawl_api::{Client, Club, traits::*};
179    ///
180    /// # fn main() -> Result<(), Box<dyn ::std::error::Error>> {
181    /// let my_client = Client::new("my auth token");
182    /// let club = Club::fetch(&my_client, "#CLUBTAGHERE")?;
183    /// // now the data for the given club is available for use.
184    ///
185    /// # Ok(())
186    /// # }
187    /// ```
188    ///
189    /// [`Error::Request`]: error/enum.Error.html#variant.Request
190    /// [`Error::Status`]: error/enum.Error.html#variant.Status
191    /// [`Error::Ratelimited`]: error/enum.Error.html#variant.Ratelimited
192    /// [`Error::Json`]: error/enum.Error.html#variant.Json
193    fn fetch(client: &Client, tag: &str) -> Result<Club> {
194        let route = Club::get_route(tag);
195        let mut club = fetch_route::<Club>(client, &route)?;
196        club.members.tag = club.tag.clone();
197        Ok(club)
198    }
199
200    /// (Async) Fetches a club from its tag.
201    ///
202    /// # Errors
203    ///
204    /// This function may error:
205    /// - While requesting (will return an [`Error::Request`]);
206    /// - After receiving a bad status code (API or other error - returns an [`Error::Status`]);
207    /// - After a ratelimit is indicated by the API, while also specifying when it is lifted ([`Error::Ratelimited`]);
208    /// - While parsing incoming JSON (will return an [`Error::Json`]).
209    ///
210    /// (All of those, of course, wrapped inside an `Err`.)
211    ///
212    /// # Examples
213    ///
214    /// ```rust,ignore
215    /// use brawl_api::{Client, Club, traits::*};
216    ///
217    /// # async fn main() -> Result<(), Box<dyn ::std::error::Error>> {
218    /// let my_client = Client::new("my auth token");
219    /// let club = Club::a_fetch(&my_client, "#CLUBTAGHERE").await?;
220    /// // now the data for the given club is available for use.
221    ///
222    /// # Ok(())
223    /// # }
224    /// ```
225    ///
226    /// [`Error::Request`]: error/enum.Error.html#variant.Request
227    /// [`Error::Status`]: error/enum.Error.html#variant.Status
228    /// [`Error::Ratelimited`]: error/enum.Error.html#variant.Ratelimited
229    /// [`Error::Json`]: error/enum.Error.html#variant.Json
230    #[cfg(feature="async")]
231    async fn a_fetch(client: &Client, tag: &'async_trait str) -> Result<Club>
232        where Self: 'async_trait,
233              Self::Property: 'async_trait,
234    {
235        let route = Club::get_route(tag);
236        let mut club = a_fetch_route::<Club>(client, &route).await?;
237        club.members.tag = club.tag.clone();
238        Ok(club)
239    }
240}
241
242#[cfg_attr(feature = "async", async_trait)]
243#[cfg(feature = "players")]
244impl FetchFrom<PlayerClub> for Club {
245    /// (Sync) Fetches a `Club` using data from a [`PlayerClub`] object.
246    ///
247    /// [`PlayerClub`]: ../../players/player/struct.PlayerClub.html
248    fn fetch_from(client: &Client, p_club: &PlayerClub) -> Result<Club> {
249        Club::fetch(client, &p_club.tag)
250    }
251
252    /// (Async) Fetches a `Club` using data from a [`PlayerClub`] object.
253    ///
254    /// [`PlayerClub`]: ../../players/player/struct.PlayerClub.html
255    #[cfg(feature = "async")]
256    async fn a_fetch_from(client: &Client, p_club: &PlayerClub) -> Result<Club> {
257        Club::a_fetch(client, &p_club.tag).await
258    }
259}
260
261#[cfg_attr(feature = "async", async_trait)]
262#[cfg(feature = "rankings")]
263impl FetchFrom<ClubRanking> for Club {
264
265    /// (Sync) Fetches a `Club` using data from a [`ClubRanking`] object.
266    ///
267    /// [`ClubRanking`]: ../../rankings/clubs/struct.ClubRanking.html
268    fn fetch_from(client: &Client, c_ranking: &ClubRanking) -> Result<Club> {
269        Club::fetch(client, &c_ranking.tag)
270    }
271
272    /// (Async) Fetches a `Club` using data from a [`ClubRanking`] object.
273    ///
274    /// [`ClubRanking`]: ../../rankings/clubs/struct.ClubRanking.html
275    #[cfg(feature = "async")]
276    async fn a_fetch_from(client: &Client, c_ranking: &ClubRanking) -> Result<Club> {
277        Club::a_fetch(client, &c_ranking.tag).await
278    }
279}
280
281/// An enum representing a member's possible roles (See [`ClubMember`]).
282///
283/// [`ClubMember`]: ./struct.ClubMember.html
284#[non_exhaustive]
285#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
286#[serde(rename_all = "camelCase")]
287pub enum ClubMemberRole {
288    Member = 0,
289    Senior = 1,
290    VicePresident = 2,
291    President = 3,
292}
293
294impl Display for ClubMemberRole {
295    /// Writes this `ClubMemberRole` variant's name.
296    ///
297    /// # Examples
298    ///
299    /// ```rust
300    /// use brawl_api::ClubMemberRole;
301    ///
302    /// assert_eq!(
303    ///     format!("{}", ClubMemberRole::Senior),
304    ///     String::from("Senior")
305    /// );
306    /// ```
307    fn fmt(&self, f: &mut Formatter<'_>) -> ::std::fmt::Result {
308        write!(
309            f, "{}",
310            match *self {
311                ClubMemberRole::Member => "Member",
312                ClubMemberRole::Senior => "Senior",
313                ClubMemberRole::VicePresident => "VicePresident",
314                ClubMemberRole::President => "President",
315            }
316        )
317    }
318}
319
320impl PartialOrd for ClubMemberRole {
321    /// Compares and determines which `ClubMemberRole` is higher in the hierarchy:
322    /// `Member < Senior < VicePresident < President`.
323    ///
324    /// # Examples
325    ///
326    /// ```rust
327    /// use brawl_api::ClubMemberRole;
328    ///
329    /// // vice-president has more power (is higher in the hierarchy) than a normal Member
330    /// assert!(ClubMemberRole::Member < ClubMemberRole::VicePresident);
331    /// assert!(ClubMemberRole::President > ClubMemberRole::VicePresident);
332    /// assert!(ClubMemberRole::Senior > ClubMemberRole::Member);
333    /// assert!(ClubMemberRole::Member >= ClubMemberRole::Member);
334    /// ```
335    fn partial_cmp(&self, other: &ClubMemberRole) -> Option<Ordering> {
336        Some(self.cmp(other))
337    }
338}
339
340impl Ord for ClubMemberRole {
341    /// Compares and determines which `ClubMemberRole` is higher in the hierarchy:
342    /// `Member < Senior < VicePresident < President`.
343    ///
344    /// # Examples
345    ///
346    /// ```rust
347    /// use brawl_api::ClubMemberRole;
348    ///
349    /// // vice-president has more power (is higher in the hierarchy) than a normal Member
350    /// assert!(ClubMemberRole::Member < ClubMemberRole::VicePresident);
351    /// assert!(ClubMemberRole::President > ClubMemberRole::VicePresident);
352    /// assert!(ClubMemberRole::Senior > ClubMemberRole::Member);
353    /// assert!(ClubMemberRole::Member >= ClubMemberRole::Member);
354    /// ```
355    fn cmp(&self, other: &ClubMemberRole) -> Ordering {
356        (*self as u8).cmp(&(*other as u8))
357    }
358}
359
360impl Default for ClubMemberRole {
361    /// Defaults to [`ClubMemberRole::Member`] - that is the initial role that any club member
362    /// adquires after joining (it may be promoted later, though).
363    ///
364    /// # Examples
365    ///
366    /// ```rust
367    /// use brawl_api::ClubMemberRole;
368    ///
369    /// assert_eq!(ClubMemberRole::default(), ClubMemberRole::Member);
370    /// ```
371    ///
372    /// [`ClubMemberRole::Member`]: ./enum.ClubMemberRole.html#variant.Member
373    fn default() -> ClubMemberRole { ClubMemberRole::Member }
374}
375
376/// A struct representing a Brawl Stars club's member, with its club-relevant data
377/// (most importantly, its role). Use [`Player::fetch_from`] to fetch the full player data.
378///
379/// [`Player::fetch_from`]: ../players/player/struct.Player.html#method.fetch_from
380#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
381#[serde(rename_all = "camelCase")]
382pub struct ClubMember {
383
384    /// The member's tag.
385    #[serde(default)]
386    pub tag: String,
387
388    /// The member's name.
389    #[serde(default)]
390    pub name: String,
391
392    /// The member's trophies.
393    #[serde(default)]
394    pub trophies: usize,
395
396    /// The member's role in the guild. (Default is [`ClubMemberRole::Member`])
397    ///
398    /// [`ClubMemberRole::Member`]: ./enum.ClubMemberRole.html#variant.Member
399    #[serde(default)]
400    pub role: ClubMemberRole,
401
402    /// The member's name color, as an integer (Default is 0xffffff = 16777215 - this is used
403    /// when the data is not available).
404    #[serde(default = "oxffffff_default")]
405    #[serde(deserialize_with = "deserialize_number_from_string")]  // parse num
406    pub name_color: u64
407}
408
409impl PartialOrd for ClubMember {
410    /// Compares and determines which `ClubMember` has a higher role.
411    ///
412    /// # Examples
413    ///
414    /// (**NOTE:** Club members are not meant to be initialized, but rather obtained from
415    /// a fetched [`Club`] instance. They are only instantiated here for this example.)
416    ///
417    /// ```rust
418    /// use brawl_api::{ClubMember, ClubMemberRole};
419    ///
420    /// let member_1 = ClubMember { role: ClubMemberRole::Member, ..ClubMember::default() };
421    /// let member_2 = ClubMember { role: ClubMemberRole::VicePresident, ..ClubMember::default() };
422    ///
423    /// assert!(member_1 < member_2)  // vice-president has more power than a normal Member
424    /// ```
425    ///
426    /// [`Club`]: struct.Club.html
427    fn partial_cmp(&self, other: &ClubMember) -> Option<Ordering> {
428        Some(self.cmp(other))
429    }
430}
431
432impl Ord for ClubMember {
433    /// Compares and determines which `ClubMember` has a higher role.
434    ///
435    /// # Examples
436    ///
437    /// (**NOTE:** Club members are not meant to be initialized, but rather obtained from
438    /// a fetched [`Club`] instance. They are only instantiated here for this example.)
439    ///
440    /// ```rust
441    /// use brawl_api::{ClubMember, ClubMemberRole};
442    ///
443    /// let member_1 = ClubMember { role: ClubMemberRole::Member, ..ClubMember::default() };
444    /// let member_2 = ClubMember { role: ClubMemberRole::VicePresident, ..ClubMember::default() };
445    ///
446    /// assert!(member_1 < member_2)  // vice-president has more power than a normal Member
447    /// ```
448    ///
449    /// [`Club`]: struct.Club.html
450    fn cmp(&self, other: &ClubMember) -> Ordering {
451        self.role.cmp(&other.role)
452    }
453}
454
455impl Default for ClubMember {
456
457    /// Returns an instance of `ClubMember` with initial values.
458    ///
459    /// # Examples
460    ///
461    /// ```rust
462    /// use brawl_api::model::{ClubMember, ClubMemberRole};
463    ///
464    /// assert_eq!(
465    ///     ClubMember::default(),
466    ///     ClubMember {
467    ///         tag: String::from(""),
468    ///         name: String::from(""),
469    ///         trophies: 0,
470    ///         role: ClubMemberRole::default(),
471    ///         name_color: 0xff_ff_ff
472    ///     }
473    /// );
474    /// ```
475    fn default() -> ClubMember {
476        ClubMember {
477            tag: String::from(""),
478            name: String::from(""),
479            trophies: 0,
480            role: ClubMemberRole::default(),
481            name_color: 0xff_ff_ff
482        }
483    }
484}
485
486/// Contains the model for the `/clubs/:tag/members` endpoint, which simply retrieves a club's
487/// members without needing to get the rest of the data.
488pub mod members {
489    use super::*;
490    use std::ops::{Deref, DerefMut};
491
492    /// Represents a list of Club members, without relating to a previous [`Club`] object.
493    /// This is only used if one does not want to fetch full club data, but only its members.
494    ///
495    /// Use [`ClubMembers::fetch`] to fetch the members from a specific club tag.
496    /// 
497    /// [`Club`]: ../struct.Club.html
498    /// [`ClubMembers::fetch`]: #method.fetch
499    #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
500    pub struct ClubMembers {
501        /// The tag of the club whose members were fetched.
502        #[serde(skip)]  // artificial
503        pub tag: String,
504
505        /// The fetched members of the specified club.
506        #[serde(default)]
507        pub items: Vec<ClubMember>
508    }
509
510    impl Deref for ClubMembers {
511        type Target = Vec<ClubMember>;
512
513        /// Obtain the club's members - dereferencing returns the [`items`] field.
514        ///
515        /// # Examples
516        ///
517        /// ```rust,ignore
518        /// use brawl_api::{Client, ClubMembers, traits::*};
519        ///
520        /// # fn main() -> Result<(), Box<dyn ::std::error::Error>> {
521        /// let client = Client::new("my auth token");
522        /// let members = ClubMembers::fetch(
523        ///     &client,            // <- the client containing the auth key
524        ///     "#CLUB_TAG_HERE"  // <- the club whose members should be fetched
525        /// )?;
526        ///
527        /// assert_eq!(members.items, *members);
528        ///
529        /// #     Ok(())
530        /// # }
531        ///
532        /// ```
533        ///
534        /// [`items`]: #structfield.items
535        fn deref(&self) -> &Vec<ClubMember> {
536            &self.items
537        }
538    }
539
540    impl DerefMut for ClubMembers {
541        /// Obtain the club's members - dereferencing returns the [`items`] field.
542        ///
543        /// # Examples
544        ///
545        /// ```rust,ignore
546        /// use brawl_api::{Client, ClubMembers, traits::*};
547        ///
548        /// # fn main() -> Result<(), Box<dyn ::std::error::Error>> {
549        /// let client = Client::new("my auth token");
550        /// let members = ClubMembers::fetch(
551        ///     &client,            // <- the client containing the auth key
552        ///     "#CLUB_TAG_HERE"  // <- the club whose members should be fetched
553        /// )?;
554        ///
555        /// assert_eq!(members.items, *members);
556        ///
557        /// #     Ok(())
558        /// # }
559        ///
560        /// ```
561        ///
562        /// [`items`]: #structfield.items
563        fn deref_mut(&mut self) -> &mut Vec<ClubMember> {
564            &mut self.items
565        }
566    }
567
568    impl GetFetchProp for ClubMembers {
569        type Property = str;
570
571        fn get_fetch_prop(&self) -> &str {
572            &*self.tag
573        }
574
575        fn get_route(tag: &str) -> Route {
576            Route::ClubMembers(auto_hashtag(tag))
577        }
578    }
579
580    impl From<Club> for ClubMembers {
581        /// Simply returns a given [`Club`]'s [`members`][Club.members] field.
582        ///
583        /// [`Club`]: ../struct.Club.html
584        /// [Club.members]: ../struct.Club.html#structfield.members
585        fn from(club: Club) -> ClubMembers {
586            club.members
587        }
588    }
589
590    impl From<&Club> for ClubMembers {
591        /// Simply returns a given [`Club`]'s [`members`][Club.members] field,
592        /// **while cloning**.
593        ///
594        /// [`Club`]: ../struct.Club.html
595        /// [Club.members]: ../struct.Club.html#structfield.members
596        fn from(club: &Club) -> ClubMembers {
597            club.members.to_owned()
598        }
599    }
600
601    impl<'a> From<&'a Club> for &'a ClubMembers {
602        /// Simply returns a given [`Club`]'s [`members`][Club.members] field.
603        ///
604        /// [`Club`]: ../struct.Club.html
605        /// [Club.members]: ../struct.Club.html#structfield.members
606        fn from(club: &'a Club) -> Self {
607            (&club.members) as &'a ClubMembers
608        }
609    }
610
611    #[cfg_attr(feature = "async", async_trait)]
612    impl PropFetchable for ClubMembers {
613        type Property = str;
614
615        /// (Sync) Fetches a club's members, given its tag, without fetching the rest of the data.
616        /// (If it is desired to fetch the rest of the data as well, simply fetching a [`Club`] is
617        /// enough, since that also fetches all of the members.)
618        ///
619        /// # Errors
620        ///
621        /// This function may error:
622        /// - While requesting (will return an [`Error::Request`]);
623        /// - After receiving a bad status code (API or other error - returns an [`Error::Status`]);
624        /// - After a ratelimit is indicated by the API, while also specifying when it is lifted ([`Error::Ratelimited`]);
625        /// - While parsing incoming JSON (will return an [`Error::Json`]).
626        ///
627        /// (All of those, of course, wrapped inside an `Err`.)
628        ///
629        /// # Examples
630        ///
631        /// ```rust,ignore
632        /// use brawl_api::{Client, ClubMembers, traits::*};
633        ///
634        /// # fn main() -> Result<(), Box<dyn ::std::error::Error>> {
635        /// let my_client = Client::new("my auth token");
636        /// let club_members = ClubMembers::fetch(&my_client, "#CLUBTAGHERE")?;
637        /// // now the members of the club with the given tag are available in the code
638        ///
639        /// # Ok(())
640        /// # }
641        /// ```
642        ///
643        /// [`Club`]: ../struct.Club.html
644        /// [`Error::Request`]: error/enum.Error.html#variant.Request
645        /// [`Error::Status`]: error/enum.Error.html#variant.Status
646        /// [`Error::Ratelimited`]: error/enum.Error.html#variant.Ratelimited
647        /// [`Error::Json`]: error/enum.Error.html#variant.Json
648        fn fetch(client: &Client, tag: &str) -> Result<ClubMembers> {
649            let route = Self::get_route(tag);
650            let mut members = fetch_route::<ClubMembers>(client, &route)?;
651            members.tag = tag.to_owned();
652            Ok(members)
653        }
654
655        /// (Async) Fetches a club's members, given its tag, without fetching the rest of the data.
656        /// (If it is desired to fetch the rest of the data as well, simply fetching a [`Club`] is
657        /// enough, since that also fetches all of the members.)
658        ///
659        /// # Errors
660        ///
661        /// This function may error:
662        /// - While requesting (will return an [`Error::Request`]);
663        /// - After receiving a bad status code (API or other error - returns an [`Error::Status`]);
664        /// - After a ratelimit is indicated by the API, while also specifying when it is lifted ([`Error::Ratelimited`]);
665        /// - While parsing incoming JSON (will return an [`Error::Json`]).
666        ///
667        /// (All of those, of course, wrapped inside an `Err`.)
668        ///
669        /// # Examples
670        ///
671        /// ```rust,ignore
672        /// use brawl_api::{Client, ClubMembers, traits::*};
673        ///
674        /// # async fn main() -> Result<(), Box<dyn ::std::error::Error>> {
675        /// let my_client = Client::new("my auth token");
676        /// let club_members = ClubMembers::a_fetch(&my_client, "#CLUBTAGHERE").await?;
677        /// // now the members of the club with the given tag are available in the code
678        ///
679        /// # Ok(())
680        /// # }
681        /// ```
682        ///
683        /// [`Club`]: ../struct.Club.html
684        /// [`Error::Request`]: error/enum.Error.html#variant.Request
685        /// [`Error::Status`]: error/enum.Error.html#variant.Status
686        /// [`Error::Ratelimited`]: error/enum.Error.html#variant.Ratelimited
687        /// [`Error::Json`]: error/enum.Error.html#variant.Json
688        #[cfg(feature="async")]
689        async fn a_fetch(client: &Client, tag: &'async_trait str) -> Result<ClubMembers>
690            where Self: 'async_trait,
691                  Self::Property: 'async_trait,
692        {
693            let route = ClubMembers::get_route(tag);
694            let mut members = a_fetch_route::<ClubMembers>(client, &route).await?;
695            members.tag = tag.to_owned();
696            Ok(members)
697        }
698    }
699
700    impl Default for ClubMembers {
701        /// Returns an instance of `ClubMembers` with initial values.
702        ///
703        /// # Examples
704        ///
705        /// ```rust
706        /// use brawl_api::model::ClubMembers;
707        ///
708        /// assert_eq!(
709        ///     ClubMembers::default(),
710        ///     ClubMembers {
711        ///         tag: String::from(""),
712        ///         items: vec![],
713        ///     }
714        /// );
715        /// ```
716        fn default() -> ClubMembers {
717            ClubMembers { tag: String::from(""), items: vec![] }
718        }
719    }
720}
721
722///////////////////////////////////   tests   ///////////////////////////////////
723
724#[cfg(test)]
725mod tests {
726    use std::result::Result as StdResult;
727    use super::*;
728    use crate::error::Error as BrawlError;
729    use serde_json;
730
731    /// Tests for club deserialization from API-provided JSON.
732    #[test]
733    fn club_deser() -> StdResult<(), Box<dyn ::std::error::Error>> {
734        let club_json_s = r##"{
735  "tag": "#GGGGGGG",
736  "name": "Club",
737  "description": "Brawl Stars club",
738  "type": "open",
739  "requiredTrophies": 1000,
740  "trophies": 60000,
741  "members": [
742    {
743      "tag": "#PPP200JJJ",
744      "name": "Member #1",
745      "nameColor": "0xffff8afb",
746      "role": "vicePresident",
747      "trophies": 500
748    },
749    {
750      "tag": "#CCCCCCCCCC",
751      "name": "Member #2",
752      "nameColor": "0xff1ba5f5",
753      "role": "president",
754      "trophies": 200
755    },
756    {
757      "tag": "#VVVVVVVVV",
758      "name": "Member #3",
759      "nameColor": "0xffffff",
760      "role": "member",
761      "trophies": 8500
762    },
763    {
764      "tag": "#9999999999",
765      "name": "Member #4",
766      "nameColor": "0xff4ddba2",
767      "role": "member",
768      "trophies": 20000
769    },
770    {
771      "tag": "#UUUUUU888",
772      "name": "Member #5",
773      "nameColor": "0xff1ba5f5",
774      "role": "senior",
775      "trophies": 4500
776    },
777    {
778      "tag": "#JJJJJJJJJ",
779      "name": "Member ██▬█",
780      "nameColor": "0xff1ba5f5",
781      "role": "member",
782      "trophies": 26300
783    }
784  ]
785}"##;
786
787        let club: Club = serde_json::from_str::<Club>(club_json_s)
788            .map_err(BrawlError::Json)?;
789
790        assert_eq!(
791            club,
792            Club {
793                tag: String::from("#GGGGGGG"),
794                name: String::from("Club"),
795                description: Some(String::from("Brawl Stars club")),
796                club_type: ClubType::Open,
797                required_trophies: 1000,
798                trophies: 60000,
799                members: ClubMembers {
800                    items: vec![
801                        ClubMember {
802                            tag: String::from("#PPP200JJJ"),
803                            name: String::from("Member #1"),
804                            name_color: 0xffff8afb,
805                            role: ClubMemberRole::VicePresident,
806                            trophies: 500
807                        },
808                        ClubMember {
809                            tag: String::from("#CCCCCCCCCC"),
810                            name: String::from("Member #2"),
811                            name_color: 0xff1ba5f5,
812                            role: ClubMemberRole::President,
813                            trophies: 200
814                        },
815                        ClubMember {
816                            tag: String::from("#VVVVVVVVV"),
817                            name: String::from("Member #3"),
818                            name_color: 0xffffff,
819                            role: ClubMemberRole::Member,
820                            trophies: 8500
821                        },
822                        ClubMember {
823                            tag: String::from("#9999999999"),
824                            name: String::from("Member #4"),
825                            name_color: 0xff4ddba2,
826                            role: ClubMemberRole::Member,
827                            trophies: 20000
828                        },
829                        ClubMember {
830                            tag: String::from("#UUUUUU888"),
831                            name: String::from("Member #5"),
832                            name_color: 0xff1ba5f5,
833                            role: ClubMemberRole::Senior,
834                            trophies: 4500
835                        },
836                        ClubMember {
837                            tag: String::from("#JJJJJJJJJ"),
838                            name: String::from("Member ██▬█"),
839                            name_color: 0xff1ba5f5,
840                            role: ClubMemberRole::Member,
841                            trophies: 26300
842                        }
843                    ],
844                    ..ClubMembers::default()
845                }
846            }
847        );
848
849        Ok(())
850    }
851
852    /// Tests for ClubMembers deserialization from API-provided JSON.
853    #[test]
854    fn club_members_deser() -> StdResult<(), Box<dyn ::std::error::Error>> {
855        let cm_json_s = r##"{
856  "items": [
857    {
858      "tag": "#PPP200JJJ",
859      "name": "Member #1",
860      "nameColor": "0xffff8afb",
861      "role": "vicePresident",
862      "trophies": 500
863    },
864    {
865      "tag": "#CCCCCCCCCC",
866      "name": "Member #2",
867      "nameColor": "0xff1ba5f5",
868      "role": "president",
869      "trophies": 200
870    },
871    {
872      "tag": "#VVVVVVVVV",
873      "name": "Member #3",
874      "nameColor": "0xffffff",
875      "role": "member",
876      "trophies": 8500
877    },
878    {
879      "tag": "#9999999999",
880      "name": "Member #4",
881      "nameColor": "0xff4ddba2",
882      "role": "member",
883      "trophies": 20000
884    },
885    {
886      "tag": "#UUUUUU888",
887      "name": "Member #5",
888      "nameColor": "0xff1ba5f5",
889      "role": "senior",
890      "trophies": 4500
891    },
892    {
893      "tag": "#JJJJJJJJJ",
894      "name": "Member ██▬█",
895      "nameColor": "0xff1ba5f5",
896      "role": "member",
897      "trophies": 26300
898    }
899  ],
900  "paging": {
901    "cursors": {}
902  }
903}"##;
904        let club_members: ClubMembers = serde_json::from_str::<ClubMembers>(cm_json_s)
905            .map_err(BrawlError::Json)?;
906
907        assert_eq!(
908            club_members,
909            ClubMembers {
910                items: vec![
911                    ClubMember {
912                        tag: String::from("#PPP200JJJ"),
913                        name: String::from("Member #1"),
914                        name_color: 0xffff8afb,
915                        role: ClubMemberRole::VicePresident,
916                        trophies: 500
917                    },
918                    ClubMember {
919                        tag: String::from("#CCCCCCCCCC"),
920                        name: String::from("Member #2"),
921                        name_color: 0xff1ba5f5,
922                        role: ClubMemberRole::President,
923                        trophies: 200
924                    },
925                    ClubMember {
926                        tag: String::from("#VVVVVVVVV"),
927                        name: String::from("Member #3"),
928                        name_color: 0xffffff,
929                        role: ClubMemberRole::Member,
930                        trophies: 8500
931                    },
932                    ClubMember {
933                        tag: String::from("#9999999999"),
934                        name: String::from("Member #4"),
935                        name_color: 0xff4ddba2,
936                        role: ClubMemberRole::Member,
937                        trophies: 20000
938                    },
939                    ClubMember {
940                        tag: String::from("#UUUUUU888"),
941                        name: String::from("Member #5"),
942                        name_color: 0xff1ba5f5,
943                        role: ClubMemberRole::Senior,
944                        trophies: 4500
945                    },
946                    ClubMember {
947                        tag: String::from("#JJJJJJJJJ"),
948                        name: String::from("Member ██▬█"),
949                        name_color: 0xff1ba5f5,
950                        role: ClubMemberRole::Member,
951                        trophies: 26300
952                    }
953                ],
954                ..ClubMembers::default()
955            }
956        );
957
958        Ok(())
959    }
960}
961