Skip to main content

mlb_api/requests/meta/
mod.rs

1macro_rules! meta_kind_impl {
2	($endpoint:literal => $name:ty) => {
3		impl $crate::meta::MetaKind for $name {
4			type Complete = $name;
5
6			const ENDPOINT_NAME: &'static str = $endpoint;
7		}
8	};
9}
10
11macro_rules! test_impl {
12    ($name:ty) => {
13		#[cfg(test)]
14		mod tests {
15			use super::*;
16			use crate::request::RequestURL;
17
18			#[tokio::test]
19			async fn parse_meta() {
20				let _response = $crate::meta::MetaRequest::<$name>::new().get().await.unwrap();
21			}
22		}
23	};
24}
25
26macro_rules! tiered_request_entry_cache_impl {
27	($complete:ident.$id_field:ident: $id:ident) => {
28		tiered_request_entry_cache_impl!([$complete].$id_field: $id);
29	};
30	([$complete:ident $(, $($others:ident)*)?].$id_field:ident: $id:ident) => {
31		#[cfg(feature = "cache")]
32		static CACHE: $crate::RwLock<$crate::cache::CacheTable<$complete>> = $crate::rwlock_const_new($crate::cache::CacheTable::new());
33
34		impl $crate::cache::Requestable for $complete {
35			type Identifier = $id;
36			type URL = $crate::meta::MetaRequest<Self>;
37
38			fn id(&self) -> &Self::Identifier {
39				&self.$id_field
40			}
41
42			fn url_for_id(_id: &Self::Identifier) -> Self::URL {
43				$crate::meta::MetaRequest::new()
44			}
45
46			fn get_entries(response: <Self::URL as $crate::request::RequestURL>::Response) -> impl IntoIterator<Item=Self>
47			where
48				Self: Sized
49			{
50				response.entries
51			}
52
53			#[cfg(feature = "cache")]
54			fn get_cache_table() -> &'static $crate::RwLock<$crate::cache::CacheTable<Self>>
55			where
56				Self: Sized
57			{
58				&CACHE
59			}
60		}
61
62		entrypoint!($complete.$id_field => $complete);
63		$($(
64		entrypoint!($others.$id_field => $complete);
65		)*)?
66		entrypoint!($id => $complete);
67	};
68}
69
70macro_rules! static_request_entry_cache_impl {
71    ($name:ident) => {
72	    #[cfg(feature = "cache")]
73		static CACHE: $crate::RwLock<$crate::cache::CacheTable<$name>> = $crate::rwlock_const_new($crate::cache::CacheTable::new());
74
75		impl $crate::cache::Requestable for $name {
76			type Identifier = Self;
77			type URL = $crate::meta::MetaRequest<Self>;
78
79			fn id(&self) -> &Self::Identifier {
80				self
81			}
82
83			fn url_for_id(_id: &Self::Identifier) -> Self::URL {
84				$crate::meta::MetaRequest::new()
85			}
86
87			fn get_entries(response: <Self::URL as $crate::request::RequestURL>::Response) -> impl IntoIterator<Item=Self>
88			where
89				Self: Sized
90			{
91				response.entries
92			}
93
94			#[cfg(feature = "cache")]
95			fn get_cache_table() -> &'static $crate::RwLock<$crate::cache::CacheTable<Self>>
96			where
97				Self: Sized
98			{
99				&CACHE
100			}
101		}
102		
103		entrypoint!($name => $name);
104	};
105}
106
107pub mod baseball_stats;
108pub mod event_types;
109pub mod game_status;
110pub mod game_types;
111pub mod hit_trajectories;
112pub mod job_types;
113pub mod languages;
114pub mod league_leader_types;
115pub mod logical_events;
116pub mod metrics;
117pub mod pitch_codes;
118pub mod pitch_types;
119pub mod platforms;
120pub mod positions;
121pub mod review_reasons;
122pub mod roster_types;
123pub mod schedule_event_types;
124pub mod situations;
125pub mod sky;
126pub mod standings_types;
127pub mod stat_groups;
128pub mod stat_types;
129pub mod wind_direction;
130
131use crate::request::RequestURL;
132use derive_more::{Deref, DerefMut};
133use serde::de::{DeserializeOwned, Error, MapAccess, SeqAccess};
134use serde::{de, Deserialize, Deserializer};
135use std::fmt::{Debug, Display, Formatter};
136use std::marker::PhantomData;
137
138pub trait MetaKind {
139	type Complete: Debug + DeserializeOwned + Eq + Clone;
140
141	const ENDPOINT_NAME: &'static str;
142}
143
144#[derive(Debug, Deref, DerefMut, PartialEq, Eq, Clone)]
145pub struct MetaResponse<T: MetaKind> {
146	pub entries: Vec<<T as MetaKind>::Complete>,
147}
148
149impl<'de, T: MetaKind> Deserialize<'de> for MetaResponse<T> {
150	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
151	where
152		D: Deserializer<'de>,
153	{
154		struct Visitor<T: MetaKind>(PhantomData<T>);
155
156		impl<'de, T: MetaKind> de::Visitor<'de> for Visitor<T> {
157			type Value = MetaResponse<T>;
158
159			fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
160				formatter.write_str("either copyright and other entry, or just raw list")
161			}
162
163			fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
164			where
165				A: SeqAccess<'de>,
166			{
167				let mut entries = vec![];
168				while let Some(element) = seq.next_element::<<T as MetaKind>::Complete>()? {
169					entries.push(element);
170				}
171				Ok(MetaResponse { entries })
172			}
173
174			fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
175			where
176				A: MapAccess<'de>,
177			{
178				while let Some(key) = map.next_key::<String>()? {
179					if key != "copyright" {
180						let entries = map.next_value::<Vec<<T as MetaKind>::Complete>>()?;
181						return Ok(MetaResponse { entries });
182					}
183				}
184				Err(Error::custom("Could not find a field that deserializes to the entries"))
185			}
186		}
187
188		deserializer.deserialize_any(Visitor(PhantomData))
189	}
190}
191
192pub struct MetaRequest<T: MetaKind> {
193	_marker: PhantomData<T>,
194}
195
196impl<T: MetaKind> Default for MetaRequest<T> {
197	fn default() -> Self {
198		Self { _marker: PhantomData }
199	}
200}
201
202impl<T: MetaKind> MetaRequest<T> {
203	#[must_use]
204	pub const fn new() -> Self {
205		Self {
206			_marker: PhantomData
207		}
208	}
209}
210
211impl<T: MetaKind> Display for MetaRequest<T> {
212	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
213		write!(f, "http://statsapi.mlb.com/api/v1/{}", T::ENDPOINT_NAME)
214	}
215}
216
217impl<T: MetaKind> RequestURL for MetaRequest<T> {
218	type Response = MetaResponse<T>;
219}