mlb_api/endpoints/meta/kinds/
positions.rs

1use crate::endpoints::meta::{MetaEndpointUrl, MetaKind};
2use derive_more::{Deref, DerefMut, Display, From};
3use serde::Deserialize;
4use std::ops::{Deref, DerefMut};
5use strum::EnumTryAs;
6use crate::cache::{EndpointEntryCache, HydratedCacheTable};
7use crate::{rwlock_const_new, RwLock};
8use crate::endpoints::StatsAPIUrl;
9
10#[derive(Debug, Deserialize, Deref, DerefMut, PartialEq, Eq, Clone)]
11#[serde(rename_all = "camelCase")]
12pub struct HydratedPosition {
13	pub short_name: String,
14	pub full_name: String,
15	pub formal_name: String,
16	#[serde(rename = "pitcher")]
17	pub is_pitcher: bool,
18	#[serde(rename = "gamePosition")]
19	pub is_game_position: bool,
20	#[serde(rename = "fielder")]
21	pub is_fielder: bool,
22	#[serde(rename = "outfield")]
23	pub is_outfield: bool,
24
25	#[deref]
26	#[deref_mut]
27	#[serde(flatten)]
28	inner: NamedPosition,
29}
30
31#[derive(Debug, Deserialize, PartialEq, Eq, Clone)]
32#[serde(rename_all = "camelCase")]
33pub struct NamedPosition {
34	pub code: PositionCode,
35	#[serde(alias = "displayName")]
36	pub name: String,
37	#[serde(rename = "type")]
38	pub r#type: String,
39	#[serde(alias = "abbrev")]
40	pub abbreviation: String,
41}
42
43#[repr(transparent)]
44#[derive(Debug, Deserialize, Deref, Display, PartialEq, Eq, Clone, Hash)]
45pub struct PositionCode(String);
46
47#[derive(Debug, Deserialize, Eq, Clone, From, EnumTryAs)]
48#[serde(untagged)]
49pub enum Position {
50	Hydrated(HydratedPosition),
51	Named(NamedPosition),
52}
53
54impl PartialEq for Position {
55	fn eq(&self, other: &Self) -> bool {
56		self.code == other.code
57	}
58}
59
60impl Deref for Position {
61	type Target = NamedPosition;
62
63	fn deref(&self) -> &Self::Target {
64		match self {
65			Self::Hydrated(inner) => inner,
66			Self::Named(inner) => inner,
67		}
68	}
69}
70
71impl DerefMut for Position {
72	fn deref_mut(&mut self) -> &mut Self::Target {
73		match self {
74			Self::Hydrated(inner) => inner,
75			Self::Named(inner) => inner,
76		}
77	}
78}
79
80impl MetaKind for Position {
81	const ENDPOINT_NAME: &'static str = "positions";
82}
83
84static CACHE: RwLock<HydratedCacheTable<Position>> = rwlock_const_new(HydratedCacheTable::new());
85
86impl EndpointEntryCache for Position {
87	type HydratedVariant = HydratedPosition;
88	type Identifier = PositionCode;
89	type URL = MetaEndpointUrl<Self>;
90
91	fn into_hydrated_variant(self) -> Option<Self::HydratedVariant> {
92		self.try_as_hydrated()
93	}
94
95	fn id(&self) -> &Self::Identifier {
96		&self.code
97	}
98
99	fn url_for_id(_id: &Self::Identifier) -> Self::URL {
100		MetaEndpointUrl::new()
101	}
102
103	fn get_entries(response: <Self::URL as StatsAPIUrl>::Response) -> impl IntoIterator<Item=Self>
104	where
105		Self: Sized
106	{
107		response.entries
108	}
109
110	fn get_hydrated_cache_table() -> &'static RwLock<HydratedCacheTable<Self>>
111	where
112		Self: Sized
113	{
114		&CACHE
115	}
116}
117
118#[cfg(test)]
119mod tests {
120	use crate::endpoints::StatsAPIUrl;
121	use crate::endpoints::meta::MetaEndpointUrl;
122
123	#[tokio::test]
124	async fn parse_meta() {
125		let _response = MetaEndpointUrl::<super::Position>::new().get().await.unwrap();
126	}
127}