1#[macro_export]
2#[doc(hidden)]
3macro_rules! __stats__stat_type_definition {
4 ($parent_name:ident => $vis:vis struct $name:ident { $stat_type:ident => [$($stat_group:ident),+] }) => {
5 ::pastey::paste! {
6 #[derive(Debug, PartialEq, Clone)]
7 $vis struct $name {
8 $($vis [< $stat_group:snake >]: ::std::boxed::Box<<$crate::stats::stat_types::[<__ $stat_type StatTypeStats>] as $crate::stats::StatTypeStats>::$stat_group>),+
9 }
10
11 impl [<__ $parent_name Split Parser>] for $name {
12 fn parse(parsed_stats: &mut $crate::stats::parse::__ParsedStats) -> ::core::result::Result<Self, ::std::string::String> {
13 Ok(Self {
14 $([<$stat_group:snake>]: ::std::boxed::Box::new(
15 $crate::stats::parse::make_stat_split::<<$crate::stats::stat_types::[< __ $stat_type StatTypeStats >] as $crate::stats::StatTypeStats>::$stat_group>(
16 parsed_stats, ::core::stringify!([<$stat_type:lower_camel>]), $crate::meta::StatGroup::$stat_group
17 ).map_err(|e| ::std::string::ToString::to_string(&e))?
18 )),+
19 })
20 }
21 }
22 }
23 };
24}
25
26#[macro_export]
27#[doc(hidden)]
28macro_rules! __stats__base_hydration_text {
29 ([$first_stat_type:ident $(, $stat_type:ident)* $(,)?] [$first_stat_group:ident $(, $stat_group:ident)* $(,)?]) => {
30 ::pastey::paste! {
31 ::core::concat!(
32 "type=[",
33 ::core::stringify!([<$first_stat_type:lower_camel>]),
34 $(",", ::core::stringify!([<$stat_type:lower_camel>]), )*
35 "],group=[",
36 ::core::stringify!([<$first_stat_group:lower_camel>]),
37 $(",", ::core::stringify!([<$stat_group:lower_camel>]), )*
38 "]"
39 )
40 }
41 };
42}
43
44#[macro_export]
67#[doc(hidden)]
68macro_rules! __stats__needle_haystack_metrics {
69 ([$($haystack:ident),+ $(,)?] => { $($t:tt)* }) => {
70 $crate::__stats__needle_haystack_metrics!([$($haystack),+] => { $($t)* } else {});
71 };
72 ([MetricLog $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
73 $($t1)*
74 };
75 ([MetricAverages $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
76 $($t1)*
77 };
78 ([$first:ident $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
79 $crate::__stats__needle_haystack_metrics!([$($haystack),*] => { $($t1)* } else { $($t2)* });
80 };
81 ([$(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => { $($t2)* };
82}
83
84#[macro_export]
86#[doc(hidden)]
87macro_rules! __stats__needle_haystack_date_range {
88 ([$($haystack:ident),+ $(,)?] => { $($t:tt)* }) => {
89 $crate::__stats__needle_haystack_date_range!([$($haystack),+] => { $($t)* } else {});
90 };
91 ([ByDateRange $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
92 $($t1)*
93 };
94 ([$first:ident $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
95 $crate::__stats__needle_haystack_date_range!([$($haystack),*] => { $($t1)* } else { $($t2)* });
96 };
97 ([$(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => { $($t2)* };
98}
99
100#[macro_export]
102#[doc(hidden)]
103macro_rules! __stats__needle_haystack_situations {
104 ([$($haystack:ident),+ $(,)?] => { $($t:tt)* }) => {
105 $crate::__stats__needle_haystack_situations!([$($haystack),+] => { $($t)* } else {});
106 };
107 ([StatSplits $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
108 $($t1)*
109 };
110 ([StatSplitsAdvanced $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
111 $($t1)*
112 };
113 ([$first:ident $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
114 $crate::__stats__needle_haystack_situations!([$($haystack),*] => { $($t1)* } else { $($t2)* });
115 };
116 ([$(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => { $($t2)* };
117}
118
119#[macro_export]
121#[doc(hidden)]
122macro_rules! __stats__needle_haystack_games_back {
123 ([$($haystack:ident),+ $(,)?] => { $($t:tt)* }) => {
124 $crate::__stats__needle_haystack_games_back!([$($haystack),+] => { $($t)* } else {});
125 };
126 ([LastXGames $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
127 $($t1)*
128 };
129 ([$first:ident $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
130 $crate::__stats__needle_haystack_games_back!([$($haystack),*] => { $($t1)* } else { $($t2)* });
131 };
132 ([$(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => { $($t2)* };
133}
134
135#[macro_export]
137#[doc(hidden)]
138macro_rules! __stats__needle_haystack_opponent_player {
139 ([$($haystack:ident),+ $(,)?] => { $($t:tt)* }) => {
140 $crate::__stats__needle_haystack_opponent_player!([$($haystack),+] => { $($t)* } else {});
141 };
142 ([VsPlayer5Y $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
143 $($t1)*
144 };
145 ([VsPlayerTotal $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
146 $($t1)*
147 };
148 ([VsPlayer $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
149 $($t1)*
150 };
151 ([$first:ident $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
152 $crate::__stats__needle_haystack_opponent_player!([$($haystack),*] => { $($t1)* } else { $($t2)* });
153 };
154 ([$(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => { $($t2)* };
155}
156
157#[macro_export]
158#[doc(hidden)]
159macro_rules! __stats__request_data {
160 (@ metrics [$($stat_type:ident),+] $(#[$m:meta])* $vis:vis struct $name:ident { $($field_tt:tt)* } $($impl_tt:tt)*) => {
161 ::pastey::paste! {
162 $crate::__stats__needle_haystack_metrics! { [$($stat_type),+] => {
163 $crate::__stats__request_data! { @ date_range [$($stat_type),+]
164 $(#[$m])*
165 $vis struct $name {
166 $($field_tt)*
167 metrics: ::std::vec::Vec<$crate::meta::MetricId>,
168 }
169 $($impl_tt)*
170 impl<S: [<$name:snake _builder>]::State> [<$name Builder>]<S> {
171 pub fn metric(self, metric: impl ::core::convert::Into<$crate::meta::MetricId>) -> [<$name Builder>]<[<$name:snake _builder>]::SetMetrics<S>>
172 where
173 S::Metrics: [<$name:snake _builder>]::IsUnset
174 {
175 self.metrics(::std::vec![::core::convert::Into::into(metric)])
176 }
177 }
178 }
179 } else {
180 $crate::__stats__request_data! { @ date_range [$($stat_type),+]
181 $(#[$m])*
182 $vis struct $name {
183 $($field_tt)*
184 }
185 $($impl_tt)*
186 }
187 }}
188 }
189 };
190 (@ date_range [$($stat_type:ident),+] $(#[$m:meta])* $vis:vis struct $name:ident { $($field_tt:tt)* } $($impl_tt:tt)*) => {
191 ::pastey::paste! {
192 $crate::__stats__needle_haystack_date_range!{[$($stat_type),+] => {
193 $crate::__stats__request_data! { @ situations [$($stat_type),+]
194 $(#[$m])*
195 $vis struct $name {
196 $($field_tt)*
197 date_range: $crate::NaiveDateRange,
198 }
199 $($impl_tt)*
200 }
201 } else {
202 $crate::__stats__request_data! { @ situations [$($stat_type),+]
203 $(#[$m])*
204 $vis struct $name {
205 $($field_tt)*
206 }
207 $($impl_tt)*
208 }
209 }}
210 }
211 };
212 (@ situations [$($stat_type:ident),+] $(#[$m:meta])* $vis:vis struct $name:ident { $($field_tt:tt)* } $($impl_tt:tt)*) => {
213 ::pastey::paste! {
214 $crate::__stats__needle_haystack_situations!{[$($stat_type),+] => {
215 $crate::__stats__request_data! { @ games_back [$($stat_type),+]
216 $(#[$m])*
217 $vis struct $name {
218 $($field_tt)*
219 situations: ::std::vec::Vec<$crate::meta::SituationCodeId>,
220 #[builder(default)]
221 situation_filter: $crate::meta::SituationCodeFilter,
222 }
223 $($impl_tt)*
224 impl<S: [<$name:snake _builder>]::State> [<$name Builder>]<S> {
225 #[allow(dead_code, reason = "could be used by the end user")]
226 pub fn situation(self, situation: impl ::core::convert::Into<$crate::meta::SituationCodeId>) -> [<$name Builder>]<[<$name:snake _builder>]::SetSituations<S>>
227 where
228 S::Situations: [<$name:snake _builder>]::IsUnset
229 {
230 self.situations(::std::vec![::core::convert::Into::into(situation)])
231 }
232 }
233 }
234 } else {
235 $crate::__stats__request_data! { @ games_back [$($stat_type),+]
236 $(#[$m])*
237 $vis struct $name {
238 $($field_tt)*
239 }
240 $($impl_tt)*
241 }
242 }}
243 }
244 };
245 (@ games_back [$($stat_type:ident),+] $(#[$m:meta])* $vis:vis struct $name:ident { $($field_tt:tt)* } $($impl_tt:tt)*) => {
246 ::pastey::paste! {
247 $crate::__stats__needle_haystack_games_back!{[$($stat_type),+] => {
248 $crate::__stats__request_data! { @ opponent_player [$($stat_type),+]
249 $(#[$m])*
250 $vis struct $name {
251 $($field_tt)*
252 games_back: usize,
253 }
254 $($impl_tt)*
255 }
256 } else {
257 $crate::__stats__request_data! { @ opponent_player [$($stat_type),+]
258 $(#[$m])*
259 $vis struct $name {
260 $($field_tt)*
261 }
262 $($impl_tt)*
263 }
264 }}
265 }
266 };
267 (@ opponent_player [$($stat_type:ident),+] $(#[$m:meta])* $vis:vis struct $name:ident { $($field_tt:tt)* } $($impl_tt:tt)*) => {
268 ::pastey::paste! {
269 $crate::__stats__needle_haystack_opponent_player!{[$($stat_type),+] => {
270 $(#[$m])*
272 $vis struct $name {
273 $($field_tt)*
274 #[builder(into)]
275 opponent_player: $crate::person::PersonId,
276 }
277 $($impl_tt)*
278 } else {
280 $(#[$m])*
282 $vis struct $name {
283 $($field_tt)*
284 }
285 $($impl_tt)*
286 }}
288 }
289 };
290 ($vis:vis $name:ident [$($stat_type:ident),+]) => {
291 ::pastey::paste! {
292 $crate::__stats__request_data! { @ metrics [$($stat_type),+]
293 #[derive(::bon::Builder)]
294 #[builder(derive(Into))]
295 #[allow(unused, reason = "could be unused by the end user")]
296 $vis struct [<$name RequestData>] {
297 #[builder(default)]
298 game_type: $crate::meta::GameType,
299 #[builder(into)]
300 season: ::core::option::Option<$crate::season::SeasonId>,
301 team_ids: ::core::option::Option<::std::vec::Vec<$crate::team::TeamId>>,
302 sport_ids: ::core::option::Option<::std::vec::Vec<$crate::sport::SportId>>,
303 league_ids: ::core::option::Option<::std::vec::Vec<$crate::league::LeagueId>>,
304 limit: Option<usize>,
305 #[builder(default)]
306 player_pool: $crate::PlayerPool,
307
308
309 }
315
316 #[allow(unused, reason = "may be used by end user")]
317 impl<S: [<$name:snake _request_data_builder>]::State> [<$name RequestDataBuilder>]<S> {
318 pub fn team_id(self, team_id: impl ::core::convert::Into<$crate::team::TeamId>) -> [<$name RequestDataBuilder>]<[<$name:snake _request_data_builder>]::SetTeamIds<S>>
319 where
320 S::TeamIds: [<$name:snake _request_data_builder>]::IsUnset
321 {
322 self.team_ids(::std::vec![::core::convert::Into::into(team_id)])
323 }
324
325 pub fn sport_id(self, sport_id: impl ::core::convert::Into<$crate::sport::SportId>) -> [<$name RequestDataBuilder>]<[<$name:snake _request_data_builder>]::SetSportIds<S>>
326 where
327 S::SportIds: [<$name:snake _request_data_builder>]::IsUnset
328 {
329 self.sport_ids(::std::vec![::core::convert::Into::into(sport_id)])
330 }
331
332 pub fn league_id(self, league_id: impl ::core::convert::Into<$crate::league::LeagueId>) -> [<$name RequestDataBuilder>]<[<$name:snake _request_data_builder>]::SetLeagueIds<S>>
333 where
334 S::LeagueIds: [<$name:snake _request_data_builder>]::IsUnset
335 {
336 self.league_ids(::std::vec![::core::convert::Into::into(league_id)])
337 }
338 }
339 }
340
341 impl ::core::fmt::Display for [<$name RequestData>] {
342 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
343 use ::itertools::Itertools;
344
345 ::core::fmt::Write::write_fmt(f, ::core::format_args!("gameType={:?},", self.game_type))?;
346 if let ::core::option::Option::Some(season) = self.season {
347 ::core::fmt::Write::write_fmt(f, ::core::format_args!("season={},", season))?;
348 }
349 if let ::core::option::Option::Some(ids) = ::core::option::Option::as_ref(&self.team_ids) {
350 ::core::fmt::Write::write_fmt(f, ::core::format_args!("teamIds=[{}],", ids.iter().join(",")))?;
351 }
352 if let ::core::option::Option::Some(ids) = ::core::option::Option::as_ref(&self.sport_ids) {
353 ::core::fmt::Write::write_fmt(f, ::core::format_args!("sportIds=[{}],", ids.iter().join(",")))?;
354 }
355 if let ::core::option::Option::Some(ids) = ::core::option::Option::as_ref(&self.league_ids) {
356 ::core::fmt::Write::write_fmt(f, ::core::format_args!("leagueIds=[{}],", ids.iter().join(",")))?;
357 }
358 ::core::fmt::Write::write_fmt(f, ::core::format_args!("playerPool={},", self.player_pool))?;
359 if let ::core::option::Option::Some(limit) = ::core::option::Option::as_ref(&self.limit) {
360 ::core::fmt::Write::write_fmt(f, ::core::format_args!("limit={}", limit))?;
361 }
362
363 $crate::__stats__needle_haystack_metrics! { [$($stat_type),+] => {
364 ::core::fmt::Write::write_fmt(f, ::core::format_args!("metrics={},", self.metrics.iter().join(",")))?;
365 } else {}}
366 $crate::__stats__needle_haystack_date_range! { [$($stat_type),+] => {
367 ::core::fmt::Write::write_fmt(f, ::core::format_args!("startDate={},endDate={},", self.date_range.start().format($crate::MLB_API_DATE_FORMAT), self.date_range.end().format($crate::MLB_API_DATE_FORMAT)))?;
368 } else {}}
369 $crate::__stats__needle_haystack_situations! { [$($stat_type),+] => {
370 ::core::fmt::Write::write_fmt(f, ::core::format_args!("sitCodes=[{}],combineSits={},", self.situations.iter().join(","), self.situation_filter == $crate::meta::SituationCodeFilter::All))?;
371 } else {}}
372 $crate::__stats__needle_haystack_opponent_player! { [$($stat_type),+] => {
373 ::core::fmt::Write::write_fmt(f, ::core::format_args!("opposingPlayerId={},", self.opponent_player))?;
374 } else {}}
375
376 Ok(())
377 }
378 }
379
380 $crate::__stats__needle_haystack_metrics! { [$($stat_type),+] => {} else {
381 $crate::__stats__needle_haystack_date_range! { [$($stat_type),+] => {} else {
382 $crate::__stats__needle_haystack_situations! { [$($stat_type),+] => {} else {
383 $crate::__stats__needle_haystack_opponent_player! { [$($stat_type),+] => {} else {
384 impl ::core::default::Default for [<$name RequestData>] {
385 fn default() -> Self {
386 [<$name RequestDataBuilder>]::<[<$name:snake _request_data_builder>]::Empty>::build(Self::builder())
387 }
388 }
389 }}
390 }}
391 }}
392 }}
393
394 impl $name {
395 #[allow(unused, reason = "might use RequestData::builder() instead")]
396 pub fn builder() -> [<$name RequestDataBuilder>] {
397 [<$name RequestData>]::builder()
398 }
399 }
400 }
401 };
402}
403
404#[doc(hidden)]
405#[macro_export]
406macro_rules! __stats0 {
407 ($vis:vis struct $name:ident {
408 [$($stat_type:ident),+ $(,)?] + $stat_groups:tt
409 }) => {
410 ::pastey::paste! {
411 #[derive(Debug, PartialEq, Clone)]
412 $vis struct $name {
413 $($vis [<$stat_type:snake>]: [<$name $stat_type Split>],)*
414 }
415
416 #[doc(hidden)]
417 trait [<__ $name Split Parser>] {
418 fn parse(parsed_stats: &mut $crate::stats::parse::__ParsedStats) -> ::core::result::Result<Self, ::std::string::String>
419 where
420 Self: Sized;
421 }
422
423 $($crate::__stats__stat_type_definition!($name => $vis struct [<$name $stat_type Split>] { $stat_type => $stat_groups });)+
424
425 impl<'de> ::serde::Deserialize<'de> for $name {
426 fn deserialize<D: ::serde::de::Deserializer<'de>>(deserializer: D) -> ::core::result::Result<Self, D::Error>
427 where
428 Self: Sized
429 {
430 let mut parsed_stats: $crate::stats::parse::__ParsedStats = <$crate::stats::parse::__ParsedStats as ::serde::Deserialize>::deserialize(deserializer)?;
431
432 Ok(Self {
433 $([<$stat_type:snake>]: <[<$name $stat_type Split>] as [<__ $name Split Parser>]>::parse(&mut parsed_stats).map_err(<D::Error as ::serde::de::Error>::custom)?),+
434 })
435 }
436 }
437
438 $crate::__stats__request_data!($vis $name [$($stat_type),+]);
439
440 impl $crate::hydrations::Hydrations for $name {
441 type RequestData = [<$name RequestData>];
442
443 fn hydration_text(data: &<Self as $crate::hydrations::Hydrations>::RequestData) -> ::std::borrow::Cow<'static, str> {
444 let base: &'static str = $crate::__stats__base_hydration_text!([$($stat_type),+] $stat_groups);
445 let data: ::std::string::String = ::std::string::ToString::to_string(data);
446 if str::is_empty(&*data) {
447 ::std::borrow::Cow::Borrowed(base)
448 } else {
449 ::std::borrow::Cow::Owned(::std::format!("{base},{data}"))
450 }
451 }
452 }
453 }
454 };
455}
456
457
458#[macro_export]
470macro_rules! single_stat {
471 ($stat_type:ident + $stat_group:ident for $person_id:expr) => {
472 $crate::single_stat! { $stat_type + $stat_group for $person_id; with |builder| builder }
473 };
474 ($stat_type:ident + $stat_group:ident for $person_id:expr; with |$builder:ident| $builder_expr:expr) => {{
475 ::pastey::paste! {
476 $crate::person_hydrations! {
477 struct [<$stat_type $stat_group SingleStatHydrations >] {
478 stats: { [$stat_type] + [$stat_group] },
479 }
480 }
481
482 async {
483 let request = $crate::person::PersonRequest::<[<$stat_type $stat_group SingleStatHydrations >]>::builder().hydrations([<$stat_type $stat_group SingleStatHydrations>]::builder().stats({
484 let $builder = [<$stat_type $stat_group SingleStatHydrationsInlineStats>]::builder();
485 $builder_expr
486 })).id($person_id).build();
487 let response = $crate::request::RequestURL::get(&request).await;
488 response.and_then::<[$crate::person::Person<[<$stat_type $stat_group SingleStatHydrations>]>; 1], _>(|response|
489 response.people.try_into().map_err(|_| $crate::request::Error::MLB($crate::MLBError { message: "Expected one person in a single stat response".to_owned() }))
490 )
491 .map(|[person]| person.extras.stats.[<$stat_type:snake>].[<$stat_group:snake>].clone())
492 }
493 }
494 }};
495}
496
497#[macro_export]
583macro_rules! stats_hydrations {
584 ($($t:tt)*) => {
585 $crate::__stats0! { $($t)* }
586 };
587}