1use std::cmp::Ordering;
2use std::fmt;
3use std::ops::{Add, Div, Mul, Sub};
4
5use ffi::*;
6use libc::c_int;
7
8#[derive(Copy, Clone)]
9pub struct Rational(pub i32, pub i32);
10
11impl Rational {
12 #[inline]
13 pub fn new(numerator: i32, denominator: i32) -> Self {
14 Rational(numerator, denominator)
15 }
16
17 #[inline]
18 pub fn numerator(&self) -> i32 {
19 self.0
20 }
21
22 #[inline]
23 pub fn denominator(&self) -> i32 {
24 self.1
25 }
26
27 #[inline]
28 pub fn reduce(&self) -> Rational {
29 match self.reduce_with_limit(i32::max_value()) {
30 Ok(r) => r,
31 Err(r) => r,
32 }
33 }
34
35 #[inline]
36 pub fn reduce_with_limit(&self, max: i32) -> Result<Rational, Rational> {
37 unsafe {
38 let mut dst_num: c_int = 0;
39 let mut dst_den: c_int = 0;
40
41 let exact = av_reduce(
42 &mut dst_num,
43 &mut dst_den,
44 i64::from(self.numerator()),
45 i64::from(self.denominator()),
46 i64::from(max),
47 );
48
49 if exact == 1 {
50 Ok(Rational(dst_num, dst_den))
51 } else {
52 Err(Rational(dst_num, dst_den))
53 }
54 }
55 }
56
57 #[inline]
58 pub fn invert(&self) -> Rational {
59 unsafe { Rational::from(av_inv_q((*self).into())) }
60 }
61}
62
63impl From<AVRational> for Rational {
64 #[inline]
65 fn from(value: AVRational) -> Rational {
66 Rational(value.num, value.den)
67 }
68}
69
70impl From<Rational> for AVRational {
71 #[inline]
72 fn from(value: Rational) -> AVRational {
73 AVRational {
74 num: value.0,
75 den: value.1,
76 }
77 }
78}
79
80impl From<f64> for Rational {
81 #[inline]
82 fn from(value: f64) -> Rational {
83 unsafe { Rational::from(av_d2q(value, c_int::max_value())) }
84 }
85}
86
87impl From<Rational> for f64 {
88 #[inline]
89 fn from(value: Rational) -> f64 {
90 unsafe { av_q2d(value.into()) }
91 }
92}
93
94impl From<Rational> for u32 {
95 #[inline]
96 fn from(value: Rational) -> u32 {
97 unsafe { av_q2intfloat(value.into()) }
98 }
99}
100
101impl From<(i32, i32)> for Rational {
102 fn from((num: i32, den: i32): (i32, i32)) -> Rational {
103 Rational::new(numerator:num, denominator:den)
104 }
105}
106
107impl PartialEq for Rational {
108 fn eq(&self, other: &Rational) -> bool {
109 if self.0 == other.0 && self.1 == other.1 {
110 return true;
111 }
112
113 let a: Rational = self.reduce();
114 let b: Rational = other.reduce();
115
116 if a.0 == b.0 && a.1 == b.1 {
117 return true;
118 }
119
120 false
121 }
122}
123
124impl Eq for Rational {}
125
126impl PartialOrd for Rational {
127 #[inline]
128 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
129 unsafe {
130 match av_cmp_q((*self).into(), (*other).into()) {
131 0 => Some(Ordering::Equal),
132 1 => Some(Ordering::Greater),
133 -1 => Some(Ordering::Less),
134
135 _ => None,
136 }
137 }
138 }
139}
140
141impl Add for Rational {
142 type Output = Rational;
143
144 #[inline]
145 fn add(self, other: Rational) -> Rational {
146 unsafe { Rational::from(av_add_q(self.into(), other.into())) }
147 }
148}
149
150impl Sub for Rational {
151 type Output = Rational;
152
153 #[inline]
154 fn sub(self, other: Rational) -> Rational {
155 unsafe { Rational::from(av_sub_q(self.into(), other.into())) }
156 }
157}
158
159impl Mul for Rational {
160 type Output = Rational;
161
162 #[inline]
163 fn mul(self, other: Rational) -> Rational {
164 unsafe { Rational::from(av_mul_q(self.into(), other.into())) }
165 }
166}
167
168impl Div for Rational {
169 type Output = Rational;
170
171 #[inline]
172 fn div(self, other: Rational) -> Rational {
173 unsafe { Rational::from(av_div_q(self.into(), other.into())) }
174 }
175}
176
177impl fmt::Display for Rational {
178 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
179 f.write_str(&format!("{}/{}", self.numerator(), self.denominator()))
180 }
181}
182
183impl fmt::Debug for Rational {
184 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
185 f.write_str(&format!(
186 "Rational({}/{})",
187 self.numerator(),
188 self.denominator()
189 ))
190 }
191}
192
193#[inline]
194pub fn nearer(q: Rational, q1: Rational, q2: Rational) -> Ordering {
195 unsafe {
196 match av_nearer_q(q.into(), q1.into(), q2.into()) {
197 1 => Ordering::Greater,
198 -1 => Ordering::Less,
199 _ => Ordering::Equal,
200 }
201 }
202}
203