From befde73950b97830b2c76344985c945daae8a829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merryweather=20=CE=BC?= Date: Mon, 29 Apr 2024 16:34:42 -0500 Subject: [PATCH 1/5] Add more context to `api` --- src/api/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/api/mod.rs b/src/api/mod.rs index 2704424..309570f 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,6 +1,9 @@ -//! The main module where obtaining the data happens. +//! This is where the main asynchronous (and if elligble, blocking) API implementation is. +//! You are able to obtain data about multiple entities in the game here. + #[cfg(feature = "blocking")] pub mod blocking; + pub mod currency; pub mod enemy; pub mod equipment; From 1ee7e527c344e2dca1c21b4d969ddc03d41a84fa Mon Sep 17 00:00:00 2001 From: Bibi Reden Date: Sat, 4 May 2024 22:30:31 -0500 Subject: [PATCH 2/5] Derive serde for ID, and some few adjustments --- src/api/mod.rs | 3 ++- src/api/summon.rs | 15 ++++++++++----- src/filter/student.rs | 2 +- src/types/mod.rs | 21 +-------------------- src/types/students/mod.rs | 4 +--- 5 files changed, 15 insertions(+), 30 deletions(-) diff --git a/src/api/mod.rs b/src/api/mod.rs index 309570f..3875d08 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -30,9 +30,10 @@ pub(crate) mod internal { /// Contains the endpoints for the data, they mainly just represent the path of what data is obtained. #[derive(Debug, Display)] pub enum Endpoint { + _Localization, + _Voice, _Furniture, _Items, - _Localization, Enemies, Equipment, Currency, diff --git a/src/api/summon.rs b/src/api/summon.rs index 93ed9dc..f35d71d 100644 --- a/src/api/summon.rs +++ b/src/api/summon.rs @@ -2,14 +2,19 @@ use std::borrow::Borrow; -use super::{internal::Endpoint, BlueArchiveError, Client, Language, Result, Summon}; +use super::{ + internal::{fetch_response, Endpoint}, + BlueArchiveError, Client, Language, Result, Summon, +}; /// Fetches all **[`Summons`][`Summon`]** from the data. pub async fn fetch_all_summons( language: impl Borrow, ) -> Result, BlueArchiveError> { - let response = - super::internal::fetch_response(&Endpoint::Summons, language.borrow(), &Client::new()) - .await?; - Ok(response.json::>().await?) + Ok( + fetch_response(&Endpoint::Summons, language.borrow(), &Client::new()) + .await? + .json::>() + .await?, + ) } diff --git a/src/filter/student.rs b/src/filter/student.rs index bf91f2c..77ec2c2 100644 --- a/src/filter/student.rs +++ b/src/filter/student.rs @@ -7,7 +7,7 @@ use crate::{ /// Used to filter **[`Students`][`Student`]**. pub trait StudentFilter { - /// Filters a borrowed slice of [`Student`], and returns a **[`Vec`]**. + /// Filters a borrowed slice of [`Student`], and returns a **[`Vec<&Student>`]**. fn filter<'a>(&self, students: &'a [Student]) -> Vec<&'a Student>; } diff --git a/src/types/mod.rs b/src/types/mod.rs index 1073210..1512d2d 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -17,7 +17,7 @@ pub use summons::Summon; /// **A Blue Archive ID**. /// /// Basically wraps around a [`u32`], and exists for representation of an identifier that can be filtered and have extra functionality. -#[derive(Debug, PartialEq, Eq, Hash, Clone)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)] pub struct ID(u32); impl ID { @@ -33,25 +33,6 @@ impl std::fmt::Display for ID { } } -impl Serialize for ID { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_newtype_struct("ID", &self.0) - } -} - -impl<'de> Deserialize<'de> for ID { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let value: u32 = Deserialize::deserialize(deserializer)?; - Ok(Self(value)) - } -} - #[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)] pub enum SkillKind { #[serde(alias = "weaponpassive")] diff --git a/src/types/students/mod.rs b/src/types/students/mod.rs index 8c00681..b0d004e 100644 --- a/src/types/students/mod.rs +++ b/src/types/students/mod.rs @@ -24,9 +24,7 @@ impl From for Age { impl Display for Age { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self.0 { - Some(age) => { - write!(f, "{}", age) - } + Some(age) => write!(f, "{}", age), None => write!(f, "None"), } } From 92274e10d613759a81e9aa6f6633955777961bdb Mon Sep 17 00:00:00 2001 From: Bibi Reden Date: Sat, 4 May 2024 22:52:19 -0500 Subject: [PATCH 3/5] Make age changes. --- CHANGELOG.md | 11 +++++++++ examples/fetch_student.rs | 3 ++- examples/student_fetcher.rs | 2 +- src/filter/student.rs | 2 +- src/types/mod.rs | 2 +- src/types/students/mod.rs | 46 ++++++++++++++++++++++++++++++++--- src/types/students/student.rs | 20 +++------------ 7 files changed, 62 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 351bae2..19cc375 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,3 +45,14 @@ Added the new `blocking` feature. It is not enabled by default, so you must requ - Changed how some internal deserialization and hashing works in the crate. ### Fixes ⚒️ + +## 0.5.1 - 2024-05-04 + +### Additions ✨ + +### Changes 📝 + +- Changed how `age` is obtained and how it is serialized/deserialized. This will be done as soon as it is read/written without a method call. + - Use `student.age` instead of `student.age()`. + +### Fixes ⚒️ diff --git a/examples/fetch_student.rs b/examples/fetch_student.rs index ab1bea4..85d02bd 100644 --- a/examples/fetch_student.rs +++ b/examples/fetch_student.rs @@ -11,7 +11,8 @@ async fn main() -> anyhow::Result<()> { println!("{header}"); println!("{}", "-".repeat(header.len())); let segments = [ - ("age", format!("{}", hina.age())), + ("id", format!("{}", hina.id)), + ("age", format!("{}", hina.age)), ("birthday", hina.birthday.to_string()), ("school", format!("{}", hina.school())), ("club", format!("{}", hina.club())), diff --git a/examples/student_fetcher.rs b/examples/student_fetcher.rs index 834c99a..1538e66 100644 --- a/examples/student_fetcher.rs +++ b/examples/student_fetcher.rs @@ -36,7 +36,7 @@ async fn main() -> anyhow::Result<()> { - full name (surname): {} "#, aru.id, - aru.age(), + aru.age, aru.club(), aru.full_name_last() ); diff --git a/src/filter/student.rs b/src/filter/student.rs index 77ec2c2..c4c869b 100644 --- a/src/filter/student.rs +++ b/src/filter/student.rs @@ -15,7 +15,7 @@ impl StudentFilter for Age { fn filter<'a>(&self, students: &'a [Student]) -> Vec<&'a Student> { students .iter() - .filter(|student| &student.age() == self) + .filter(|student| &student.age == self) .collect() } } diff --git a/src/types/mod.rs b/src/types/mod.rs index 1512d2d..f32aa2b 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -29,7 +29,7 @@ impl ID { impl std::fmt::Display for ID { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "ID#:({})", self.0) + write!(f, "{}", self.0) } } diff --git a/src/types/students/mod.rs b/src/types/students/mod.rs index b0d004e..33cdb6f 100644 --- a/src/types/students/mod.rs +++ b/src/types/students/mod.rs @@ -7,9 +7,10 @@ use serde::{Deserialize, Serialize}; pub use student::Student; /// The age of a **[`Student`]**, which can be **[`None`]** or a **[`u8`]**, depending on if the age can be parsed or not. -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Age(pub Option); impl Age { + /// Returns the underlying value, though if [`None`], it will return `0`. pub fn as_u8(&self) -> u8 { self.0.unwrap_or(0) } @@ -21,6 +22,37 @@ impl From for Age { } } +impl Serialize for Age { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self.0 { + Some(v) => serializer.serialize_some::(&v), + None => serializer.serialize_none(), + } + } +} + +impl<'de> Deserialize<'de> for Age { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let radix = 10; + let mut num_sequence: Vec = vec![]; + for char in String::deserialize(deserializer)?.chars() { + match char.to_digit(radix.into()) { + Some(digit) => num_sequence.push(digit as u8), + None => break, + } + } + Ok(Age((!num_sequence.is_empty()).then_some( + num_sequence.iter().fold(0, |acc, el| acc * radix + el), + ))) + } +} + impl Display for Age { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self.0 { @@ -50,11 +82,17 @@ impl Released { impl Display for Released { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "(JP: {} | Global: {})", self.japan(), self.global()) + write!( + f, + "(JP: {}, GL: {}, CN, {})", + self.japan(), + self.global(), + self.china() + ) } } -/// The height of a student, represented in a [`metric`](`Height.metric`) or [`imperial`](`Height.imperial`) standard. +/// The height of a student, represented in a [`metric`](`Height::metric`) or [`imperial`](`Height::imperial`) standard. #[derive(Debug, PartialEq, Eq)] pub struct Height { /// The student height in metric standard. @@ -66,7 +104,7 @@ impl Display for Height { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, - "(Metric: {} | Imperial: {:?})", + "(Metric: {}, Imperial: {:?})", self.metric, self.imperial ) } diff --git a/src/types/students/student.rs b/src/types/students/student.rs index 66f4956..d7a40ed 100644 --- a/src/types/students/student.rs +++ b/src/types/students/student.rs @@ -27,6 +27,9 @@ pub struct Student { /// The name of the student as presented in the data, and can have an associated tag alongside it. /// An example would be **`Toki (Bunny)`**. pub name: String, + /// The **[`Age`]** of the student. + #[serde(alias = "CharacterAge")] + pub age: Age, /// The first name of the student. e.g., Ichinose. #[serde(alias = "PersonalName")] pub first_name: String, @@ -62,7 +65,6 @@ pub struct Student { collection_texture: Option, family_name_ruby: Option, pub school_year: Option, - character_age: String, /// The birthday of the student represented as (Month, Day). pub birthday: String, #[serde(alias = "CharacterSSRNew")] @@ -146,20 +148,6 @@ impl Student { }) } - /// Gets the **[`Age`]** of the student. - pub fn age(&self) -> Age { - let radix = 10; - let mut num_sequence: Vec = vec![]; - for char in self.character_age.chars() { - match char.to_digit(radix.into()) { - Some(digit) => num_sequence.push(digit as u8), - None => break, - } - } - Age((!num_sequence.is_empty()) - .then_some(num_sequence.iter().fold(0, |acc, el| acc * radix + el))) - } - /// Gets the [`Height`] of the [`Student`]. pub fn height(&self) -> Height { Height { @@ -232,7 +220,7 @@ impl std::fmt::Display for Student { "Student : {} :-: {} | Age:{} | School: {}", self.full_name_last(), self.id, - self.age(), + self.age, self.school() ) } From bd75d12c5c56b8631ea66043215893834d29d3d4 Mon Sep 17 00:00:00 2001 From: Bibi Reden Date: Sat, 4 May 2024 23:05:06 -0500 Subject: [PATCH 4/5] Apply different serde tactic for released --- CHANGELOG.md | 1 + src/types/students/mod.rs | 45 +++++++++++++++++++++++++++------------ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19cc375..07d7709 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ Added the new `blocking` feature. It is not enabled by default, so you must requ ### Changes 📝 +- Changed `Released` struct to allow direct access to `japan`, `global` and `china` fields. - Changed how `age` is obtained and how it is serialized/deserialized. This will be done as soon as it is read/written without a method call. - Use `student.age` instead of `student.age()`. diff --git a/src/types/students/mod.rs b/src/types/students/mod.rs index 33cdb6f..4d123f1 100644 --- a/src/types/students/mod.rs +++ b/src/types/students/mod.rs @@ -3,6 +3,8 @@ pub mod student; use std::fmt::Display; +use serde::ser::SerializeStruct; + use serde::{Deserialize, Serialize}; pub use student::Student; @@ -63,20 +65,37 @@ impl Display for Age { } /// The released status of a **[`Student`]**. -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] -pub struct Released(bool, bool, bool); - -impl Released { - pub fn japan(&self) -> bool { - self.0 - } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Released { + pub japan: bool, + pub global: bool, + pub china: bool, +} - pub fn global(&self) -> bool { - self.1 +impl Serialize for Released { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut released = serializer.serialize_struct("IsReleased", 3)?; + released.serialize_field("japan", &self.japan)?; + released.serialize_field("global", &self.global)?; + released.serialize_field("china", &self.china)?; + released.end() } +} - pub fn china(&self) -> bool { - self.2 +impl<'de> Deserialize<'de> for Released { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let vec = Vec::deserialize(deserializer)?; + Ok(Self { + japan: vec[0], + global: vec[1], + china: vec[2], + }) } } @@ -85,9 +104,7 @@ impl Display for Released { write!( f, "(JP: {}, GL: {}, CN, {})", - self.japan(), - self.global(), - self.china() + self.japan, self.global, self.china ) } } From 7f4f883156cb1376552433cbe4938e9fc8a9db62 Mon Sep 17 00:00:00 2001 From: Bibi Reden Date: Sun, 5 May 2024 00:24:44 -0500 Subject: [PATCH 5/5] Adjustments to display and examples, stage 0.5.1 --- CHANGELOG.md | 53 ++++++++++++++++++----------------- Cargo.toml | 2 +- examples/fetch_equipment.rs | 4 ++- examples/fetch_student.rs | 2 +- examples/guessing_game.rs | 2 +- src/types/students/student.rs | 4 +-- 6 files changed, 35 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07d7709..4ca3e43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,32 @@ # blue_archive-rs + +## 0.5.1 - 2024-05-04 + +### Additions ✨ + +### Changes 📝 +- Modified displayed portions of `Student` and other struct fields. +- Changed `Released` struct to allow direct access to `japan`, `global` and `china` fields. +- Changed how `age` is obtained and how it is serialized/deserialized. This will be done as soon as it is read/written without a method call. + - Use `student.age` instead of `student.age()`. + +### Fixes ⚒️ + +## 0.5.0 - 2024-04-01 + +### Additions ✨ + +Added the new `blocking` feature. It is not enabled by default, so you must require it if you wish to use it! + +- This uses reqwest's `blocking` feature to handle all requests in a non-asynchronous way. + +### Changes 📝 + +- Changed how some internal deserialization and hashing works in the crate. + +### Fixes ⚒️ + ## 0.4.0 - 2024-03-23 ### Additions ✨ @@ -31,29 +58,3 @@ ### Fixes ⚒️ - Applied a change to the `Student::position` function, was passing in the `Student::armor_type` for some reason... oops! - -## 0.5.0 - 2024-04-01 - -### Additions ✨ - -Added the new `blocking` feature. It is not enabled by default, so you must require it if you wish to use it! - -- This uses reqwest's `blocking` feature to handle all requests in a non-asynchronous way. - -### Changes 📝 - -- Changed how some internal deserialization and hashing works in the crate. - -### Fixes ⚒️ - -## 0.5.1 - 2024-05-04 - -### Additions ✨ - -### Changes 📝 - -- Changed `Released` struct to allow direct access to `japan`, `global` and `china` fields. -- Changed how `age` is obtained and how it is serialized/deserialized. This will be done as soon as it is read/written without a method call. - - Use `student.age` instead of `student.age()`. - -### Fixes ⚒️ diff --git a/Cargo.toml b/Cargo.toml index 687f039..7ac6406 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "blue_archive" -version = "0.5.0" +version = "0.5.1" edition = "2021" license-file = "LICENSE" description = "A Blue Archive api wrapper for Rust, based off of SchaleDB's data: https://github.com/lonqie/SchaleDB" diff --git a/examples/fetch_equipment.rs b/examples/fetch_equipment.rs index 89a619c..b51e1f8 100644 --- a/examples/fetch_equipment.rs +++ b/examples/fetch_equipment.rs @@ -2,13 +2,15 @@ use blue_archive::{types::equipment::EquipmentCategory, Language}; #[tokio::main] async fn main() -> anyhow::Result<()> { + println!("{:<60} Category", "Name"); for equipment in blue_archive::fetch_all_equipment(Language::English).await? { - println!("{}", equipment.name) + println!("{:<60} {:?}", equipment.name, equipment.category); } let hats = blue_archive::fetch_equipment_by_category(Language::English, EquipmentCategory::Hat) .await?; + println!("\nHats"); for hat in &hats { println!("[{}] -> {}", hat.id, hat.name) } diff --git a/examples/fetch_student.rs b/examples/fetch_student.rs index 85d02bd..12b28df 100644 --- a/examples/fetch_student.rs +++ b/examples/fetch_student.rs @@ -37,7 +37,7 @@ async fn main() -> anyhow::Result<()> { let random_student = (blue_archive::fetch_random_student(Language::English).await?).unwrap(); // I wonder who it will be this time? println!( - "The random student of this second is: {}!", + "The random student of this second is: {}!\n", random_student.full_name_last() ); diff --git a/examples/guessing_game.rs b/examples/guessing_game.rs index 1a7d808..cd0d3c8 100644 --- a/examples/guessing_game.rs +++ b/examples/guessing_game.rs @@ -12,7 +12,7 @@ async fn main() -> anyhow::Result<()> { println!("Guessing Game (it's really bad)"); println!("---------------------------"); - println!("See if you can guess the characters based on certain properties.\n\n"); + println!("See if you can guess the characters based on the remaining ones.\n\n"); let chosen = blue_archive::fetch_random_student(Language::English) .await? diff --git a/src/types/students/student.rs b/src/types/students/student.rs index d7a40ed..1a693e5 100644 --- a/src/types/students/student.rs +++ b/src/types/students/student.rs @@ -217,9 +217,9 @@ impl std::fmt::Display for Student { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, - "Student : {} :-: {} | Age:{} | School: {}", - self.full_name_last(), + "(ID: {}, Name: {}, Age: {}, School: {})", self.id, + self.full_name_last(), self.age, self.school() )