rff_core/rational.rs
1//! Exact rational numbers, used for time bases and frame rates — exactly the
2//! role `AVRational` plays in FFmpeg. Storing time as a rational avoids the
3//! drift you get from representing e.g. 1/30000 as a float.
4
5use std::fmt;
6
7/// A rational number `num / den`.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub struct Rational {
10 pub num: i32,
11 pub den: i32,
12}
13
14impl Rational {
15 pub const ZERO: Rational = Rational { num: 0, den: 1 };
16
17 pub const fn new(num: i32, den: i32) -> Rational {
18 Rational { num, den }
19 }
20
21 /// Approximate value as `f64`. Returns `NAN` for a zero denominator rather
22 /// than panicking — callers building these from untrusted headers shouldn't
23 /// crash on bad input.
24 pub fn as_f64(self) -> f64 {
25 if self.den == 0 {
26 f64::NAN
27 } else {
28 self.num as f64 / self.den as f64
29 }
30 }
31
32 /// The reciprocal (`den / num`). Useful to flip a frame rate into a time base.
33 pub fn inverse(self) -> Rational {
34 Rational {
35 num: self.den,
36 den: self.num,
37 }
38 }
39}
40
41/// Defaults to `0/1` (not the derive's `0/0`, which would be a divide-by-zero
42/// trap waiting to happen).
43impl Default for Rational {
44 fn default() -> Self {
45 Rational::ZERO
46 }
47}
48
49impl fmt::Display for Rational {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 write!(f, "{}/{}", self.num, self.den)
52 }
53}