mlb_api/requests/meta/
mod.rs1macro_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}