1 | use std::cmp::Ordering; |
2 | use std::fmt; |
3 | use std::ops::{Add, Div, Mul, Sub}; |
4 | |
5 | use ffi::*; |
6 | use libc::c_int; |
7 | |
8 | #[derive (Copy, Clone)] |
9 | pub struct Rational(pub i32, pub i32); |
10 | |
11 | impl 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 | |
63 | impl From<AVRational> for Rational { |
64 | #[inline ] |
65 | fn from(value: AVRational) -> Rational { |
66 | Rational(value.num, value.den) |
67 | } |
68 | } |
69 | |
70 | impl 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 | |
80 | impl 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 | |
87 | impl From<Rational> for f64 { |
88 | #[inline ] |
89 | fn from(value: Rational) -> f64 { |
90 | unsafe { av_q2d(value.into()) } |
91 | } |
92 | } |
93 | |
94 | impl From<Rational> for u32 { |
95 | #[inline ] |
96 | fn from(value: Rational) -> u32 { |
97 | unsafe { av_q2intfloat(value.into()) } |
98 | } |
99 | } |
100 | |
101 | impl 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 | |
107 | impl 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 | |
124 | impl Eq for Rational {} |
125 | |
126 | impl 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 | |
141 | impl 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 | |
150 | impl 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 | |
159 | impl 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 | |
168 | impl 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 | |
177 | impl 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 | |
183 | impl 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 ] |
194 | pub 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 | |