Skip to content

Commit

Permalink
refactor(fixed_point): Move from_ticks() and from_ticks() into th…
Browse files Browse the repository at this point in the history
…e `FixedPoint` trait
  • Loading branch information
PTaylor-us committed Aug 6, 2020
1 parent ab86978 commit adffe0d
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 129 deletions.
Binary file modified examples/nrf52_dk-bloat.txt
Binary file not shown.
23 changes: 13 additions & 10 deletions src/duration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ pub trait Duration: Sized + Copy {
.recip();

if size_of::<Self::T>() >= size_of::<Rate::T>() {
fixed_point::from_ticks(
fixed_point::FixedPoint::from_ticks(
Self::T::from(*conversion_factor.numerator())
.checked_div(
&self
Expand All @@ -403,7 +403,7 @@ pub trait Duration: Sized + Copy {
Rate::SCALING_FACTOR,
)
} else {
fixed_point::from_ticks(
fixed_point::FixedPoint::from_ticks(
Rate::T::from(*conversion_factor.numerator())
.checked_div(
&Rate::T::try_from(*self.integer())
Expand Down Expand Up @@ -557,7 +557,7 @@ pub mod units {
/// See [Converting from a `Generic`
/// `Duration`](trait.Duration.html#converting-from-a-generic-duration)
fn try_from(generic_duration: Generic<SourceInt>) -> Result<Self, Self::Error> {
fixed_point::from_ticks(
fixed_point::FixedPoint::from_ticks(
generic_duration.integer,
generic_duration.scaling_factor,
)
Expand Down Expand Up @@ -835,7 +835,10 @@ pub mod units {
/// See [Converting between
/// `Duration`s](trait.Duration.html#converting-between-durations)
fn try_from(source: $name<u64>) -> Result<Self, Self::Error> {
fixed_point::from_ticks(*source.integer(), $name::<u64>::SCALING_FACTOR)
fixed_point::FixedPoint::from_ticks(
*source.integer(),
$name::<u64>::SCALING_FACTOR,
)
}
}
};
Expand All @@ -855,15 +858,15 @@ pub mod units {
{
/// See [Converting between `Duration`s](trait.Duration.html#converting-between-durations)
fn from(small: $small<T>) -> Self {
fixed_point::from_ticks_safe(*small.integer(), $small::<T>::SCALING_FACTOR)
fixed_point::FixedPoint::from_ticks_safe(*small.integer(), $small::<T>::SCALING_FACTOR)
}
}

impl From<$small<u32>> for $big<u64>
{
/// See [Converting between `Duration`s](trait.Duration.html#converting-between-durations)
fn from(small: $small<u32>) -> Self {
fixed_point::from_ticks_safe(*small.integer(), $small::<u32>::SCALING_FACTOR)
fixed_point::FixedPoint::from_ticks_safe(*small.integer(), $small::<u32>::SCALING_FACTOR)
}
}

Expand All @@ -873,7 +876,7 @@ pub mod units {

/// See [Converting between `Duration`s](trait.Duration.html#converting-between-durations)
fn try_from(small: $small<u64>) -> Result<Self, Self::Error> {
fixed_point::from_ticks(
fixed_point::FixedPoint::from_ticks(
*small.integer(),
$small::<u64>::SCALING_FACTOR,
)
Expand Down Expand Up @@ -902,7 +905,7 @@ pub mod units {
{
/// See [Converting between `Duration`s](trait.Duration.html#converting-between-durations)
fn from(big: $big<u32>) -> Self {
fixed_point::from_ticks_safe(*big.integer(), $big::<u32>::SCALING_FACTOR)
fixed_point::FixedPoint::from_ticks_safe(*big.integer(), $big::<u32>::SCALING_FACTOR)
}
}

Expand All @@ -912,7 +915,7 @@ pub mod units {

/// See [Converting between `Duration`s](trait.Duration.html#converting-between-durations)
fn try_from(big: $big<T>) -> Result<Self, Self::Error> {
fixed_point::from_ticks(
fixed_point::FixedPoint::from_ticks(
*big.integer(),
$big::<T>::SCALING_FACTOR,
)
Expand All @@ -925,7 +928,7 @@ pub mod units {

/// See [Converting between `Duration`s](trait.Duration.html#converting-between-durations)
fn try_from(big: $big<u64>) -> Result<Self, Self::Error> {
fixed_point::from_ticks(
fixed_point::FixedPoint::from_ticks(
*big.integer(),
$big::<u64>::SCALING_FACTOR,
)
Expand Down
218 changes: 109 additions & 109 deletions src/fixed_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub trait FixedPoint: Sized + Copy {
#[doc(hidden)]
fn new(value: Self::T) -> Self;

/// Returns the integer value of the `FixedPoint`
/// Returns the integer part of the `FixedPoint` value
///
/// ```rust
/// # use embedded_time::{ rate::*};
Expand All @@ -29,6 +29,112 @@ pub trait FixedPoint: Sized + Copy {
/// ```
fn integer(&self) -> &Self::T;

/// Constructs a `FixedPoint` value from _integer_ and _scaling-factor_ ([`Fraction`]) parts
///
/// # Errors
///
/// Failure will only occur if the provided value does not fit in the selected destination type.
///
/// - [`ConversionError::Unspecified`]
/// - [`ConversionError::Overflow`]
/// - [`ConversionError::ConversionFailure`]
#[doc(hidden)]
fn from_ticks<SourceInt: TimeInt>(
ticks: SourceInt,
scaling_factor: Fraction,
) -> Result<Self, ConversionError>
where
Self::T: TryFrom<SourceInt>,
{
if size_of::<Self::T>() > size_of::<SourceInt>() {
// the dest integer is wider than the source, first promote the source integer to the
// dest type
let ticks = Self::T::try_from(ticks).map_err(|_| ConversionError::ConversionFailure)?;

let ticks = if scaling_factor > Fraction::new(1, 1) {
// In order to preserve precision, if the source scaling factor is > 1, the source's
// pure integer value can be calculated first followed by division by the
// dest scaling factor.
TimeInt::checked_div_fraction(
&TimeInt::checked_mul_fraction(&ticks, &scaling_factor)
.ok_or(ConversionError::Unspecified)?,
&Self::SCALING_FACTOR,
)
.ok_or(ConversionError::Unspecified)?
} else {
// If the source scaling factor is <= 1, the relative ratio of the scaling factors
// are calculated first by dividing the source scaling factor by
// that of the dest. The source integer part is then multiplied by
// the result.
TimeInt::checked_mul_fraction(
&ticks,
&scaling_factor
.checked_div(&Self::SCALING_FACTOR)
.ok_or(ConversionError::Unspecified)?,
)
.ok_or(ConversionError::Unspecified)?
};

Ok(Self::new(ticks))
} else {
let ticks = if scaling_factor > Fraction::new(1, 1) {
TimeInt::checked_div_fraction(
&TimeInt::checked_mul_fraction(&ticks, &scaling_factor)
.ok_or(ConversionError::Unspecified)?,
&Self::SCALING_FACTOR,
)
.ok_or(ConversionError::Unspecified)?
} else if Self::SCALING_FACTOR > Fraction::new(1, 1) {
TimeInt::checked_mul_fraction(
&TimeInt::checked_div_fraction(&ticks, &Self::SCALING_FACTOR)
.ok_or(ConversionError::Unspecified)?,
&scaling_factor,
)
.ok_or(ConversionError::Unspecified)?
} else {
TimeInt::checked_mul_fraction(
&ticks,
&scaling_factor
.checked_div(&Self::SCALING_FACTOR)
.ok_or(ConversionError::Unspecified)?,
)
.ok_or(ConversionError::Unspecified)?
};

let ticks = Self::T::try_from(ticks).map_err(|_| ConversionError::ConversionFailure)?;

Ok(Self::new(ticks))
}
}

/// Constructs a `FixedPoint` value from _integer_ and _scaling-factor_ ([`Fraction`]) parts
///
#[doc(hidden)]
fn from_ticks_safe<SourceInt: TimeInt>(ticks: SourceInt, scaling_factor: Fraction) -> Self
where
Self::T: From<SourceInt>,
Self::T: ops::Mul<Fraction, Output = Self::T> + ops::Div<Fraction, Output = Self::T>,
{
let ticks = Self::T::from(ticks);

let ticks = if (scaling_factor >= Fraction::new(1, 1)
&& Self::SCALING_FACTOR <= Fraction::new(1, 1))
|| (scaling_factor <= Fraction::new(1, 1)
&& Self::SCALING_FACTOR >= Fraction::new(1, 1))
{
// if the source's _scaling factor_ is > `1/1`, start by converting to a _scaling
// factor_ of `1/1`, then convert to destination _scaling factor_.
(ticks * scaling_factor) / Self::SCALING_FACTOR
} else {
// If the source scaling factor is <= 1, the relative ratio of the scaling factors are
// calculated first by dividing the source scaling factor by that of the
// dest. The source integer part is then multiplied by the result.
ticks * (scaling_factor / Self::SCALING_FACTOR)
};

Self::new(ticks)
}

/// Returns the _integer_ of the fixed-point value after converting to the _scaling factor_
/// provided
///
Expand Down Expand Up @@ -142,112 +248,6 @@ pub trait FixedPoint: Sized + Copy {
}
}

/// Constructs a `FixedPoint` from an integer and scaling-factor fraction
///
/// # Errors
///
/// Failure will only occur if the provided value does not fit in the selected destination type.
///
/// [`ConversionError::Overflow`] : The conversion of the _scaling factor_ causes an overflow.
/// [`ConversionError::ConversionFailure`] : The integer conversion to that of the destination
/// type fails.
// TODO: Move back into FixedPoint?
#[doc(hidden)]
pub(crate) fn from_ticks<SourceInt: TimeInt, Dest: FixedPoint>(
ticks: SourceInt,
scaling_factor: Fraction,
) -> Result<Dest, ConversionError>
where
Dest::T: TryFrom<SourceInt>,
{
if size_of::<Dest::T>() > size_of::<SourceInt>() {
// the dest integer is wider than the source, first promote the source integer to the dest
// type
let ticks = Dest::T::try_from(ticks).map_err(|_| ConversionError::ConversionFailure)?;

let ticks = if scaling_factor > Fraction::new(1, 1) {
// In order to preserve precision, if the source scaling factor is > 1, the source's
// pure integer value can be calculated first followed by division by the
// dest scaling factor.
TimeInt::checked_div_fraction(
&TimeInt::checked_mul_fraction(&ticks, &scaling_factor)
.ok_or(ConversionError::Unspecified)?,
&Dest::SCALING_FACTOR,
)
.ok_or(ConversionError::Unspecified)?
} else {
// If the source scaling factor is <= 1, the relative ratio of the scaling factors are
// calculated first by dividing the source scaling factor by that of the
// dest. The source integer part is then multiplied by the result.
TimeInt::checked_mul_fraction(
&ticks,
&scaling_factor
.checked_div(&Dest::SCALING_FACTOR)
.ok_or(ConversionError::Unspecified)?,
)
.ok_or(ConversionError::Unspecified)?
};

Ok(Dest::new(ticks))
} else {
let ticks = if scaling_factor > Fraction::new(1, 1) {
TimeInt::checked_div_fraction(
&TimeInt::checked_mul_fraction(&ticks, &scaling_factor)
.ok_or(ConversionError::Unspecified)?,
&Dest::SCALING_FACTOR,
)
.ok_or(ConversionError::Unspecified)?
} else if Dest::SCALING_FACTOR > Fraction::new(1, 1) {
TimeInt::checked_mul_fraction(
&TimeInt::checked_div_fraction(&ticks, &Dest::SCALING_FACTOR)
.ok_or(ConversionError::Unspecified)?,
&scaling_factor,
)
.ok_or(ConversionError::Unspecified)?
} else {
TimeInt::checked_mul_fraction(
&ticks,
&scaling_factor
.checked_div(&Dest::SCALING_FACTOR)
.ok_or(ConversionError::Unspecified)?,
)
.ok_or(ConversionError::Unspecified)?
};

let ticks = Dest::T::try_from(ticks).map_err(|_| ConversionError::ConversionFailure)?;

Ok(Dest::new(ticks))
}
}

#[doc(hidden)]
pub(crate) fn from_ticks_safe<SourceInt: TimeInt, Dest: FixedPoint>(
ticks: SourceInt,
scaling_factor: Fraction,
) -> Dest
where
Dest::T: From<SourceInt>,
Dest::T: ops::Mul<Fraction, Output = Dest::T> + ops::Div<Fraction, Output = Dest::T>,
{
let ticks = Dest::T::from(ticks);

let ticks = if (scaling_factor >= Fraction::new(1, 1)
&& Dest::SCALING_FACTOR <= Fraction::new(1, 1))
|| (scaling_factor <= Fraction::new(1, 1) && Dest::SCALING_FACTOR >= Fraction::new(1, 1))
{
// if the source's _scaling factor_ is > `1/1`, start by converting to a _scaling factor_
// of `1/1`, then convert to destination _scaling factor_.
(ticks * scaling_factor) / Dest::SCALING_FACTOR
} else {
// If the source scaling factor is <= 1, the relative ratio of the scaling factors are
// calculated first by dividing the source scaling factor by that of the
// dest. The source integer part is then multiplied by the result.
ticks * (scaling_factor / Dest::SCALING_FACTOR)
};

Dest::new(ticks)
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -257,11 +257,11 @@ mod tests {
#[test]
fn from_ticks() {
assert_eq!(
fixed_point::from_ticks(200_u32, Fraction::new(1, 1_000)),
fixed_point::FixedPoint::from_ticks(200_u32, Fraction::new(1, 1_000)),
Ok(Milliseconds(200_u64))
);
assert_eq!(
fixed_point::from_ticks(200_u32, Fraction::new(1_000, 1)),
fixed_point::FixedPoint::from_ticks(200_u32, Fraction::new(1_000, 1)),
Ok(Seconds(200_000_u64))
);
}
Expand Down
Loading

0 comments on commit adffe0d

Please sign in to comment.