From eade8d6967756a5a34ac3659fd7e23ad2f1429cf Mon Sep 17 00:00:00 2001 From: TotallyNot <44345987+TotallyNot@users.noreply.github.com> Date: Thu, 7 Mar 2024 13:01:49 +0100 Subject: [PATCH] added awards selections --- torn-api/Cargo.toml | 5 +- torn-api/src/send.rs | 2 - torn-api/src/user.rs | 144 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 146 insertions(+), 5 deletions(-) diff --git a/torn-api/Cargo.toml b/torn-api/Cargo.toml index d3719de..10a1e82 100644 --- a/torn-api/Cargo.toml +++ b/torn-api/Cargo.toml @@ -1,7 +1,8 @@ [package] name = "torn-api" -version = "0.6.4" +version = "0.6.5" edition = "2021" +rust-version = "1.75.0" authors = ["Pyrit [2111649]"] license = "MIT" repository = "https://github.com/TotallyNot/torn-api.rs.git" @@ -29,7 +30,7 @@ __common = [] [dependencies] serde = { version = "1", features = [ "derive" ] } serde_json = "1" -chrono = { version = "0.4", features = [ "serde" ], default-features = false } +chrono = { version = "0.4.31", features = [ "serde" ], default-features = false } async-trait = "0.1" thiserror = "1" futures = "0.3" diff --git a/torn-api/src/send.rs b/torn-api/src/send.rs index 9061c8c..706f8b6 100644 --- a/torn-api/src/send.rs +++ b/torn-api/src/send.rs @@ -11,9 +11,7 @@ where C: ApiClient, E: RequestExecutor, { - #[allow(dead_code)] client: &'a C, - #[allow(dead_code)] executor: E, } diff --git a/torn-api/src/user.rs b/torn-api/src/user.rs index bcc2185..26e0872 100644 --- a/torn-api/src/user.rs +++ b/torn-api/src/user.rs @@ -2,7 +2,10 @@ use serde::{ de::{self, MapAccess, Visitor}, Deserialize, Deserializer, }; -use std::collections::{BTreeMap, HashMap}; +use std::{ + collections::{BTreeMap, HashMap}, + iter::zip, +}; use torn_api_macros::{ApiCategory, IntoOwned}; @@ -30,6 +33,10 @@ pub enum UserSelection { Attacks, #[api(type = "HashMap", field = "icons")] Icons, + #[api(type = "Awards", flatten)] + Medals, + #[api(type = "Awards", flatten)] + Honors, } pub type Selection = UserSelection; @@ -586,6 +593,137 @@ pub struct EmploymentStatus { pub company: Company, } +#[derive(Debug, Clone, Copy)] +pub struct Award { + pub award_time: chrono::DateTime, +} + +pub trait AwardMarker { + fn award_key() -> &'static str; + fn time_key() -> &'static str; +} + +#[derive(Debug, Clone)] +pub struct Awards +where + T: AwardMarker, +{ + pub inner: BTreeMap, + marker: std::marker::PhantomData, +} + +impl std::ops::Deref for Awards +where + T: AwardMarker, +{ + type Target = BTreeMap; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl std::ops::DerefMut for Awards +where + T: AwardMarker, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl Awards +where + T: AwardMarker, +{ + pub fn into_inner(self) -> BTreeMap { + self.inner + } +} + +pub struct Medals; + +impl AwardMarker for Medals { + #[inline(always)] + fn award_key() -> &'static str { + "medals_awarded" + } + #[inline(always)] + fn time_key() -> &'static str { + "medals_time" + } +} + +pub struct Honors; + +impl AwardMarker for Honors { + #[inline(always)] + fn award_key() -> &'static str { + "honors_awarded" + } + #[inline(always)] + fn time_key() -> &'static str { + "honors_time" + } +} + +impl<'de, T> Deserialize<'de> for Awards +where + T: AwardMarker, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct AwardVisitor(std::marker::PhantomData) + where + T: AwardMarker; + + impl<'de, T> Visitor<'de> for AwardVisitor + where + T: AwardMarker, + { + type Value = Awards; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("struct awards") + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut awards: Option> = None; + let mut times: Option> = None; + + while let Some(key) = map.next_key::<&'de str>()? { + if key == T::award_key() { + awards = map.next_value()?; + } else if key == T::time_key() { + times = map.next_value()?; + } + } + + let awards = awards.ok_or_else(|| de::Error::missing_field(T::award_key()))?; + let times = times.ok_or_else(|| de::Error::missing_field(T::time_key()))?; + + Ok(Awards { + inner: zip( + awards, + times.into_iter().map(|t| Award { + award_time: chrono::DateTime::from_timestamp(t, 0).unwrap_or_default(), + }), + ) + .collect(), + marker: Default::default(), + }) + } + } + + deserializer.deserialize_map(AwardVisitor(Default::default())) + } +} + #[cfg(test)] mod tests { use super::*; @@ -605,6 +743,8 @@ mod tests { Selection::PersonalStats, Selection::Crimes, Selection::Attacks, + Selection::Medals, + Selection::Honors, ]) }) .await @@ -617,6 +757,8 @@ mod tests { response.crimes().unwrap(); response.attacks().unwrap(); response.attacks_full().unwrap(); + response.medals().unwrap(); + response.honors().unwrap(); } #[async_test]