Skip to main content

mlb_api/requests/stats/
mod.rs

1#![allow(clippy::trait_duplication_in_bounds, reason = "serde")]
2
3use crate::hydrations::Hydrations;
4use serde::de::DeserializeOwned;
5use serde::Deserialize;
6use std::convert::Infallible;
7use std::fmt::Debug;
8
9pub mod macros;
10pub mod raw;
11pub mod wrappers;
12pub mod leaders;
13pub mod units;
14pub mod parse;
15// mod derived;
16#[cfg(test)]
17mod tests;
18
19// pub use derived::*;
20
21pub trait Stats: 'static + Debug + PartialEq + Eq + Clone + Hydrations {}
22
23impl Stats for () {}
24
25pub trait Stat: Debug + Clone + PartialEq + Eq + Default {
26	type Split: DeserializeOwned;
27
28	type TryFromSplitError;
29
30	/// # Errors
31	/// See [`Self::TryFromSplitError`]
32	fn from_splits(splits: impl Iterator<Item=Self::Split>) -> Result<Self, Self::TryFromSplitError> where Self: Sized;
33}
34
35/// Represents the types defined in [`raw`], not the wrapped final types. In the serialized format, this represents the `stat' field.
36pub trait RawStat: Debug + DeserializeOwned + Clone + Eq + Default {}
37
38impl RawStat for () {}
39impl SingletonSplitStat for () {}
40
41/// Represents types that are made from a single 'split' in the serialized format (able to be deserialized)
42pub trait SingletonSplitStat: Debug + DeserializeOwned + Clone + PartialEq + Eq + Default {
43
44}
45
46impl<T: SingletonSplitStat> Stat for T {
47	type Split = Self;
48
49	type TryFromSplitError = &'static str;
50
51	fn from_splits(mut splits: impl Iterator<Item=Self::Split>) -> Result<Self, Self::TryFromSplitError>
52	where
53		Self: Sized
54	{
55		Ok(splits.next().ok_or("length of stat splits is not >= 1, cannot convert to unit type.")?)
56	}
57}
58
59pub trait StatTypeStats {
60	type Hitting: Stat;
61
62	type Pitching: Stat;
63
64	type Fielding: Stat;
65
66	type Catching: Stat;
67}
68
69#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Default)]
70pub struct PlayStat {
71	// pub play: Play,
72}
73
74// todo: replace with real struct once game stuff is implemented
75pub type PitchStat = ();
76
77impl RawStat for PlayStat {}
78
79impl<T: Stat> Stat for Option<T> {
80	type Split = T::Split;
81	type TryFromSplitError = Infallible;
82
83	fn from_splits(splits: impl Iterator<Item=Self::Split>) -> Result<Self, Self::TryFromSplitError>
84	where
85		Self: Sized
86	{
87		Ok(T::from_splits(splits).ok())
88	}
89}
90
91#[doc(hidden)]
92pub mod stat_types {
93	use super::*;
94	use crate::stats::raw::{catching, fielding, hitting, pitching, FieldedMatchup};
95	use crate::stats::wrappers::{AccumulatedVsPlayerMatchup, ByMonth, ByPosition, BySeason, ByWeekday, Career, Map, Map2D, SingleMatchup, WithGame, WithHomeAndAway, WithMonth, WithPlayer, WithPositionAndSeason, WithSeason, WithTeam, WithWeekday, WithWinLoss};
96
97	macro_rules! stat_type_stats {
98		($name:ident {
99			$hitting:ty,
100			$pitching:ty,
101			$catching:ty,
102			$fielding:ty $(,)?
103		}) => {
104			::pastey::paste! {
105				#[doc(hidden)]
106				pub struct [<__ $name StatTypeStats>];
107
108				impl StatTypeStats for [<__ $name StatTypeStats>] {
109					type Hitting = $hitting;
110					type Pitching = $pitching;
111					type Fielding = $fielding;
112					type Catching = $catching;
113				}
114			}
115		};
116	}
117
118	// NOTES
119	// 1. Make sure all modules are correct, `hitting`, `pitching`, `catching`, then `fielding`.
120
121	stat_type_stats!(Projected { WithPlayer<hitting::__ProjectedStatsData>, WithPlayer<pitching::__ProjectedStatsData>, (), () });
122	stat_type_stats!(YearByYear { Map<WithSeason<hitting::__YearByYearStatsData>, BySeason>, Map<WithSeason<pitching::__YearByYearStatsData>, BySeason>, Map<WithSeason<catching::__YearByYearStatsData>, BySeason>, Map2D<WithPositionAndSeason<fielding::__YearByYearStatsData>, BySeason, ByPosition> });
123	stat_type_stats!(YearByYearAdvanced { Map<WithSeason<hitting::__YearByYearAdvancedStatsData>, BySeason>, Map<WithSeason<pitching::__YearByYearAdvancedStatsData>, BySeason>, (), () });
124	stat_type_stats!(Season { WithSeason<hitting::__SeasonStatsData>, WithSeason<pitching::__SeasonStatsData>, WithSeason<catching::__SeasonStatsData>, Map2D<WithPositionAndSeason<fielding::__SeasonStatsData>, BySeason, ByPosition> });
125	stat_type_stats!(Career { Career<hitting::__CareerStatsData>, Career<pitching::__CareerStatsData>, Career<catching::__CareerStatsData>, Career<fielding::__CareerStatsData> });
126	stat_type_stats!(SeasonAdvanced { WithSeason<hitting::__SeasonAdvancedStatsData>, WithSeason<pitching::__SeasonAdvancedStatsData>, (), () });
127	stat_type_stats!(CareerAdvanced { Career<hitting::__CareerAdvancedStatsData>, Career<pitching::__CareerAdvancedStatsData>, (), () });
128	stat_type_stats!(GameLog { Vec<WithGame<hitting::__GameLogStatsData>>, Vec<WithGame<pitching::__GameLogStatsData>>, Vec<WithGame<catching::__GameLogStatsData>>, Vec<WithGame<fielding::__GameLogStatsData>> });
129	stat_type_stats!(PlayLog { Vec<SingleMatchup<PlayStat>>, Vec<SingleMatchup<PlayStat>>, Vec<SingleMatchup<PlayStat>>, Vec<SingleMatchup<PlayStat>> });
130	stat_type_stats!(PitchLog { Vec<SingleMatchup<PitchStat>>, Vec<SingleMatchup<PitchStat>>, Vec<SingleMatchup<PitchStat>>, Vec<SingleMatchup<PitchStat>> });
131	// 'metricLog'?
132	// 'metricAverages'?
133	// stat_type_stats!(PitchArsenal { Vec<PitchUsage>, Vec<PitchUsage>, (), () }); // has no stat group
134	// 'outsAboveAverage'?
135	stat_type_stats!(ExpectedStatistics { WithPlayer<hitting::__ExpectedStatisticsStatsData>, WithPlayer<pitching::__ExpectedStatisticsStatsData>, (), () });
136	stat_type_stats!(Sabermetrics { WithPlayer<hitting::__SabermetricsStatsData>, WithPlayer<pitching::__SabermetricsStatsData>, (), () });
137	// stat_type_stats!(SprayChart { SprayChart, SprayChart, (), () }); // does not have statGroup on the response
138	// 'tracking'?
139	// stat_type_stats!(VsPlayer { AccumulatedMatchup<VsPlayerHittingStats>, AccumulatedMatchup<VsPlayerPitchingStats>, (), () });
140	// stat_type_stats!(VsPlayerTotal { AccumulatedMatchup<VsPlayerHittingStats>, AccumulatedMatchup<VsPlayerPitchingStats>, (), () });
141	stat_type_stats!(VsPlayer5Y { AccumulatedVsPlayerMatchup<hitting::__VsPlayerStatsData>, AccumulatedVsPlayerMatchup<pitching::__VsPlayerStatsData>, (), () });
142	// stat_type_stats!(VsTeam { Multiple<AccumulatedVsTeamSeasonalPitcherSplit<HittingStats>>, (), (), () });
143	// stat_type_stats!(VsTeam5Y { Multiple<AccumulatedVsTeamSeasonalPitcherSplit<HittingStats>>, (), (), () });
144	// stat_type_stats!(VsTeamTotal { AccumulatedVsTeamTotalMatchup<HittingStats>, (), (), () });
145	stat_type_stats!(LastXGames { WithTeam<hitting::__LastXGamesStatsData>, WithTeam<pitching::__LastXGamesStatsData>, WithTeam<catching::__LastXGamesStatsData>, WithTeam<fielding::__LastXGamesStatsData> });
146	stat_type_stats!(ByDateRange { WithTeam<hitting::__ByDateRangeStatsData>, WithTeam<pitching::__ByDateRangeStatsData>, WithTeam<catching::__ByDateRangeStatsData>, WithTeam<fielding::__ByDateRangeStatsData> });
147	stat_type_stats!(ByDateRangeAdvanced { WithTeam<hitting::__ByDateRangeAdvancedStatsData>, WithTeam<pitching::__ByDateRangeAdvancedStatsData>, WithTeam<catching::__ByDateRangeAdvancedStatsData>, WithTeam<fielding::__ByDateRangeAdvancedStatsData> });
148	stat_type_stats!(ByMonth { Map<WithMonth<hitting::__ByMonthStatsData>, ByMonth>, Map<WithMonth<pitching::__ByMonthStatsData>, ByMonth>, Map<WithMonth<catching::__ByMonthStatsData>, ByMonth>, Map<WithMonth<fielding::__ByMonthStatsData>, ByMonth> });
149	stat_type_stats!(ByDayOfWeek { Map<WithWeekday<hitting::__ByDayOfWeekStatsData>, ByWeekday>, Map<WithWeekday<pitching::__ByDayOfWeekStatsData>, ByWeekday>, Map<WithWeekday<catching::__ByDayOfWeekStatsData>, ByWeekday>, Map<WithWeekday<fielding::__ByDayOfWeekStatsData>, ByWeekday> });
150	stat_type_stats!(HomeAndAway { WithHomeAndAway<hitting::__HomeAndAwayStatsData>, WithHomeAndAway<pitching::__HomeAndAwayStatsData>, WithHomeAndAway<catching::__HomeAndAwayStatsData>, WithHomeAndAway<fielding::__HomeAndAwayStatsData> });
151	stat_type_stats!(WinLoss { WithWinLoss<hitting::__WinLossStatsData>, WithWinLoss<pitching::__WinLossStatsData>, WithWinLoss<catching::__WinLossStatsData>, WithWinLoss<fielding::__WinLossStatsData> });
152	// stat_type_stats!(Rankings { WithPlayerAndTeam<hitting::__RankingsStatsData>, WithPlayerAndTeam<pitching::__RankingsStatsData>, (), () });
153	// stat_type_stats!(RankingsByYear { Map<WithPlayerAndTeam<hitting::__RankingsByYearStatsData>, BySeason>, Map<WithPlayerAndTeam<pitching::__RankingsByYearStatsData>, BySeason>, (), () });
154	// stat_type_stats!(HotColdZones { HittingHotColdZones, PitchingHotColdZones, (), () }); // has no stat group
155	stat_type_stats!(OpponentsFaced { Vec<FieldedMatchup>, Vec<FieldedMatchup>, Vec<FieldedMatchup>, Vec<FieldedMatchup> });
156	stat_type_stats!(StatSplits { WithSeason<hitting::__StatSplitsStatsData>, WithSeason<pitching::__StatSplitsStatsData>, (), () });
157	stat_type_stats!(StatSplitsAdvanced { WithSeason<hitting::__StatSplitsAdvancedStatsData>, WithSeason<pitching::__StatSplitsAdvancedStatsData>, (), () });
158	// stat_type_stats!(AtGameStart { Multiple<WithGame<hitting::AtGameStart>>, Multiple<WithGame<pitching::AtGameStart>>, Multiple<WithGame<catching::AtGameStart>>, Multiple<WithGame<fielding::AtGameStart>> });
159	// 'vsOpponents'?
160}