Skip to main content

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}