From 21206737c07f902b790267d3f72ad4e427e770a6 Mon Sep 17 00:00:00 2001 From: Pavel Perestoronin Date: Sat, 3 Dec 2022 17:48:42 +0100 Subject: [PATCH] Break: refactor the models --- Cargo.toml | 1 + src/lib.rs | 24 ++++++++++ src/models.rs | 34 ++------------ src/models/battle_results.rs | 44 ++++++++++++++++++ src/models/battle_results_dat.rs | 6 +++ src/replay.rs | 7 ++- tests/battle_results.rs | 4 +- ...otbreplay => battle_results_ok.wotbreplay} | Bin 8 files changed, 83 insertions(+), 37 deletions(-) create mode 100644 src/models/battle_results.rs create mode 100644 src/models/battle_results_dat.rs rename tests/replays/{20221202_2259__zeekrab_It20_Car_Comb_45t_2308705958773814583.wotbreplay => battle_results_ok.wotbreplay} (100%) diff --git a/Cargo.toml b/Cargo.toml index 8535a9a..af1eea9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ default = [] [dependencies] prost = "0.11.3" +serde = { version = "1.0.148", features = ["derive"] } serde_bytes = "0.11.7" serde-pickle = "1.1.1" thiserror = "1.0.37" diff --git a/src/lib.rs b/src/lib.rs index ce240eb..d7db746 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,15 @@ +//! World of Tanks Blitz replay parser. + +#![warn( + clippy::all, + clippy::missing_const_for_fn, + clippy::trivially_copy_pass_by_ref, + clippy::map_unwrap_or, + clippy::explicit_into_iter_loop, + clippy::unused_self, + clippy::needless_pass_by_value +)] + mod error; pub mod models; mod replay; @@ -6,3 +18,15 @@ mod result; pub use crate::error::Error; pub use crate::replay::Replay; pub use crate::result::Result; + +#[cfg(doctest)] +mod test_readme { + macro_rules! external_doc_test { + ($x:expr) => { + #[doc = $x] + extern "C" {} + }; + } + + external_doc_test!(include_str!("../README.md")); +} diff --git a/src/models.rs b/src/models.rs index de41171..9e6a457 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,31 +1,5 @@ -use ::prost::Message; +mod battle_results; +mod battle_results_dat; -#[derive(Message)] -pub struct BattleResults { - #[prost(int64, tag = "2")] - pub timestamp: i64, - - #[prost(message, repeated, tag = "201")] - pub players: Vec, -} - -#[derive(Message)] -pub struct Player { - #[prost(uint32, tag = "1")] - pub account_id: u32, - - #[prost(message, required, tag = "2")] - pub info: PlayerInfo, -} - -#[derive(Message)] -pub struct PlayerInfo { - #[prost(string, tag = "1")] - pub nickname: String, - - #[prost(uint32, optional, tag = "2")] - pub platoon_id: Option, - - #[prost(uint32, tag = "3")] - pub team_number: u32, -} +pub use self::battle_results::*; +pub use self::battle_results_dat::*; diff --git a/src/models/battle_results.rs b/src/models/battle_results.rs new file mode 100644 index 0000000..ae89714 --- /dev/null +++ b/src/models/battle_results.rs @@ -0,0 +1,44 @@ +use prost::bytes::Buf; +use prost::Message; + +use crate::error::Error; +use crate::result::Result; + +impl BattleResults { + /// Parse battle results from the buffer. + /// + /// Note, that this does NOT parse `battle_results.dat` itself, but the un-pickled tuple element. + pub fn parse(buffer: impl Buf) -> Result { + Self::decode(buffer).map_err(Error::DecodeFailed) + } +} + +#[derive(Message)] +pub struct BattleResults { + #[prost(int64, tag = "2")] + pub timestamp: i64, + + #[prost(message, repeated, tag = "201")] + pub players: Vec, +} + +#[derive(Message)] +pub struct Player { + #[prost(uint32, tag = "1")] + pub account_id: u32, + + #[prost(message, required, tag = "2")] + pub info: PlayerInfo, +} + +#[derive(Message)] +pub struct PlayerInfo { + #[prost(string, tag = "1")] + pub nickname: String, + + #[prost(uint32, optional, tag = "2")] + pub platoon_id: Option, + + #[prost(uint32, tag = "3")] + pub team_number: u32, +} diff --git a/src/models/battle_results_dat.rs b/src/models/battle_results_dat.rs new file mode 100644 index 0000000..14ff30e --- /dev/null +++ b/src/models/battle_results_dat.rs @@ -0,0 +1,6 @@ +use serde::Deserialize; +use serde_bytes::ByteBuf; + +/// Represents un-pickled `battle_results.dat`. +#[derive(Debug, Deserialize)] +pub struct BattleResultsDat(pub(crate) u64, pub(crate) ByteBuf); diff --git a/src/replay.rs b/src/replay.rs index d968ba2..7b0e820 100644 --- a/src/replay.rs +++ b/src/replay.rs @@ -1,11 +1,10 @@ use std::io::{Read, Seek}; use prost::Message; -use serde_bytes::ByteBuf; use zip::ZipArchive; use crate::error::Error; -use crate::models::BattleResults; +use crate::models::{BattleResults, BattleResultsDat}; use crate::result::Result; pub struct Replay(pub(crate) ZipArchive); @@ -27,9 +26,9 @@ impl Replay { pickled_battle_results .read_to_end(&mut serialized_battle_results) .map_err(Error::ReadEntryFailed)?; - let (_, battle_results): (u64, ByteBuf) = + let battle_results_dat: BattleResultsDat = serde_pickle::from_slice(&serialized_battle_results, Default::default()) .map_err(Error::UnpickleFailed)?; - BattleResults::decode(battle_results.as_ref()).map_err(Error::DecodeFailed) + BattleResults::decode(battle_results_dat.1.as_ref()).map_err(Error::DecodeFailed) } } diff --git a/tests/battle_results.rs b/tests/battle_results.rs index 3a6e419..d2c43a0 100644 --- a/tests/battle_results.rs +++ b/tests/battle_results.rs @@ -5,9 +5,7 @@ use wotbreplay_parser::Replay; #[test] fn battle_results_ok() -> Result<()> { - let mut replay = Replay::open(File::open( - "tests/replays/20221202_2259__zeekrab_It20_Car_Comb_45t_2308705958773814583.wotbreplay", - )?)?; + let mut replay = Replay::open(File::open("tests/replays/battle_results_ok.wotbreplay")?)?; let battle_results = replay.read_battle_results()?; assert_eq!(battle_results.timestamp, 1670018359); diff --git a/tests/replays/20221202_2259__zeekrab_It20_Car_Comb_45t_2308705958773814583.wotbreplay b/tests/replays/battle_results_ok.wotbreplay similarity index 100% rename from tests/replays/20221202_2259__zeekrab_It20_Car_Comb_45t_2308705958773814583.wotbreplay rename to tests/replays/battle_results_ok.wotbreplay