frame_rate/
lib.rs

1pub use num_rational::Ratio;
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3
4#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5pub enum FrameRate {
6  _24_00,
7  _25_00,
8  _30_00,
9  _50_00,
10  _60_00,
11  _120_00,
12  _23_97,
13  _24_97,
14  _29_97,
15  _59_94,
16  FrCustom(Ratio<u32>),
17}
18
19impl utoipa::ToSchema for FrameRate {
20  fn name() -> std::borrow::Cow<'static, str> {
21    std::borrow::Cow::Borrowed("FrameRate")
22  }
23}
24
25impl utoipa::PartialSchema for FrameRate {
26  fn schema() -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
27    utoipa::openapi::ObjectBuilder::new().into()
28  }
29}
30
31impl FrameRate {
32  pub fn new(num: u32, den: u32) -> Self {
33    Ratio::new(num, den).into()
34  }
35}
36
37impl From<&FrameRate> for f64 {
38  fn from(frame_rate: &FrameRate) -> Self {
39    let ratio: Ratio<u32> = (*frame_rate).into();
40    *ratio.numer() as f64 / *ratio.denom() as f64
41  }
42}
43
44impl From<FrameRate> for Ratio<u32> {
45  fn from(frame_rate: FrameRate) -> Self {
46    match frame_rate {
47      FrameRate::_24_00 => Self::from_integer(24),
48      FrameRate::_25_00 => Self::from_integer(25),
49      FrameRate::_30_00 => Self::from_integer(30),
50      FrameRate::_50_00 => Self::from_integer(50),
51      FrameRate::_60_00 => Self::from_integer(60),
52      FrameRate::_120_00 => Self::from_integer(120),
53      FrameRate::_23_97 => Self::new(24000, 1001),
54      FrameRate::_24_97 => Self::new(25000, 1001),
55      FrameRate::_29_97 => Self::new(30000, 1001),
56      FrameRate::_59_94 => Self::new(60000, 1001),
57      FrameRate::FrCustom(rational) => rational,
58    }
59  }
60}
61
62impl From<Ratio<u32>> for FrameRate {
63  fn from(rational: Ratio<u32>) -> Self {
64    match (rational.numer(), rational.denom()) {
65      (24, 1) => Self::_24_00,
66      (25, 1) => Self::_25_00,
67      (30, 1) => Self::_30_00,
68      (50, 1) => Self::_50_00,
69      (60, 1) => Self::_60_00,
70      (120, 1) => Self::_120_00,
71      (24000, 1001) => Self::_23_97,
72      (25000, 1001) => Self::_24_97,
73      (30000, 1001) => Self::_29_97,
74      (60000, 1001) => Self::_59_94,
75      _ => Self::FrCustom(rational),
76    }
77  }
78}
79
80#[derive(Serialize, Deserialize)]
81struct SerializeRational {
82  num: u32,
83  den: u32,
84}
85
86impl From<Ratio<u32>> for SerializeRational {
87  fn from(rational: Ratio<u32>) -> Self {
88    Self {
89      num: *rational.numer(),
90      den: *rational.denom(),
91    }
92  }
93}
94
95impl From<SerializeRational> for Ratio<u32> {
96  fn from(serialize_rational: SerializeRational) -> Self {
97    Self::new(serialize_rational.num, serialize_rational.den)
98  }
99}
100
101impl Serialize for FrameRate {
102  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
103  where
104    S: Serializer,
105  {
106    SerializeRational::from(Ratio::<u32>::from(*self)).serialize(serializer)
107  }
108}
109
110impl<'de> Deserialize<'de> for FrameRate {
111  fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
112  where
113    D: Deserializer<'de>,
114  {
115    Ok(Self::from(Ratio::<u32>::from(
116      SerializeRational::deserialize(deserializer)?,
117    )))
118  }
119}
120
121#[cfg(test)]
122mod tests {
123  use super::*;
124
125  #[test]
126  fn rational_from_frame_rate() {
127    assert_eq!(Ratio::from(FrameRate::_24_00), Ratio::from_integer(24));
128    assert_eq!(Ratio::from(FrameRate::_25_00), Ratio::from_integer(25));
129    assert_eq!(Ratio::from(FrameRate::_30_00), Ratio::from_integer(30));
130    assert_eq!(Ratio::from(FrameRate::_50_00), Ratio::from_integer(50));
131    assert_eq!(Ratio::from(FrameRate::_60_00), Ratio::from_integer(60));
132    assert_eq!(Ratio::from(FrameRate::_120_00), Ratio::from_integer(120));
133    assert_eq!(Ratio::from(FrameRate::_23_97), Ratio::new(24000, 1001));
134    assert_eq!(Ratio::from(FrameRate::_24_97), Ratio::new(25000, 1001));
135    assert_eq!(Ratio::from(FrameRate::_29_97), Ratio::new(30000, 1001));
136    assert_eq!(Ratio::from(FrameRate::_59_94), Ratio::new(60000, 1001));
137    let rational_2_3 = Ratio::new(2, 3);
138    let rational_6_9 = Ratio::new(6, 9);
139    assert_eq!(Ratio::from(FrameRate::FrCustom(rational_2_3)), rational_2_3);
140    assert_eq!(Ratio::from(FrameRate::FrCustom(rational_6_9)), rational_2_3);
141  }
142
143  #[test]
144  fn frame_rate_from_rational() {
145    assert_eq!(FrameRate::from(Ratio::from_integer(24)), FrameRate::_24_00);
146    assert_eq!(FrameRate::from(Ratio::from_integer(25)), FrameRate::_25_00);
147    assert_eq!(FrameRate::from(Ratio::from_integer(30)), FrameRate::_30_00);
148    assert_eq!(FrameRate::from(Ratio::from_integer(50)), FrameRate::_50_00);
149    assert_eq!(FrameRate::from(Ratio::from_integer(60)), FrameRate::_60_00);
150    assert_eq!(
151      FrameRate::from(Ratio::from_integer(120)),
152      FrameRate::_120_00
153    );
154    assert_eq!(FrameRate::from(Ratio::new(24000, 1001)), FrameRate::_23_97);
155    assert_eq!(FrameRate::from(Ratio::new(25000, 1001)), FrameRate::_24_97);
156    assert_eq!(FrameRate::from(Ratio::new(30000, 1001)), FrameRate::_29_97);
157    assert_eq!(FrameRate::from(Ratio::new(60000, 1001)), FrameRate::_59_94);
158    let rational_2_3 = Ratio::new(2, 3);
159    let rational_6_9 = Ratio::new(6, 9);
160    assert_eq!(
161      FrameRate::from(rational_2_3),
162      FrameRate::FrCustom(rational_2_3)
163    );
164    assert_eq!(
165      FrameRate::from(rational_2_3),
166      FrameRate::FrCustom(rational_6_9)
167    );
168    assert_eq!(FrameRate::from(Ratio::new(200, 4)), FrameRate::_50_00);
169  }
170
171  #[test]
172  fn serialize() {
173    assert_eq!(
174      serde_json::to_value(FrameRate::_24_00).unwrap(),
175      serde_json::json!({
176        "num": 24,
177        "den": 1
178      })
179    );
180    assert_eq!(
181      serde_json::to_value(FrameRate::_25_00).unwrap(),
182      serde_json::json!({
183        "num": 25,
184        "den": 1
185      })
186    );
187    assert_eq!(
188      serde_json::to_value(FrameRate::_30_00).unwrap(),
189      serde_json::json!({
190        "num": 30,
191        "den": 1
192      })
193    );
194    assert_eq!(
195      serde_json::to_value(FrameRate::_50_00).unwrap(),
196      serde_json::json!({
197        "num": 50,
198        "den": 1
199      })
200    );
201    assert_eq!(
202      serde_json::to_value(FrameRate::_60_00).unwrap(),
203      serde_json::json!({
204        "num": 60,
205        "den": 1
206      })
207    );
208    assert_eq!(
209      serde_json::to_value(FrameRate::_120_00).unwrap(),
210      serde_json::json!({
211        "num": 120,
212        "den": 1
213      })
214    );
215    assert_eq!(
216      serde_json::to_value(FrameRate::_23_97).unwrap(),
217      serde_json::json!({
218        "num": 24000,
219        "den": 1001
220      })
221    );
222    assert_eq!(
223      serde_json::to_value(FrameRate::_24_97).unwrap(),
224      serde_json::json!({
225        "num": 25000,
226        "den": 1001
227      })
228    );
229    assert_eq!(
230      serde_json::to_value(FrameRate::_29_97).unwrap(),
231      serde_json::json!({
232        "num": 30000,
233        "den": 1001
234      })
235    );
236    assert_eq!(
237      serde_json::to_value(FrameRate::_59_94).unwrap(),
238      serde_json::json!({
239        "num": 60000,
240        "den": 1001
241      })
242    );
243    assert_eq!(
244      serde_json::to_value(FrameRate::FrCustom(Ratio::new(2, 3))).unwrap(),
245      serde_json::json!({
246        "num": 2,
247        "den": 3
248      })
249    );
250    assert_eq!(
251      serde_json::to_value(FrameRate::FrCustom(Ratio::new(6, 9))).unwrap(),
252      serde_json::json!({
253        "num": 2,
254        "den": 3
255      })
256    );
257  }
258
259  #[test]
260  fn deserialize() {
261    assert_eq!(
262      serde_json::from_value::<FrameRate>(serde_json::json!({
263        "num": 24,
264        "den": 1
265      }))
266      .unwrap(),
267      FrameRate::_24_00
268    );
269    assert_eq!(
270      serde_json::from_value::<FrameRate>(serde_json::json!({
271        "num": 25,
272        "den": 1
273      }))
274      .unwrap(),
275      FrameRate::_25_00
276    );
277    assert_eq!(
278      serde_json::from_value::<FrameRate>(serde_json::json!({
279        "num": 30,
280        "den": 1
281      }))
282      .unwrap(),
283      FrameRate::_30_00
284    );
285    assert_eq!(
286      serde_json::from_value::<FrameRate>(serde_json::json!({
287        "num": 50,
288        "den": 1
289      }))
290      .unwrap(),
291      FrameRate::_50_00
292    );
293    assert_eq!(
294      serde_json::from_value::<FrameRate>(serde_json::json!({
295        "num": 60,
296        "den": 1
297      }))
298      .unwrap(),
299      FrameRate::_60_00
300    );
301    assert_eq!(
302      serde_json::from_value::<FrameRate>(serde_json::json!({
303        "num": 120,
304        "den": 1
305      }))
306      .unwrap(),
307      FrameRate::_120_00
308    );
309    assert_eq!(
310      serde_json::from_value::<FrameRate>(serde_json::json!({
311        "num": 24000,
312        "den": 1001
313      }))
314      .unwrap(),
315      FrameRate::_23_97
316    );
317    assert_eq!(
318      serde_json::from_value::<FrameRate>(serde_json::json!({
319        "num": 25000,
320        "den": 1001
321      }))
322      .unwrap(),
323      FrameRate::_24_97
324    );
325    assert_eq!(
326      serde_json::from_value::<FrameRate>(serde_json::json!({
327        "num": 30000,
328        "den": 1001
329      }))
330      .unwrap(),
331      FrameRate::_29_97
332    );
333    assert_eq!(
334      serde_json::from_value::<FrameRate>(serde_json::json!({
335        "num": 60000,
336        "den": 1001
337      }))
338      .unwrap(),
339      FrameRate::_59_94
340    );
341    assert_eq!(
342      serde_json::from_value::<FrameRate>(serde_json::json!({
343        "num": 2,
344        "den": 3
345      }))
346      .unwrap(),
347      FrameRate::FrCustom(Ratio::new(2, 3))
348    );
349    assert_eq!(
350      serde_json::from_value::<FrameRate>(serde_json::json!({
351        "num": 6,
352        "den": 9
353      }))
354      .unwrap(),
355      FrameRate::FrCustom(Ratio::new(2, 3))
356    );
357    assert_eq!(
358      serde_json::from_value::<FrameRate>(serde_json::json!({
359        "num": 200,
360        "den": 4
361      }))
362      .unwrap(),
363      FrameRate::_50_00
364    );
365  }
366}