Skip to main content

mlb_api/requests/stats/raw/
mod.rs

1use std::ops::Add;
2use serde::{Deserialize, Deserializer};
3use serde::de::DeserializeOwned;
4use thiserror::Error;
5
6macro_rules! register_fields {
7    ($d:tt $($name:ident: $ty:ty),+ $(,)?) => {
8        macro_rules! api_name_to_type {
9            $(
10            ($name) => { $ty };
11            )+
12            ($d ($d t:tt)*) => { compile_error!("Invalid field name") };
13        }
14    };
15}
16
17register_fields![ $
18    games_played: crate::stats::units::CountingStat,
19    games_pitched: crate::stats::units::CountingStat,
20    games_started: crate::stats::units::CountingStat,
21    games_finished: crate::stats::units::CountingStat,
22    groundouts: crate::stats::units::CountingStat,
23    airouts: crate::stats::units::CountingStat,
24    runs: crate::stats::units::CountingStat,
25    doubles: crate::stats::units::CountingStat,
26    triples: crate::stats::units::CountingStat,
27    home_runs: crate::stats::units::CountingStat,
28    strikeouts: crate::stats::units::CountingStat,
29    base_on_balls: crate::stats::units::CountingStat,
30    intentional_walks: crate::stats::units::CountingStat,
31    hits: crate::stats::units::CountingStat,
32    hit_by_pitch: crate::stats::units::CountingStat,
33    at_bats: crate::stats::units::CountingStat,
34    caught_stealing: crate::stats::units::CountingStat,
35    stolen_bases: crate::stats::units::CountingStat,
36    grounded_into_double_play: crate::stats::units::CountingStat,
37    grounded_into_triple_play: crate::stats::units::CountingStat,
38    grounded_into_double_play_opponent: crate::stats::units::CountingStat,
39    number_of_pitches: crate::stats::units::CountingStat,
40    innings_pitched: crate::stats::units::InningsPitched,
41    plate_appearances: crate::stats::units::CountingStat,
42    total_bases: crate::stats::units::CountingStat,
43    rbi: crate::stats::units::CountingStat,
44    left_on_base: crate::stats::units::CountingStat,
45    sac_bunts: crate::stats::units::CountingStat,
46    sac_flies: crate::stats::units::CountingStat,
47    bunts_failed: crate::stats::units::CountingStat,
48    bunts_missed_tipped: crate::stats::units::CountingStat,
49    catchers_interference: crate::stats::units::CountingStat,
50    wOBA: crate::stats::units::ThreeDecimalPlaceRateStat,
51    wRAA: crate::stats::units::FloatCountingStat<2>,
52    wRC: crate::stats::units::FloatCountingStat<2>,
53    wRCp: crate::stats::units::FloatCountingStat<0>,
54    RAR: crate::stats::units::FloatCountingStat<1>,
55    bWAR: crate::stats::units::FloatCountingStat<1>,
56    fWAR: crate::stats::units::FloatCountingStat<1>,
57    FIP: crate::stats::units::TwoDecimalPlaceRateStat,
58    xFIP: crate::stats::units::TwoDecimalPlaceRateStat,
59    xAVG: crate::stats::units::ThreeDecimalPlaceRateStat,
60    xSLG: crate::stats::units::ThreeDecimalPlaceRateStat,
61    wOBA: crate::stats::units::ThreeDecimalPlaceRateStat,
62    xwOBA: crate::stats::units::ThreeDecimalPlaceRateStat,
63    wOBACON: crate::stats::units::ThreeDecimalPlaceRateStat,
64    xwOBACON: crate::stats::units::ThreeDecimalPlaceRateStat,
65    wLeague: crate::stats::units::FloatCountingStat<1>,
66    FIPm: crate::stats::units::TwoDecimalPlaceRateStat,
67    shutdowns: crate::stats::units::FloatCountingStat<0>,
68    meltdowns: crate::stats::units::FloatCountingStat<0>,
69    leverage_index: crate::stats::units::TwoDecimalPlaceRateStat,
70    inning_start_leverage_index: crate::stats::units::TwoDecimalPlaceRateStat,
71    game_leverage_index: crate::stats::units::TwoDecimalPlaceRateStat,
72    exiting_leverage_index: crate::stats::units::TwoDecimalPlaceRateStat,
73    batting_run_value: crate::stats::units::FloatCountingStat<0>,
74    fielding_run_value: crate::stats::units::FloatCountingStat<0>,
75    baserunning_run_value: crate::stats::units::FloatCountingStat<0>,
76    positional_run_adjustment: crate::stats::units::FloatCountingStat<1>,
77    replacement_run_value: crate::stats::units::FloatCountingStat<0>,
78    ERAm: crate::stats::units::FloatCountingStat<0>,
79    SPD: crate::stats::units::TwoDecimalPlaceRateStat,
80    UBR: crate::stats::units::TwoDecimalPlaceRateStat,
81    wSB: crate::stats::units::TwoDecimalPlaceRateStat,
82    wGDP: crate::stats::units::TwoDecimalPlaceRateStat,
83    age: crate::stats::units::CountingStat,
84    extra_base_hits: crate::stats::units::CountingStat,
85    reached_on_error: crate::stats::units::CountingStat,
86    walkoffs: crate::stats::units::CountingStat,
87    flyouts: crate::stats::units::CountingStat,
88    total_swings: crate::stats::units::CountingStat,
89    whiffs: crate::stats::units::CountingStat,
90    balls_in_play: crate::stats::units::CountingStat,
91    popouts: crate::stats::units::CountingStat,
92    lineouts: crate::stats::units::CountingStat,
93    flyball_hits: crate::stats::units::CountingStat,
94    popfly_hits: crate::stats::units::CountingStat,
95    line_drive_hits: crate::stats::units::CountingStat,
96    groundball_hits: crate::stats::units::CountingStat,
97    wins: crate::stats::units::CountingStat,
98    losses: crate::stats::units::CountingStat,
99    saves: crate::stats::units::CountingStat,
100    save_opportunities: crate::stats::units::CountingStat,
101    holds: crate::stats::units::CountingStat,
102    blown_saves: crate::stats::units::CountingStat,
103    earned_runs: crate::stats::units::CountingStat,
104    batters_faced: crate::stats::units::CountingStat,
105    outs: crate::stats::units::CountingStat,
106    outs_pitched: crate::stats::units::CountingStat,
107    lob_wins: crate::stats::units::TwoDecimalPlaceRateStat,
108    bip_wins: crate::stats::units::TwoDecimalPlaceRateStat,
109    fdp_wins: crate::stats::units::TwoDecimalPlaceRateStat,
110    quality_starts: crate::stats::units::CountingStat,
111    complete_games: crate::stats::units::CountingStat,
112    shutouts: crate::stats::units::CountingStat,
113    strikes: crate::stats::units::CountingStat,
114    balls: crate::stats::units::CountingStat,
115    balks: crate::stats::units::CountingStat,
116    wild_pitches: crate::stats::units::CountingStat,
117    passed_balls: crate::stats::units::CountingStat,
118    pickoffs: crate::stats::units::CountingStat,
119    pickoff_attempts: crate::stats::units::CountingStat,
120    inherited_runners: crate::stats::units::CountingStat,
121    inherited_runners_scored: crate::stats::units::CountingStat,
122    bequeathed_runners: crate::stats::units::CountingStat,
123    bequeathed_runners_scored: crate::stats::units::CountingStat,
124    run_support: crate::stats::units::CountingStat,
125    assists: crate::stats::units::CountingStat,
126    putouts: crate::stats::units::CountingStat,
127    errors: crate::stats::units::CountingStat,
128    chances: crate::stats::units::CountingStat,
129    position: crate::positions::NamedPosition,
130    innings: crate::stats::units::InningsPitched,
131    games: crate::stats::units::CountingStat,
132    double_plays: crate::stats::units::CountingStat,
133    triple_plays: crate::stats::units::CountingStat,
134    throwing_errors: crate::stats::units::CountingStat,
135];
136
137macro_rules! group_and_type {
138    ($name:ident { $($(#[$meta:meta])* $serde:literal => $piece:ident),* $(,)? }) => {
139        ::pastey::paste! {
140            #[doc(hidden)]
141            #[allow(non_snake_case)]
142            #[derive(Debug, ::serde::Deserialize, Clone)]
143            // #[cfg_attr(test, serde(deny_unknown_fields))] // todo: find out how to fix this to discard some
144            pub struct [<__ $name StatsData>] {
145                $(
146                #[serde(deserialize_with = "crate::stats::raw::deserialize_stat", rename = $serde)]
147                #[cfg_attr(not(test), serde(default = "crate::stats::raw::default_stat"))]
148                $(#[$meta])*
149                pub $piece: Result<api_name_to_type![$piece], crate::stats::raw::OmittedStatError>,
150                )*
151            }
152
153            impl ::std::cmp::PartialEq for [<__ $name StatsData>] {
154                fn eq(&self, rhs: &Self) -> bool {
155                    true && $(crate::stats::raw::stat_eq(&self.$piece, &rhs.$piece))&&*
156                }
157            }
158
159            impl ::std::cmp::Eq for [<__ $name StatsData>] {}
160
161            impl ::std::ops::Add for [<__ $name StatsData>]
162            where
163                $(
164                for<'no_rfc_2056> api_name_to_type![$piece]: ::std::ops::Add
165                ),*
166            {
167                type Output = Self;
168
169                fn add(mut self, rhs: Self) -> Self::Output {
170                    self += rhs;
171                    self
172                }
173            }
174
175            impl ::std::ops::AddAssign for [<__ $name StatsData>]
176            where
177                $(
178                for<'no_rfc_2056> api_name_to_type![$piece]: ::std::ops::Add
179                ),*
180            {
181                fn add_assign(&mut self, rhs: Self) {
182                    $(
183                    self.$piece = crate::stats::raw::stat_add(self.$piece.clone(), rhs.$piece);
184                    )*
185                }
186            }
187
188            impl Default for [<__ $name StatsData>] {
189                fn default() -> Self {
190                    Self {
191                        $(
192                        $piece: Err(crate::stats::raw::OmittedStatError)
193                        ),*
194                    }
195                }
196            }
197
198            impl crate::stats::RawStat for [<__ $name StatsData>] {}
199        }
200    };
201}
202
203pub mod pitching;
204pub mod hitting;
205pub mod fielding;
206pub mod catching;
207
208mod fielded_matchup;
209mod spray_chart;
210mod hit_spray;
211mod hot_cold_zones;
212mod pitch_usage;
213
214pub use fielded_matchup::*;
215pub use spray_chart::*;
216pub use hit_spray::*;
217pub use hot_cold_zones::*;
218pub use pitch_usage::*;
219
220/// For old data, some stats are just omitted, like pitch count and stuff. So every field is now possibly omittable. Gotta `?` everything now. (this api is legendary)
221#[derive(Debug, Error, PartialEq, Eq, Copy, Clone)]
222#[error("This stat was omitted.")]
223pub struct OmittedStatError;
224
225pub(crate) fn deserialize_stat<'de, D: Deserializer<'de>, T: DeserializeOwned>(deserializer: D) -> Result<Result<T, OmittedStatError>, D::Error> {
226    Ok(Option::<T>::deserialize(deserializer)?.ok_or(OmittedStatError))
227}
228
229pub(crate) fn default_stat<T>() -> Result<T, OmittedStatError> {
230    Err(OmittedStatError)
231}
232
233pub(crate) fn stat_eq<T: PartialEq>(a: &Result<T, OmittedStatError>, b: &Result<T, OmittedStatError>) -> bool {
234    match (a, b) {
235        (Ok(a), Ok(b)) => a == b,
236        (Err(a), Err(b)) => a == b,
237        _ => false,
238    }
239}
240
241pub(crate) fn stat_add<T: Add<Output=T>>(a: Result<T, OmittedStatError>, b: Result<T, OmittedStatError>) -> Result<T, OmittedStatError> {
242    match (a, b) {
243        (Ok(a), Ok(b)) => Ok(a + b),
244        // if one record does not have the value, the value is not 0 - it is unknown.
245        _ => Err(OmittedStatError),
246    }
247}