| 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) { |
| 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)) } |
| 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 | |