mlb_api/endpoints/meta/kinds/
languages.rs

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