Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/v0.13.0 #114

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
524be16
Generic add/sub
korken89 May 23, 2021
1429b4e
Add/sub between 2 `Generics`
korken89 May 27, 2021
cfbb007
add support for defmt
newAM Aug 9, 2021
acd7891
Enforce minimum defmt v0.2.3
newAM Aug 13, 2021
5994105
skip defmt for non-embedded documentation tests
newAM Aug 15, 2021
3bac663
fix(CHANGELOG): typo
PTaylor-us Aug 28, 2021
c75c040
Merge pull request #90
PTaylor-us Aug 28, 2021
675e4ad
bump version
PTaylor-us Aug 28, 2021
2b4a66c
fix: update new PR with `integer()` return change
PTaylor-us Aug 28, 2021
103e876
fix: html_root_url version
PTaylor-us Aug 28, 2021
91c80c7
refactor(instant): remove unnecessary borrow
PTaylor-us Aug 28, 2021
d1657df
tests(duration): add Generic + Generic and Generic - Generic tests
PTaylor-us Aug 28, 2021
bbf1625
refactor(fraction): `numerator()` and `denominator()` return value ra…
PTaylor-us Aug 29, 2021
240a68b
refactor(duration, rate): bind FixedPoint to traits to simplify _gene…
PTaylor-us Aug 29, 2021
a1a8249
docs(fixed_point): expose Add/Sub impl docs
PTaylor-us Sep 12, 2021
03a99c4
Add scaling_factor method to FixedPoint
Sh3Rm4n Aug 20, 2021
927e0bf
docs(fixed_point): add short example to new `scaling_factor` method
PTaylor-us Sep 12, 2021
614f667
docs(changelog): add implemented changes/additions
PTaylor-us Sep 12, 2021
008ddfd
Merge branch 'release/v0.13.0' into defmt
PTaylor-us Sep 12, 2021
ee0c883
Merge pull request #110 from newAM/defmt
PTaylor-us Sep 12, 2021
3b270c9
Fraction: manual cmp & hash
burrbull Aug 15, 2021
c89639a
Merge pull request #111 from burrbull/fraction
PTaylor-us Oct 2, 2021
2ab2ec6
Fixed generic comparison where the destination integer is larger
korken89 Oct 8, 2021
e313ce9
Merge pull request #122 from korken89/fix-generic-extending-comparison
PTaylor-us Oct 16, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -49,7 +49,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
args: --doc --all-features
args: --doc --features serde

- name: Clippy
uses: actions-rs/cargo@v1
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -2,6 +2,12 @@

## [Unreleased]

- added optional support for [defmt](https://github.com/knurling-rs/defmt)
- add `scaling_factor` method to `FixedPoint` type to retrieve the const scaling-factor [`Fraction`] from any fixed-point object
- Duration and Rate are no longer implemented by the `Generic` duration and rate types
- durations and rates can now be taken generically by a function without having to bind to `FixedPoint` (`FixedPoint` is now bound to the `Duration` and `Rate` traits)
- `Fraction`s `numerator()` and `denominator()` getter methods now return a value instead of a reference

[unreleased]: https://github.com/FluenTech/embedded-time/compare/v0.12.0...HEAD

## [0.12.0] - 2021-05-30
@@ -13,7 +19,7 @@
### Changed

- limit Rate and Duration extension to u32
- removed all use os `unwrap()`
- removed all use of `unwrap()`

[0.12.0]: https://github.com/FluenTech/embedded-time/compare/v0.11.0...v0.12.0

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "embedded-time"
version = "0.12.0"
version = "0.13.0"
authors = ["Peter Taylor <PTaylor@FluenTech.info>"]
edition = "2018"
description = "Fully defined, inter-operable, ergonomic, and fast human-time units (both duration and rate types) with hardware timer abstraction and software timers."
@@ -26,6 +26,7 @@ members = ["examples"]
[dependencies]
num = { version = "0.3.0", default-features = false }
serde = { version = "1.0.0", default-features = false, features = ["derive"], optional = true }
defmt = { version = "0.2.3", optional = true }

[dev-dependencies]
crossbeam-utils = "0.7.2"
14 changes: 8 additions & 6 deletions src/clock.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
//! Abstraction for hardware timers/clocks

use crate::{
duration::Duration, fixed_point::FixedPoint, fraction::Fraction, instant::Instant,
time_int::TimeInt, timer::param, timer::Timer,
duration::Duration, fraction::Fraction, instant::Instant, time_int::TimeInt, timer::param,
timer::Timer,
};
use core::hash::Hash;

/// Potential `Clock` errors
#[non_exhaustive]
#[derive(Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
/// Exact cause of failure is unknown
Unspecified,
@@ -34,7 +35,11 @@ impl Default for Error {
/// software [`Timer`]s can be spawned from a `Clock` object.
pub trait Clock: Sized {
/// The type to hold the tick count
#[cfg(not(feature = "defmt"))]
type T: TimeInt + Hash;
/// The type to hold the tick count
#[cfg(feature = "defmt")]
type T: TimeInt + Hash + defmt::Format;

/// The duration of one clock tick in seconds, AKA the clock precision.
const SCALING_FACTOR: Fraction;
@@ -51,10 +56,7 @@ pub trait Clock: Sized {
fn new_timer<Dur: Duration>(
&self,
duration: Dur,
) -> Timer<param::OneShot, param::Armed, Self, Dur>
where
Dur: FixedPoint,
{
) -> Timer<param::OneShot, param::Armed, Self, Dur> {
Timer::<param::None, param::None, Self, Dur>::new(&self, duration)
}
}
161 changes: 146 additions & 15 deletions src/duration.rs
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ use core::{
convert::TryFrom,
hash::{Hash, Hasher},
mem::size_of,
ops,
prelude::v1::*,
};
#[doc(hidden)]
@@ -290,7 +291,7 @@ pub use units::*;
///
/// assert_eq!(Minutes(62_u32) % Hours(1_u32), Minutes(2_u32));
/// ```
pub trait Duration: Sized + Copy {
pub trait Duration: FixedPoint + Sized + Copy {
/// Construct a `Generic` `Duration` from a _named_ `Duration` (eg.
/// [`Milliseconds`])
///
@@ -340,7 +341,6 @@ pub trait Duration: Sized + Copy {
scaling_factor: Fraction,
) -> Result<Generic<DestInt>, ConversionError>
where
Self: FixedPoint,
DestInt: TryFrom<Self::T>,
{
Ok(Generic::<DestInt>::new(
@@ -395,8 +395,6 @@ pub trait Duration: Sized + Copy {
/// ```
fn to_rate<Rate: rate::Rate>(&self) -> Result<Rate, ConversionError>
where
Rate: FixedPoint,
Self: FixedPoint,
Rate::T: TryFrom<Self::T>,
{
let conversion_factor = Self::SCALING_FACTOR
@@ -406,23 +404,23 @@ pub trait Duration: Sized + Copy {

if size_of::<Self::T>() >= size_of::<Rate::T>() {
fixed_point::FixedPoint::from_ticks(
Self::T::from(*conversion_factor.numerator())
Self::T::from(conversion_factor.numerator())
.checked_div(
&self
.integer()
.checked_mul(&Self::T::from(*conversion_factor.denominator()))
.checked_mul(&Self::T::from(conversion_factor.denominator()))
.ok_or(ConversionError::Overflow)?,
)
.ok_or(ConversionError::DivByZero)?,
Rate::SCALING_FACTOR,
)
} else {
fixed_point::FixedPoint::from_ticks(
Rate::T::from(*conversion_factor.numerator())
Rate::T::from(conversion_factor.numerator())
.checked_div(
&Rate::T::try_from(self.integer())
.map_err(|_| ConversionError::Overflow)?
.checked_mul(&Rate::T::from(*conversion_factor.denominator()))
.checked_mul(&Rate::T::from(conversion_factor.denominator()))
.ok_or(ConversionError::Overflow)?,
)
.ok_or(ConversionError::DivByZero)?,
@@ -438,6 +436,7 @@ pub trait Duration: Sized + Copy {
/// The purpose of this type is to allow a simple `Duration` object that can be defined at run-time.
/// It does this by replacing the `const` _scaling factor_ with a struct field.
#[derive(Copy, Clone, Debug, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Generic<T> {
integer: T,
scaling_factor: Fraction,
@@ -501,7 +500,108 @@ impl<T: TimeInt> Generic<T> {
}
}

impl<T: TimeInt> Duration for Generic<T> {}
impl<T: TimeInt> Generic<T> {
pub(crate) fn into_ticks<T2>(self, fraction: Fraction) -> Result<T2, ConversionError>
where
T2: TimeInt,
T2: TryFrom<T>,
{
if size_of::<T2>() > size_of::<T>() {
let ticks =
T2::try_from(self.integer()).map_err(|_| ConversionError::ConversionFailure)?;

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

T2::try_from(ticks).map_err(|_| ConversionError::ConversionFailure)
}
}

/// Checked addition of two `Generic` durations.
pub fn checked_add_generic<T2: TimeInt>(mut self, duration: Generic<T2>) -> Option<Self>
where
T: TryFrom<T2>,
{
let add_ticks: T = duration.into_ticks(*self.scaling_factor()).ok()?;
self.integer = self.integer.checked_add(&add_ticks)?;

Some(self)
}

/// Checked subtraction of two `Generic` durations.
pub fn checked_sub_generic<T2: TimeInt>(mut self, duration: Generic<T2>) -> Option<Self>
where
T: TryFrom<T2>,
{
let sub_ticks: T = duration.into_ticks(*self.scaling_factor()).ok()?;
self.integer = self.integer.checked_sub(&sub_ticks)?;

Some(self)
}
}

impl<T: TimeInt, T2: TimeInt> ops::Add<Generic<T2>> for Generic<T>
where
T: TryFrom<T2>,
{
type Output = Self;

fn add(self, rhs: Generic<T2>) -> Self::Output {
if let Some(v) = self.checked_add_generic(rhs) {
v
} else {
panic!("Add failed")
}
}
}

impl<T: TimeInt, T2: TimeInt> ops::Sub<Generic<T2>> for Generic<T>
where
T: TryFrom<T2>,
{
type Output = Self;

fn sub(self, rhs: Generic<T2>) -> Self::Output {
if let Some(v) = self.checked_sub_generic(rhs) {
v
} else {
panic!("Sub failed")
}
}
}

/// Duration units
#[doc(hidden)]
@@ -560,9 +660,15 @@ pub mod units {
}
}

#[cfg(feature = "defmt")]
impl<T: TimeInt + defmt::Format> defmt::Format for $name<T> {
fn format(&self, fmt: defmt::Formatter) {
defmt::write!(fmt, "{}", self.0)
}
}

impl<T: TimeInt, Rhs: Duration> ops::Add<Rhs> for $name<T>
where
Rhs: FixedPoint,
Self: TryFrom<Rhs>,
{
type Output = Self;
@@ -576,7 +682,6 @@ pub mod units {
impl<T: TimeInt, Rhs: Duration> ops::Sub<Rhs> for $name<T>
where
Self: TryFrom<Rhs>,
Rhs: FixedPoint,
{
type Output = Self;

@@ -623,7 +728,6 @@ pub mod units {
impl<T: TimeInt, Rhs: Duration> ops::Rem<Rhs> for $name<T>
where
Self: TryFrom<Rhs>,
Rhs: FixedPoint,
{
type Output = Self;

@@ -650,11 +754,38 @@ pub mod units {
}
}

impl<T: TimeInt> From<$name<T>> for Generic<T> {
impl<T1, T2> From<$name<T1>> for Generic<T2>
where
T1: TimeInt,
T2: TimeInt + From<T1>,
{
/// See [Converting to a `Generic`
/// `Duration`](trait.Duration.html#converting-to-a-generic-duration)
fn from(duration: $name<T>) -> Self {
Self::new(duration.integer(), $name::<T>::SCALING_FACTOR)
fn from(duration: $name<T1>) -> Self {
Self::new(duration.integer().into(), $name::<T1>::SCALING_FACTOR)
}
}

impl<T1, T2> PartialEq<$name<T1>> for Generic<T2>
where
T1: TimeInt,
T2: TimeInt + From<T1>,
{
fn eq(&self, rhs: &$name<T1>) -> bool {
self.eq(rhs.into())
}
}

impl<T1, T2> PartialOrd<$name<T1>> for Generic<T2>
where
T1: TimeInt,
T2: TimeInt + From<T1>,
{
fn partial_cmp(&self, rhs: &$name<T1>) -> Option<core::cmp::Ordering> {
self.partial_cmp(&Self::new(
rhs.integer().into(),
$name::<T1>::SCALING_FACTOR,
))
}
}
};
13 changes: 11 additions & 2 deletions src/fixed_point.rs
Original file line number Diff line number Diff line change
@@ -29,6 +29,17 @@ pub trait FixedPoint: Sized + Copy {
/// ```
fn integer(&self) -> Self::T;

/// Returns the _scaling factor_ [`Fraction`] part
///
/// ```rust
/// # use embedded_time::{ rate::*};
/// #
/// assert_eq!(Kilohertz(45_u32).scaling_factor(), Fraction::new(1_000, 1));
/// ```
fn scaling_factor(&self) -> Fraction {
Self::SCALING_FACTOR
}

/// Constructs a `FixedPoint` value from _integer_ and _scaling-factor_ ([`Fraction`]) parts
///
/// # Errors
@@ -146,7 +157,6 @@ pub trait FixedPoint: Sized + Copy {
}

/// Panicky addition
#[doc(hidden)]
fn add<Rhs: FixedPoint>(self, rhs: Rhs) -> Self
where
Self: TryFrom<Rhs>,
@@ -160,7 +170,6 @@ pub trait FixedPoint: Sized + Copy {
}

/// Panicky subtraction
#[doc(hidden)]
fn sub<Rhs: FixedPoint>(self, rhs: Rhs) -> Self
where
Self: TryFrom<Rhs>,
Loading
Oops, something went wrong.