Skip to content

Commit

Permalink
Update 0.5.1 (#35)
Browse files Browse the repository at this point in the history
* Add more context to `api`

* Derive serde for ID, and some few adjustments

* Make age changes.

* Apply different serde tactic for released

* Adjustments to display and examples, stage 0.5.1
  • Loading branch information
bibi-reden authored May 5, 2024
1 parent 3929ba9 commit 0d0d181
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 86 deletions.
41 changes: 27 additions & 14 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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 ✨
Expand Down Expand Up @@ -31,17 +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 ⚒️
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
4 changes: 3 additions & 1 deletion examples/fetch_equipment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
5 changes: 3 additions & 2 deletions examples/fetch_student.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())),
Expand All @@ -36,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()
);

Expand Down
2 changes: 1 addition & 1 deletion examples/guessing_game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down
2 changes: 1 addition & 1 deletion examples/student_fetcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ async fn main() -> anyhow::Result<()> {
- full name (surname): {}
"#,
aru.id,
aru.age(),
aru.age,
aru.club(),
aru.full_name_last()
);
Expand Down
8 changes: 6 additions & 2 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -27,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,
Expand Down
15 changes: 10 additions & 5 deletions src/api/summon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Language>,
) -> Result<Vec<Summon>, BlueArchiveError> {
let response =
super::internal::fetch_response(&Endpoint::Summons, language.borrow(), &Client::new())
.await?;
Ok(response.json::<Vec<Summon>>().await?)
Ok(
fetch_response(&Endpoint::Summons, language.borrow(), &Client::new())
.await?
.json::<Vec<Summon>>()
.await?,
)
}
4 changes: 2 additions & 2 deletions src/filter/student.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ use crate::{

/// Used to filter **[`Students`][`Student`]**.
pub trait StudentFilter {
/// Filters a borrowed slice of [`Student`], and returns a **[`Vec<Student>`]**.
/// Filters a borrowed slice of [`Student`], and returns a **[`Vec<&Student>`]**.
fn filter<'a>(&self, students: &'a [Student]) -> Vec<&'a Student>;
}

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()
}
}
Expand Down
23 changes: 2 additions & 21 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -29,26 +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)
}
}

impl Serialize for ID {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_newtype_struct("ID", &self.0)
}
}

impl<'de> Deserialize<'de> for ID {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let value: u32 = Deserialize::deserialize(deserializer)?;
Ok(Self(value))
write!(f, "{}", self.0)
}
}

Expand Down
89 changes: 71 additions & 18 deletions src/types/students/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
pub mod student;
use std::fmt::Display;

use serde::ser::SerializeStruct;

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<u8>);
impl Age {
/// Returns the underlying value, though if [`None`], it will return `0`.
pub fn as_u8(&self) -> u8 {
self.0.unwrap_or(0)
}
Expand All @@ -21,42 +24,92 @@ impl From<u8> for Age {
}
}

impl Serialize for Age {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self.0 {
Some(v) => serializer.serialize_some::<u8>(&v),
None => serializer.serialize_none(),
}
}
}

impl<'de> Deserialize<'de> for Age {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let radix = 10;
let mut num_sequence: Vec<u8> = 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 {
Some(age) => {
write!(f, "{}", age)
}
Some(age) => write!(f, "{}", age),
None => write!(f, "None"),
}
}
}

/// 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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let vec = Vec::deserialize(deserializer)?;
Ok(Self {
japan: vec[0],
global: vec[1],
china: vec[2],
})
}
}

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.
Expand All @@ -68,7 +121,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
)
}
Expand Down
Loading

0 comments on commit 0d0d181

Please sign in to comment.