scuffle_ffmpeg/
rational.rs1use std::num::NonZero;
2
3use rusty_ffmpeg::ffi::AVRational;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct Rational {
8 pub numerator: i32,
10 pub denominator: NonZero<i32>,
12}
13
14impl Default for Rational {
15 fn default() -> Self {
16 Self::ZERO
17 }
18}
19
20impl Rational {
21 pub const ZERO: Rational = Rational::static_new::<0, 1>();
23
24 pub const fn new(numerator: i32, denominator: NonZero<i32>) -> Self {
26 Self { numerator, denominator }
27 }
28
29 pub const fn static_new<const N: i32, const D: i32>() -> Self {
35 const {
36 assert!(D != 0, "denominator is 0");
37 }
38
39 Self::new(N, NonZero::new(D).expect("denominator is 0"))
40 }
41
42 pub fn as_f64(&self) -> f64 {
44 self.numerator as f64 / self.denominator.get() as f64
45 }
46
47 pub fn from_f64_rounded(value: f64) -> Self {
50 let denominator = value.abs().recip();
51 let numerator = (value * denominator).round() as i32;
52 Self {
53 numerator,
54 denominator: NonZero::new(denominator as i32).expect("denominator is 0"),
55 }
56 }
57}
58
59impl From<AVRational> for Rational {
60 fn from(rational: AVRational) -> Self {
61 if rational.den == 0 {
62 return Self::ZERO;
63 }
64
65 Self {
66 numerator: rational.num,
67 denominator: NonZero::new(rational.den).expect("denominator is 0"),
68 }
69 }
70}
71
72impl From<Rational> for AVRational {
73 fn from(rational: Rational) -> Self {
74 Self {
75 num: rational.numerator,
76 den: rational.denominator.get(),
77 }
78 }
79}
80
81impl From<i32> for Rational {
82 fn from(value: i32) -> Self {
83 Self {
84 numerator: value,
85 denominator: NonZero::new(1).expect("1 is not 0"),
86 }
87 }
88}
89
90impl From<Rational> for f32 {
91 fn from(rational: Rational) -> Self {
92 rational.numerator as f32 / rational.denominator.get() as f32
93 }
94}
95
96impl From<Rational> for f64 {
97 fn from(rational: Rational) -> Self {
98 rational.numerator as f64 / rational.denominator.get() as f64
99 }
100}