1use crate::error::ModelError as MediaError;
2
3#[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#[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#[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}