Skip to main content

ferrex_model/
titles.rs

1use crate::error::ModelError as MediaError;
2
3/// Strongly typed movie title
4#[derive(Debug, Clone, PartialEq, Eq)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6#[cfg_attr(
7    feature = "rkyv",
8    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
9)]
10#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, PartialEq, Eq, Hash)))]
11pub struct MovieTitle(String);
12
13impl MovieTitle {
14    pub fn new(title: String) -> Result<Self, MediaError> {
15        if title.is_empty() {
16            return Err(MediaError::InvalidMedia(
17                "Movie title cannot be empty".to_string(),
18            ));
19        }
20        Ok(MovieTitle(title))
21    }
22
23    pub fn as_str(&self) -> &str {
24        &self.0
25    }
26}
27
28impl std::fmt::Display for MovieTitle {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        write!(f, "{}", self.0)
31    }
32}
33
34#[cfg(feature = "rkyv")]
35impl std::fmt::Display for ArchivedMovieTitle {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37        write!(f, "{}", self.0)
38    }
39}
40
41impl From<String> for MovieTitle {
42    fn from(s: String) -> Self {
43        MovieTitle(s)
44    }
45}
46
47impl From<&str> for MovieTitle {
48    fn from(s: &str) -> Self {
49        MovieTitle(s.to_string())
50    }
51}
52
53impl AsRef<str> for MovieTitle {
54    fn as_ref(&self) -> &str {
55        &self.0
56    }
57}
58
59#[cfg(feature = "rkyv")]
60impl AsRef<str> for ArchivedMovieTitle {
61    fn as_ref(&self) -> &str {
62        self.0.as_str()
63    }
64}
65
66impl std::hash::Hash for MovieTitle {
67    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
68        self.0.hash(state);
69    }
70}
71
72impl PartialOrd for MovieTitle {
73    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
74        Some(self.cmp(other))
75    }
76}
77
78impl Ord for MovieTitle {
79    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
80        self.0.cmp(&other.0)
81    }
82}
83
84/// Strongly typed series title
85#[derive(Debug, Clone, PartialEq, Eq)]
86#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
87#[cfg_attr(
88    feature = "rkyv",
89    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
90)]
91#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, PartialEq, Eq, Hash)))]
92pub struct SeriesTitle(String);
93
94impl SeriesTitle {
95    pub fn new(title: String) -> Result<Self, MediaError> {
96        if title.is_empty() {
97            return Err(MediaError::InvalidMedia(
98                "Series title cannot be empty".to_string(),
99            ));
100        }
101        Ok(SeriesTitle(title))
102    }
103
104    pub fn as_str(&self) -> &str {
105        &self.0
106    }
107}
108
109impl std::fmt::Display for SeriesTitle {
110    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111        write!(f, "{}", self.0)
112    }
113}
114#[cfg(feature = "rkyv")]
115impl std::fmt::Display for ArchivedSeriesTitle {
116    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117        write!(f, "{}", self.0)
118    }
119}
120
121impl From<String> for SeriesTitle {
122    fn from(s: String) -> Self {
123        SeriesTitle(s)
124    }
125}
126
127impl From<&str> for SeriesTitle {
128    fn from(s: &str) -> Self {
129        SeriesTitle(s.to_string())
130    }
131}
132
133impl AsRef<str> for SeriesTitle {
134    fn as_ref(&self) -> &str {
135        &self.0
136    }
137}
138#[cfg(feature = "rkyv")]
139impl AsRef<str> for ArchivedSeriesTitle {
140    fn as_ref(&self) -> &str {
141        self.0.as_str()
142    }
143}
144
145impl std::hash::Hash for SeriesTitle {
146    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
147        self.0.hash(state);
148    }
149}
150
151impl PartialOrd for SeriesTitle {
152    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
153        Some(self.cmp(other))
154    }
155}
156
157impl Ord for SeriesTitle {
158    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
159        self.0.cmp(&other.0)
160    }
161}
162
163/// Strongly typed episode title
164#[derive(Debug, Clone, PartialEq, Eq)]
165#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
166#[cfg_attr(
167    feature = "rkyv",
168    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
169)]
170#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, PartialEq, Eq, Hash)))]
171pub struct EpisodeTitle(String);
172
173impl EpisodeTitle {
174    pub fn new(title: String) -> Result<Self, MediaError> {
175        if title.is_empty() {
176            return Err(MediaError::InvalidMedia(
177                "Episode title cannot be empty".to_string(),
178            ));
179        }
180        Ok(EpisodeTitle(title))
181    }
182
183    pub fn as_str(&self) -> &str {
184        &self.0
185    }
186}
187
188impl std::fmt::Display for EpisodeTitle {
189    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
190        write!(f, "{}", self.0)
191    }
192}
193#[cfg(feature = "rkyv")]
194impl std::fmt::Display for ArchivedEpisodeTitle {
195    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
196        write!(f, "{}", self.0)
197    }
198}
199
200impl From<String> for EpisodeTitle {
201    fn from(s: String) -> Self {
202        EpisodeTitle(s)
203    }
204}
205
206impl From<&str> for EpisodeTitle {
207    fn from(s: &str) -> Self {
208        EpisodeTitle(s.to_string())
209    }
210}
211
212impl AsRef<str> for EpisodeTitle {
213    fn as_ref(&self) -> &str {
214        &self.0
215    }
216}
217#[cfg(feature = "rkyv")]
218impl AsRef<str> for ArchivedEpisodeTitle {
219    fn as_ref(&self) -> &str {
220        self.0.as_str()
221    }
222}
223
224impl std::hash::Hash for EpisodeTitle {
225    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
226        self.0.hash(state);
227    }
228}
229
230impl PartialOrd for EpisodeTitle {
231    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
232        Some(self.cmp(other))
233    }
234}
235
236impl Ord for EpisodeTitle {
237    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
238        self.0.cmp(&other.0)
239    }
240}