embedded_time/
fixed_point.rs1use crate::{fraction::Fraction, time_int::TimeInt, ConversionError};
3use core::{convert::TryFrom, mem::size_of, prelude::v1::*};
4use num::{Bounded, CheckedDiv, CheckedMul};
5
6pub trait FixedPoint: Sized + Copy {
10 type T: TimeInt;
12
13 const SCALING_FACTOR: Fraction;
15
16 #[doc(hidden)]
21 fn new(value: Self::T) -> Self;
22
23 fn integer(&self) -> Self::T;
31
32 #[doc(hidden)]
42 fn from_ticks<SourceInt: TimeInt>(
43 ticks: SourceInt,
44 scaling_factor: Fraction,
45 ) -> Result<Self, ConversionError>
46 where
47 Self::T: TryFrom<SourceInt>,
48 {
49 if size_of::<Self::T>() > size_of::<SourceInt>() {
50 let ticks = Self::T::try_from(ticks).map_err(|_| ConversionError::ConversionFailure)?;
53 let ticks =
54 Self::convert_ticks(ticks, scaling_factor).ok_or(ConversionError::Unspecified)?;
55 Ok(Self::new(ticks))
56 } else {
57 let ticks =
58 Self::convert_ticks(ticks, scaling_factor).ok_or(ConversionError::Unspecified)?;
59 let ticks = Self::T::try_from(ticks).map_err(|_| ConversionError::ConversionFailure)?;
60 Ok(Self::new(ticks))
61 }
62 }
63
64 #[doc(hidden)]
65 fn convert_ticks<T: TimeInt>(ticks: T, scaling_factor: Fraction) -> Option<T> {
66 if (scaling_factor >= Fraction::new(1, 1) && Self::SCALING_FACTOR <= Fraction::new(1, 1))
67 || (scaling_factor <= Fraction::new(1, 1)
68 && Self::SCALING_FACTOR >= Fraction::new(1, 1))
69 {
70 TimeInt::checked_div_fraction(
71 &TimeInt::checked_mul_fraction(&ticks, &scaling_factor)?,
72 &Self::SCALING_FACTOR,
73 )
74 } else {
75 TimeInt::checked_mul_fraction(
76 &ticks,
77 &scaling_factor.checked_div(&Self::SCALING_FACTOR)?,
78 )
79 }
80 }
81
82 #[doc(hidden)]
101 fn into_ticks<T: TimeInt>(self, fraction: Fraction) -> Result<T, ConversionError>
102 where
103 Self::T: TimeInt,
104 T: TryFrom<Self::T>,
105 {
106 if size_of::<T>() > size_of::<Self::T>() {
107 let ticks =
108 T::try_from(self.integer()).map_err(|_| ConversionError::ConversionFailure)?;
109
110 if fraction > Fraction::new(1, 1) {
111 TimeInt::checked_div_fraction(
112 &TimeInt::checked_mul_fraction(&ticks, &Self::SCALING_FACTOR)
113 .ok_or(ConversionError::Unspecified)?,
114 &fraction,
115 )
116 .ok_or(ConversionError::Unspecified)
117 } else {
118 TimeInt::checked_mul_fraction(
119 &ticks,
120 &Self::SCALING_FACTOR
121 .checked_div(&fraction)
122 .ok_or(ConversionError::Unspecified)?,
123 )
124 .ok_or(ConversionError::Unspecified)
125 }
126 } else {
127 let ticks = if Self::SCALING_FACTOR > Fraction::new(1, 1) {
128 TimeInt::checked_div_fraction(
129 &TimeInt::checked_mul_fraction(&self.integer(), &Self::SCALING_FACTOR)
130 .ok_or(ConversionError::Unspecified)?,
131 &fraction,
132 )
133 .ok_or(ConversionError::Unspecified)?
134 } else {
135 TimeInt::checked_mul_fraction(
136 &self.integer(),
137 &Self::SCALING_FACTOR
138 .checked_div(&fraction)
139 .ok_or(ConversionError::Unspecified)?,
140 )
141 .ok_or(ConversionError::Unspecified)?
142 };
143
144 T::try_from(ticks).map_err(|_| ConversionError::ConversionFailure)
145 }
146 }
147
148 #[doc(hidden)]
150 fn add<Rhs: FixedPoint>(self, rhs: Rhs) -> Self
151 where
152 Self: TryFrom<Rhs>,
153 {
154 let v = if let Ok(v) = Self::try_from(rhs) {
155 v
156 } else {
157 panic!("Add failed")
158 };
159 Self::new(self.integer() + v.integer())
160 }
161
162 #[doc(hidden)]
164 fn sub<Rhs: FixedPoint>(self, rhs: Rhs) -> Self
165 where
166 Self: TryFrom<Rhs>,
167 {
168 let v = if let Ok(v) = Self::try_from(rhs) {
169 v
170 } else {
171 panic!("Sub failed")
172 };
173
174 Self::new(self.integer() - v.integer())
175 }
176
177 #[doc(hidden)]
179 fn mul(self, rhs: Self::T) -> Self {
180 Self::new(self.integer() * rhs)
181 }
182
183 fn checked_mul(&self, rhs: &Self::T) -> Option<Self> {
185 Some(Self::new((self.integer()).checked_mul(rhs)?))
186 }
187
188 #[doc(hidden)]
190 fn div(self, rhs: Self::T) -> Self {
191 Self::new(self.integer() / rhs)
192 }
193
194 fn checked_div(&self, rhs: &Self::T) -> Option<Self> {
196 Some(Self::new((self.integer()).checked_div(rhs)?))
197 }
198
199 #[doc(hidden)]
201 fn rem<Rhs: FixedPoint>(self, rhs: Rhs) -> Self
202 where
203 Self: TryFrom<Rhs>,
204 {
205 match Self::try_from(rhs) {
206 Ok(rhs) => {
207 if rhs.integer() > Self::T::from(0) {
208 Self::new(self.integer() % rhs.integer())
209 } else {
210 Self::new(Self::T::from(0))
211 }
212 }
213 Err(_) => self,
214 }
215 }
216
217 fn min_value() -> Self::T {
219 Self::T::min_value()
220 }
221
222 fn max_value() -> Self::T {
224 Self::T::max_value()
225 }
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231 use crate::duration::*;
232 use crate::fixed_point;
233
234 #[test]
235 fn from_ticks() {
236 assert_eq!(
237 fixed_point::FixedPoint::from_ticks(200_u32, Fraction::new(1, 1_000)),
238 Ok(Milliseconds(200_u64))
239 );
240 assert_eq!(
241 fixed_point::FixedPoint::from_ticks(200_u32, Fraction::new(1_000, 1)),
242 Ok(Seconds(200_000_u64))
243 );
244 }
245}