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 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#[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 _ => Err(OmittedStatError),
246 }
247}