#[macro_export]
#[doc(hidden)]
macro_rules! __stats__stat_type_definition {
    ($parent_name:ident => $vis:vis struct $name:ident { $stat_type:ident => [$($stat_group:ident),+] }) => {
		::pastey::paste! {
			#[derive(Debug, PartialEq, Clone)]
			$vis struct $name {
				$($vis [< $stat_group:snake >]: ::std::boxed::Box<<$crate::stats::stat_types::[<__ $stat_type StatTypeStats>] as $crate::stats::StatTypeStats>::$stat_group>),+
			}

			impl [<__ $parent_name Split Parser>] for $name {
				fn parse(parsed_stats: &mut $crate::stats::parse::__ParsedStats) -> ::core::result::Result<Self, ::std::string::String> {
					Ok(Self {
						$([<$stat_group:snake>]: ::std::boxed::Box::new(
							$crate::stats::parse::make_stat_split::<<$crate::stats::stat_types::[< __ $stat_type StatTypeStats >] as $crate::stats::StatTypeStats>::$stat_group>(
								parsed_stats, ::core::stringify!([<$stat_type:lower_camel>]), $crate::meta::StatGroup::$stat_group
							).map_err(|e| ::std::string::ToString::to_string(&e))?
						)),+
					})
				}
			}
    	}
	};
}

#[macro_export]
#[doc(hidden)]
macro_rules! __stats__base_hydration_text {
    ([$first_stat_type:ident $(, $stat_type:ident)* $(,)?] [$first_stat_group:ident $(, $stat_group:ident)* $(,)?]) => {
		::pastey::paste! {
			::core::concat!(
				"type=[",
				::core::stringify!([<$first_stat_type:lower_camel>]),
				$(",", ::core::stringify!([<$stat_type:lower_camel>]), )*
				"],group=[",
				::core::stringify!([<$first_stat_group:lower_camel>]),
				$(",", ::core::stringify!([<$stat_group:lower_camel>]), )*
				"]"
			)
		}
	};
}

// macro_rules! __stats__generate_needle_haystack_predicate {
//     ($name:ident ! ( $($needle:ident),+ ) $d:tt) => {
// 		#[macro_export]
// 		#[doc(hidden)]
// 		macro_rules! $name {
// 			$(
// 			([$needle $d (, $d haystack:ident)* $d (,)?] => { $d ($d t1:tt)* } else { $d ($d t2:tt)* }) => {
// 				$d ($d t1)*
// 			};
// 			)+
// 			([$d first:ident $d(, $d haystack:ident)* $d (,)?] => { $d ($d t1:tt)* } else { $d ($d t2:tt)* }) => {
// 				$name!([$d($d haystack),*] => { $d ($d t1)* } else { $d ($d t2)* });
// 			};
//     		([$d(,)?] => { $d ($d t1:tt)* } else { $d ($d t2:tt)* }) => { $d ($d t2)* };
// 		}
//
// 		#[doc(hidden)]
// 		pub use $name;
// 	};
// }

/// Generated by [`__stats__generate_needle_haystack_predicate`], cannot inline due to <https://github.com/rust-lang/rust/pull/52234>
#[macro_export]
#[doc(hidden)]
macro_rules! __stats__needle_haystack_metrics {
	([$($haystack:ident),+ $(,)?] => { $($t:tt)* }) => {
		$crate::__stats__needle_haystack_metrics!([$($haystack),+] => { $($t)* } else {});
	};
	([MetricLog $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
		$($t1)*
	};
	([MetricAverages $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
		$($t1)*
	};
	([$first:ident $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
		$crate::__stats__needle_haystack_metrics!([$($haystack),*] => { $($t1)* } else { $($t2)* });
	};
	([$(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => { $($t2)* };
}

/// Generated by [`__stats__generate_needle_haystack_predicate`], cannot inline due to <https://github.com/rust-lang/rust/pull/52234>
#[macro_export]
#[doc(hidden)]
macro_rules! __stats__needle_haystack_date_range {
	([$($haystack:ident),+ $(,)?] => { $($t:tt)* }) => {
		$crate::__stats__needle_haystack_date_range!([$($haystack),+] => { $($t)* } else {});
	};
	([ByDateRange $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
		$($t1)*
	};
	([$first:ident $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
		$crate::__stats__needle_haystack_date_range!([$($haystack),*] => { $($t1)* } else { $($t2)* });
	};
	([$(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => { $($t2)* };
}

/// Generated by [`__stats__generate_needle_haystack_predicate`], cannot inline due to <https://github.com/rust-lang/rust/pull/52234>
#[macro_export]
#[doc(hidden)]
macro_rules! __stats__needle_haystack_situations {
	([$($haystack:ident),+ $(,)?] => { $($t:tt)* }) => {
		$crate::__stats__needle_haystack_situations!([$($haystack),+] => { $($t)* } else {});
	};
	([StatSplits $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
		$($t1)*
	};
	([StatSplitsAdvanced $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
		$($t1)*
	};
	([$first:ident $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
		$crate::__stats__needle_haystack_situations!([$($haystack),*] => { $($t1)* } else { $($t2)* });
	};
	([$(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => { $($t2)* };
}

/// Generated by [`__stats__generate_needle_haystack_predicate`], cannot inline due to <https://github.com/rust-lang/rust/pull/52234>
#[macro_export]
#[doc(hidden)]
macro_rules! __stats__needle_haystack_games_back {
	([$($haystack:ident),+ $(,)?] => { $($t:tt)* }) => {
		$crate::__stats__needle_haystack_games_back!([$($haystack),+] => { $($t)* } else {});
	};
	([LastXGames $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
		$($t1)*
	};
	([$first:ident $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
		$crate::__stats__needle_haystack_games_back!([$($haystack),*] => { $($t1)* } else { $($t2)* });
	};
	([$(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => { $($t2)* };
}

/// Generated by [`__stats__generate_needle_haystack_predicate`], cannot inline due to <https://github.com/rust-lang/rust/pull/52234>
#[macro_export]
#[doc(hidden)]
macro_rules! __stats__needle_haystack_opponent_player {
	([$($haystack:ident),+ $(,)?] => { $($t:tt)* }) => {
		$crate::__stats__needle_haystack_opponent_player!([$($haystack),+] => { $($t)* } else {});
	};
	([VsPlayer5Y $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
		$($t1)*
	};
	([VsPlayerTotal $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
		$($t1)*
	};
	([VsPlayer $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
		$($t1)*
	};
	([$first:ident $(, $haystack:ident)* $(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => {
		$crate::__stats__needle_haystack_opponent_player!([$($haystack),*] => { $($t1)* } else { $($t2)* });
	};
	([$(,)?] => { $($t1:tt)* } else { $($t2:tt)* }) => { $($t2)* };
}

#[macro_export]
#[doc(hidden)]
macro_rules! __stats__request_data {
	(@ metrics [$($stat_type:ident),+] $(#[$m:meta])* $vis:vis struct $name:ident { $($field_tt:tt)* } $($impl_tt:tt)*) => {
		::pastey::paste! {
			$crate::__stats__needle_haystack_metrics! { [$($stat_type),+] => {
				$crate::__stats__request_data! { @ date_range [$($stat_type),+]
					$(#[$m])*
					$vis struct $name {
						$($field_tt)*
						metrics: ::std::vec::Vec<$crate::meta::MetricId>,
					}
					$($impl_tt)*
					impl<S: [<$name:snake _builder>]::State> [<$name Builder>]<S> {
						pub fn metric(self, metric: impl ::core::convert::Into<$crate::meta::MetricId>) -> [<$name Builder>]<[<$name:snake _builder>]::SetMetrics<S>>
						where
							S::Metrics: [<$name:snake _builder>]::IsUnset
						{
							self.metrics(::std::vec![::core::convert::Into::into(metric)])
						}
					}
				}
			} else {
				$crate::__stats__request_data! { @ date_range [$($stat_type),+]
					$(#[$m])*
					$vis struct $name {
						$($field_tt)*
					}
					$($impl_tt)*
				}
			}}
		}
	};
	(@ date_range [$($stat_type:ident),+] $(#[$m:meta])* $vis:vis struct $name:ident { $($field_tt:tt)* } $($impl_tt:tt)*) => {
		::pastey::paste! {
			$crate::__stats__needle_haystack_date_range!{[$($stat_type),+] => {
				$crate::__stats__request_data! { @ situations [$($stat_type),+]
					$(#[$m])*
					$vis struct $name {
						$($field_tt)*
						date_range: $crate::NaiveDateRange,
					}
					$($impl_tt)*
				}
			} else {
				$crate::__stats__request_data! { @ situations [$($stat_type),+]
					$(#[$m])*
					$vis struct $name {
						$($field_tt)*
					}
					$($impl_tt)*
				}
			}}
		}
	};
	(@ situations [$($stat_type:ident),+] $(#[$m:meta])* $vis:vis struct $name:ident { $($field_tt:tt)* } $($impl_tt:tt)*) => {
		::pastey::paste! {
			$crate::__stats__needle_haystack_situations!{[$($stat_type),+] => {
				$crate::__stats__request_data! { @ games_back [$($stat_type),+]
					$(#[$m])*
					$vis struct $name {
						$($field_tt)*
						situations: ::std::vec::Vec<$crate::meta::SituationCodeId>,
						#[builder(default)]
						situation_filter: $crate::meta::SituationCodeFilter,
					}
					$($impl_tt)*
					impl<S: [<$name:snake _builder>]::State> [<$name Builder>]<S> {
						#[allow(dead_code, reason = "could be used by the end user")]
						pub fn situation(self, situation: impl ::core::convert::Into<$crate::meta::SituationCodeId>) -> [<$name Builder>]<[<$name:snake _builder>]::SetSituations<S>>
						where
							S::Situations: [<$name:snake _builder>]::IsUnset
						{
							self.situations(::std::vec![::core::convert::Into::into(situation)])
						}
					}
				}
			} else {
				$crate::__stats__request_data! { @ games_back [$($stat_type),+]
					$(#[$m])*
					$vis struct $name {
						$($field_tt)*
					}
					$($impl_tt)*
				}
			}}
		}
	};
	(@ games_back [$($stat_type:ident),+] $(#[$m:meta])* $vis:vis struct $name:ident { $($field_tt:tt)* } $($impl_tt:tt)*) => {
		::pastey::paste! {
			$crate::__stats__needle_haystack_games_back!{[$($stat_type),+] => {
				$crate::__stats__request_data! { @ opponent_player [$($stat_type),+]
					$(#[$m])*
					$vis struct $name {
						$($field_tt)*
						games_back: usize,
					}
					$($impl_tt)*
				}
			} else {
				$crate::__stats__request_data! { @ opponent_player [$($stat_type),+]
					$(#[$m])*
					$vis struct $name {
						$($field_tt)*
					}
					$($impl_tt)*
				}
			}}
		}
	};
	(@ opponent_player [$($stat_type:ident),+] $(#[$m:meta])* $vis:vis struct $name:ident { $($field_tt:tt)* } $($impl_tt:tt)*) => {
		::pastey::paste! {
			$crate::__stats__needle_haystack_opponent_player!{[$($stat_type),+] => {
				// $crate::__stats__request_data! { @ ? [$($stat_type),+]
					$(#[$m])*
					$vis struct $name {
						$($field_tt)*
						#[builder(into)]
						opponent_player: $crate::person::PersonId,
					}
					$($impl_tt)*
				// }
			} else {
				// $crate::__stats__request_data! { @ ? [$($stat_type),+]
					$(#[$m])*
					$vis struct $name {
						$($field_tt)*
					}
					$($impl_tt)*
				// }
			}}
		}
	};
    ($vis:vis $name:ident [$($stat_type:ident),+]) => {
		::pastey::paste! {
			$crate::__stats__request_data! { @ metrics [$($stat_type),+]
				#[derive(::bon::Builder)]
				#[builder(derive(Into))]
				#[allow(unused, reason = "could be unused by the end user")]
				$vis struct [<$name RequestData>] {
					#[builder(default)]
					game_type: $crate::meta::GameType,
					#[builder(into)]
					season: ::core::option::Option<$crate::season::SeasonId>,
					team_ids: ::core::option::Option<::std::vec::Vec<$crate::team::TeamId>>,
					sport_ids: ::core::option::Option<::std::vec::Vec<$crate::sport::SportId>>,
					league_ids: ::core::option::Option<::std::vec::Vec<$crate::league::LeagueId>>,
					limit: Option<usize>,
					#[builder(default)]
					player_pool: $crate::PlayerPool,


					/*batter_team: TeamId,
					pitcher_team: TeamId,
					batter: PersonId,
					pitcher: PersonId,
					days_back: usize*/
				}

				#[allow(unused, reason = "may be used by end user")]
				impl<S: [<$name:snake _request_data_builder>]::State> [<$name RequestDataBuilder>]<S> {
					pub fn team_id(self, team_id: impl ::core::convert::Into<$crate::team::TeamId>) -> [<$name RequestDataBuilder>]<[<$name:snake _request_data_builder>]::SetTeamIds<S>>
					where
						S::TeamIds: [<$name:snake _request_data_builder>]::IsUnset
					{
						self.team_ids(::std::vec![::core::convert::Into::into(team_id)])
					}

					pub fn sport_id(self, sport_id: impl ::core::convert::Into<$crate::sport::SportId>) -> [<$name RequestDataBuilder>]<[<$name:snake _request_data_builder>]::SetSportIds<S>>
					where
						S::SportIds: [<$name:snake _request_data_builder>]::IsUnset
					{
						self.sport_ids(::std::vec![::core::convert::Into::into(sport_id)])
					}

					pub fn league_id(self, league_id: impl ::core::convert::Into<$crate::league::LeagueId>) -> [<$name RequestDataBuilder>]<[<$name:snake _request_data_builder>]::SetLeagueIds<S>>
					where
						S::LeagueIds: [<$name:snake _request_data_builder>]::IsUnset
					{
						self.league_ids(::std::vec![::core::convert::Into::into(league_id)])
					}
				}
			}

			impl ::core::fmt::Display for [<$name RequestData>] {
				fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
					use ::itertools::Itertools;

					::core::fmt::Write::write_fmt(f, ::core::format_args!("gameType={:?},", self.game_type))?;
					if let ::core::option::Option::Some(season)	= self.season {
						::core::fmt::Write::write_fmt(f, ::core::format_args!("season={},", season))?;
					}
					if let ::core::option::Option::Some(ids) = ::core::option::Option::as_ref(&self.team_ids) {
						::core::fmt::Write::write_fmt(f, ::core::format_args!("teamIds=[{}],", ids.iter().join(",")))?;
					}
					if let ::core::option::Option::Some(ids) = ::core::option::Option::as_ref(&self.sport_ids) {
						::core::fmt::Write::write_fmt(f, ::core::format_args!("sportIds=[{}],", ids.iter().join(",")))?;
					}
					if let ::core::option::Option::Some(ids) = ::core::option::Option::as_ref(&self.league_ids) {
						::core::fmt::Write::write_fmt(f, ::core::format_args!("leagueIds=[{}],", ids.iter().join(",")))?;
					}
					::core::fmt::Write::write_fmt(f, ::core::format_args!("playerPool={},", self.player_pool))?;
					if let ::core::option::Option::Some(limit) = ::core::option::Option::as_ref(&self.limit) {
						::core::fmt::Write::write_fmt(f, ::core::format_args!("limit={}", limit))?;
					}

					$crate::__stats__needle_haystack_metrics! { [$($stat_type),+] => {
						::core::fmt::Write::write_fmt(f, ::core::format_args!("metrics={},", self.metrics.iter().join(",")))?;
					} else {}}
					$crate::__stats__needle_haystack_date_range! { [$($stat_type),+] => {
						::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)))?;
					} else {}}
					$crate::__stats__needle_haystack_situations! { [$($stat_type),+] => {
						::core::fmt::Write::write_fmt(f, ::core::format_args!("sitCodes=[{}],combineSits={},", self.situations.iter().join(","), self.situation_filter == $crate::meta::SituationCodeFilter::All))?;
					} else {}}
					$crate::__stats__needle_haystack_opponent_player! { [$($stat_type),+] => {
						::core::fmt::Write::write_fmt(f, ::core::format_args!("opposingPlayerId={},", self.opponent_player))?;
					} else {}}

					Ok(())
				}
			}

			$crate::__stats__needle_haystack_metrics! { [$($stat_type),+] => {} else {
				$crate::__stats__needle_haystack_date_range! { [$($stat_type),+] => {} else {
					$crate::__stats__needle_haystack_situations! { [$($stat_type),+] => {} else {
						$crate::__stats__needle_haystack_opponent_player! { [$($stat_type),+] => {} else {
							impl ::core::default::Default for [<$name RequestData>] {
								fn default() -> Self {
									[<$name RequestDataBuilder>]::<[<$name:snake _request_data_builder>]::Empty>::build(Self::builder())
								}
							}
						}}
					}}
				}}
			}}

			impl $name {
				#[allow(unused, reason = "might use RequestData::builder() instead")]
				pub fn builder() -> [<$name RequestDataBuilder>] {
					[<$name RequestData>]::builder()
				}
			}
		}
	};
}

#[doc(hidden)]
#[macro_export]
macro_rules! __stats0 {
    ($vis:vis struct $name:ident {
		[$($stat_type:ident),+ $(,)?] + $stat_groups:tt
	}) => {
		::pastey::paste! {
			#[derive(Debug, PartialEq, Clone)]
        	$vis struct $name {
				$($vis [<$stat_type:snake>]: [<$name $stat_type Split>],)*
			}

			#[doc(hidden)]
			trait [<__ $name Split Parser>] {
				fn parse(parsed_stats: &mut $crate::stats::parse::__ParsedStats) -> ::core::result::Result<Self, ::std::string::String>
				where
					Self: Sized;
			}

			$($crate::__stats__stat_type_definition!($name => $vis struct [<$name $stat_type Split>] { $stat_type => $stat_groups });)+

			impl<'de> ::serde::Deserialize<'de> for $name {
				fn deserialize<D: ::serde::de::Deserializer<'de>>(deserializer: D) -> ::core::result::Result<Self, D::Error>
				where
					Self: Sized
				{
					let mut parsed_stats: $crate::stats::parse::__ParsedStats = <$crate::stats::parse::__ParsedStats as ::serde::Deserialize>::deserialize(deserializer)?;

					Ok(Self {
						$([<$stat_type:snake>]: <[<$name $stat_type Split>] as [<__ $name Split Parser>]>::parse(&mut parsed_stats).map_err(<D::Error as ::serde::de::Error>::custom)?),+
					})
				}
			}

			$crate::__stats__request_data!($vis $name [$($stat_type),+]);

			impl $crate::hydrations::Hydrations for $name {
				type RequestData = [<$name RequestData>];

                fn hydration_text(data: &<Self as $crate::hydrations::Hydrations>::RequestData) -> ::std::borrow::Cow<'static, str> {
					let base: &'static str = $crate::__stats__base_hydration_text!([$($stat_type),+] $stat_groups);
					let data: ::std::string::String = ::std::string::ToString::to_string(data);
					if str::is_empty(&*data) {
						::std::borrow::Cow::Borrowed(base)
					} else {
						::std::borrow::Cow::Owned(::std::format!("{base},{data}"))
					}
				}
            }
		}
    };
}


// todo: see why we need a clone

/// Shorthand function for getting a single [`StatType`] and [`StatGroup`] for a specific player.
///
/// ## Examples
/// ```no_run
/// let stat = single_stat!(Season + Hitting for 660_271).await.unwrap();
/// 
/// // or supply builder params with
/// let stat = single_stat!(Season + Hitting for 660_271; with |builder| builder.season(2024)).await.unwrap();
/// ```
#[macro_export]
macro_rules! single_stat {
	($stat_type:ident + $stat_group:ident for $person_id:expr) => {
		$crate::single_stat! { $stat_type + $stat_group for $person_id; with |builder| builder }
	};
	($stat_type:ident + $stat_group:ident for $person_id:expr; with |$builder:ident| $builder_expr:expr) => {{
		::pastey::paste! {
			$crate::person_hydrations! {
				struct [<$stat_type $stat_group SingleStatHydrations >] {
				    stats: { [$stat_type] + [$stat_group] },
				}
			}
			
			async {
				let request = $crate::person::PersonRequest::<[<$stat_type $stat_group SingleStatHydrations >]>::builder().hydrations([<$stat_type $stat_group SingleStatHydrations>]::builder().stats({
					let $builder = [<$stat_type $stat_group SingleStatHydrationsInlineStats>]::builder();
					$builder_expr
				})).id($person_id).build();
				let response = $crate::request::RequestURL::get(&request).await;
				response.and_then::<[$crate::person::Person<[<$stat_type $stat_group SingleStatHydrations>]>; 1], _>(|response|
					response.people.try_into().map_err(|_| $crate::request::Error::MLB($crate::MLBError { message: "Expected one person in a single stat response".to_owned() }))
				)
				.map(|[person]| person.extras.stats.[<$stat_type:snake>].[<$stat_group:snake>].clone())
			}
		}
	}};
}

/// Generates stat data types to be used in requests.
///
/// These are commonly associated with [`person_hydrations`](crate::person_hydrations) to create a [`PersonRequest`](crate::person::PersonRequest).
///
/// # Stat Types & Stat Groups for [`stats_hydrations!`](crate::stats_hydrations!)
///
/// | Name                  | Stat Type                            | Stat Group | Notes                        |
/// |-----------------------|--------------------------------------|------------|------------------------------|
/// | `Projected`           | [`WithPlayer<_>`]                    | **`HP--`** | likely ZIPS projections      |
/// | `YearByYear`          | [`HashMap<SeasonId, WithSeason<_>>`] | **`HPCF`** | 1.                           |
/// | `YearByYearAdvanced`  | [`HashMap<SeasonId, WithSeason<_>>`] | **`HP--`** | 1.                           |
/// | `Season`              | [`WithSeason<_>`]                    | **`HPCF`** |                              |
/// | `Career`              | [`Career<_>`]                        | **`HPCF`** |                              |
/// | `SeasonAdvanced`      | [`WithSeason<_>`]                    | **`HP--`** |                              |
/// | `CareerAdvanced`      | [`Career<_>`]                        | **`HP--`** |                              |
/// | `GameLog`             | [`Vec<WithGame<_>>`]                 | **`HPCF`** |                              |
/// | `PlayLog`             | [`Vec<SingleMatchup<Play<_>>>`]      | **`HPCF`** | same format as in games      |
/// | `PitchLog`            | [`Vec<SingleMatchup<PitchStat>>`]    | **`HPCF`** | same format as in games      |
/// | `ExpectedStatistics`  | *no wrapper*                         | **`HP--`** | `xAVG`, `xwOBA`, etc.        |
/// | `Sabermetrics`        | *no wrapper*                         | **`HP--`** | `xFIP`, `fWAR`, etc.         |
/// | `VsPlayer5Y`          | [`AccumulatedVsPlayerMatchup<_>`]    | **`HP--`** | `opposing_player` in builder |
/// | `LastXGames`          | [`WithTeam<_>`]                      | **`HPCF`** | `games_back` in builder      |
/// | `ByDateRange`         | [`WithTeam<_>`]                      | **`HPCF`** | `date_range` in builder      |
/// | `ByDateRangeAdvanced` | [`WithTeam<_>`]                      | **`HPCF`** | `date_range` in builder      |
/// | `ByMonth`             | [`HashMap<Month, WithMonth<_>>`]     | **`HPCF`** |                              |
/// | `ByDayOfWeek`         | [`HashMap<Weekday, WithWeekday<_>>`] | **`HPCF`** |                              |
/// | `HomeAndAway`         | [`WithHomeAndAway<_>`]               | **`HPCF`** |                              |
/// | `WinLoss`             | [`WithWinLoss<_>`]                   | **`HPCF`** |                              |
/// | `OpponentsFaced`      | [`FieldedMatchup`]                   | **`HPCF`** |                              |
/// | `StatSplits`          | [`WithSeason<_>`]                    | **`HP--`** | `situations` in builder      |
/// | `StatSplitsAdvanced`  | [`WithSeason<_>`]                    | **`HP--`** | `situations` in builder      |
///
/// Note: `HPCF` stands for Hitting, Pitching, Catching, and Fielding. [`StatType`]s will be marked as for what [`StatGroup`]s they support in requests.
///
/// Table Footnotes
/// 1. Seasons will display the last entry sent via the API, which is typically a full season with multiple teams, as opposed to the split with one team (ex. if a player is traded at the deadline).
///
/// # Examples
///```
/// mlb_api::stats_hydrations! {
///     pub struct MyStats {
///         [Season, Career] + [Hitting, Pitching]
///     }
/// }
///
/// mlb_api::person_hydrations! {
///     pub struct MyStatsHydrations {
///         stats: MyStats,
///     }
/// }
///
/// let response = mlb_api::person::PersonRequest::<MyStatsHydrations>::builder()
///     .id(id)
///     .hydrations(MyStatsHydrations::builder()
///         .stats(MyStats::builder()))
///     .build_and_get()
///     .await?;
///
/// // for simple requests which don't involve values supplied in the builder (see table above), this also works:
/// let response = mlb_api::person::PersonRequest::<MyStatsHydrations>::for_id(id)
///     .build_and_get()
///     .await?;
///
/// let stats: &MyStats = &response.people[0].extras.stats;
///```
///
/// [`HashMap<SeasonId, WithSeason<_>>`]: crate::stats::wrappers::WithSeason
/// [`WithSeason<_>`]: crate::stats::wrappers::WithSeason
/// [`Career<_>`]: crate::stats::wrappers::Career
/// [`Vec<WithGame<_>>`]: crate::stats::wrappers::WithGame
/// [`Vec<SingleMatchup<Play<_>>>`]: crate::stats::wrappers::SingleMatchup
/// [`Vec<SingleMatchup<PitchStat>>`]: crate::stats::wrappers::SingleMatchup
/// [`Vec<PitchUsage>`]: crate::stats::raw::PitchUsage
/// [`AccumulatedVsPlayerMatchup<_>`]: crate::stats::wrappers::AccumulatedVsPlayerMatchup
/// [`WithTeam<_>`]: crate::stats::wrappers::WithTeam
/// [`HashMap<Month, WithMonth<_>>`]: crate::stats::wrappers::WithMonth
/// [`HashMap<Weekday, WithWeekday<_>>`]: crate::stats::wrappers::WithWeekday
/// [`WithHomeAndAway<_>`]: crate::stats::wrappers::WithHomeAndAway
/// [`WithWinLoss<_>`]: crate::stats::wrappers::WithWinLoss
/// [`HittingHotColdZones`]: crate::stats::raw::HittingHotColdZones
/// [`PitchingHotColdZones`]: crate::stats::raw::PitchingHotColdZones
/// [`FieldedMatchup`]: crate::stats::raw::FieldedMatchup
/// [`StatType`]: crate::meta::StatType
/// [`StatGroup`]: crate::meta::StatGroup
/// [`WithPlayer<_>`]: crate::stats::wrappers::WithPlayer
#[macro_export]
macro_rules! stats_hydrations {
    ($($t:tt)*) => {
		$crate::__stats0! { $($t)* }
	};
}
