mirror of
https://github.com/rust-embedded/embedded-hal.git
synced 2026-03-19 05:40:32 +00:00
Merge #127
127: Digital v1 <-> v2 compatibility wrappers and shims r=japaric a=ryankurte This PR introduces implicit v1 -> v2 (forward) compatibility, and explicit wrapper types for v2 -> v1 (reverse) compatibility between digital trait versions as a final step for #95, as well as moving the deprecated v1 traits to a re-exported module for clarity. As @japaric pointed out, it is not feasible to have implicit compatibility in both directions, so it seemed reasonable to make regression explicit as it hides an `.unwrap()` on failure. @therealprof, @hannobraun, @eldruin what do you think of this approach? I think it probably needs more documentation, though I am definitely open to suggestions as to what / where. See also: #100, #92, #102. Co-authored-by: Ryan Kurte <ryankurte@gmail.com> Co-authored-by: Diego Barrios Romero <eldruin@gmail.com> Co-authored-by: Daniel Egger <daniel@eggers-club.de>
This commit is contained in:
@@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
fallible and their methods now return a `Result` type as setting an output pin
|
||||
and reading an input pin could potentially fail.
|
||||
See [here](https://github.com/rust-embedded/embedded-hal/issues/95) for more info.
|
||||
- Compatibility shims between `digital::v1` and `digital::v2` traits allowing v1 traits
|
||||
to be implicitly promoted to v2, and for v2 traits to be explicitly cast to v1 wrappers.
|
||||
|
||||
### Changed
|
||||
- The current versions of the `OutputPin`, `StatefulOutputPin`, `ToggleableOutputPin`
|
||||
|
||||
@@ -1,155 +1,25 @@
|
||||
//! Digital I/O
|
||||
//!
|
||||
//! The traits in this module are now deprecated. Please use the new versions included
|
||||
//! in `digital::v2`.
|
||||
//!
|
||||
//!
|
||||
|
||||
/// Single digital push-pull output pin
|
||||
///
|
||||
/// *This version of the trait is now deprecated. Please use the new `OutputPin` trait in
|
||||
/// `digital::v2::OutputPin`*.
|
||||
// Deprecated / infallible traits
|
||||
#[deprecated(since = "0.2.2", note = "Deprecated because the methods cannot return errors. \
|
||||
Users should use the traits in digital::v2.")]
|
||||
pub trait OutputPin {
|
||||
/// Drives the pin low
|
||||
///
|
||||
/// *NOTE* the actual electrical state of the pin may not actually be low, e.g. due to external
|
||||
/// electrical sources
|
||||
fn set_low(&mut self);
|
||||
pub mod v1;
|
||||
|
||||
/// Drives the pin high
|
||||
///
|
||||
/// *NOTE* the actual electrical state of the pin may not actually be high, e.g. due to external
|
||||
/// electrical sources
|
||||
fn set_high(&mut self);
|
||||
}
|
||||
|
||||
/// Push-pull output pin that can read its output state
|
||||
///
|
||||
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
|
||||
///
|
||||
/// *This version of the trait is now deprecated. Please use the new `StatefulOutputPin` trait in
|
||||
/// `digital::v2::StatefulOutputPin`*.
|
||||
#[deprecated(since = "0.2.2", note = "Deprecated because the methods cannot return errors. \
|
||||
Users should use the traits in digital::v2.")]
|
||||
#[cfg(feature = "unproven")]
|
||||
pub trait StatefulOutputPin {
|
||||
/// Is the pin in drive high mode?
|
||||
///
|
||||
/// *NOTE* this does *not* read the electrical state of the pin
|
||||
fn is_set_high(&self) -> bool;
|
||||
|
||||
/// Is the pin in drive low mode?
|
||||
///
|
||||
/// *NOTE* this does *not* read the electrical state of the pin
|
||||
fn is_set_low(&self) -> bool;
|
||||
}
|
||||
|
||||
/// Output pin that can be toggled
|
||||
///
|
||||
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
|
||||
///
|
||||
/// *This version of the trait is now deprecated. Please use the new `ToggleableOutputPin`
|
||||
/// trait in `digital::v2::ToggleableOutputPin`*.
|
||||
///
|
||||
/// See [toggleable](toggleable) to use a software implementation if
|
||||
/// both [OutputPin](trait.OutputPin.html) and
|
||||
/// [StatefulOutputPin](trait.StatefulOutputPin.html) are
|
||||
/// implemented. Otherwise, implement this using hardware mechanisms.
|
||||
#[deprecated(since = "0.2.2", note = "Deprecated because the methods cannot return errors. \
|
||||
Users should use the traits in digital::v2.")]
|
||||
#[cfg(feature = "unproven")]
|
||||
pub trait ToggleableOutputPin {
|
||||
/// Toggle pin output.
|
||||
fn toggle(&mut self);
|
||||
}
|
||||
|
||||
/// If you can read **and** write the output state, a pin is
|
||||
/// toggleable by software.
|
||||
///
|
||||
/// *This version of the module is now deprecated. Please use the new `toggleable` module in
|
||||
/// `digital::v2::toggleable`*.
|
||||
///
|
||||
/// ```
|
||||
/// use embedded_hal::digital::{OutputPin, StatefulOutputPin, ToggleableOutputPin};
|
||||
/// use embedded_hal::digital::toggleable;
|
||||
///
|
||||
/// /// A virtual output pin that exists purely in software
|
||||
/// struct MyPin {
|
||||
/// state: bool
|
||||
/// }
|
||||
///
|
||||
/// impl OutputPin for MyPin {
|
||||
/// fn set_low(&mut self) {
|
||||
/// self.state = false;
|
||||
/// }
|
||||
/// fn set_high(&mut self) {
|
||||
/// self.state = true;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl StatefulOutputPin for MyPin {
|
||||
/// fn is_set_low(&self) -> bool {
|
||||
/// !self.state
|
||||
/// }
|
||||
/// fn is_set_high(&self) -> bool {
|
||||
/// self.state
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// /// Opt-in to the software implementation.
|
||||
/// impl toggleable::Default for MyPin {}
|
||||
///
|
||||
/// let mut pin = MyPin { state: false };
|
||||
/// pin.toggle();
|
||||
/// assert!(pin.is_set_high());
|
||||
/// pin.toggle();
|
||||
/// assert!(pin.is_set_low());
|
||||
/// ```
|
||||
#[deprecated(since = "0.2.2", note = "Deprecated because the methods cannot return errors. \
|
||||
Users should use the traits in digital::v2.")]
|
||||
#[cfg(feature = "unproven")]
|
||||
pub mod toggleable {
|
||||
#[allow(deprecated)]
|
||||
use super::{OutputPin, StatefulOutputPin, ToggleableOutputPin};
|
||||
|
||||
/// Software-driven `toggle()` implementation.
|
||||
///
|
||||
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
|
||||
#[allow(deprecated)]
|
||||
pub trait Default: OutputPin + StatefulOutputPin {}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<P> ToggleableOutputPin for P
|
||||
where
|
||||
P: Default,
|
||||
{
|
||||
/// Toggle pin output
|
||||
fn toggle(&mut self) {
|
||||
if self.is_set_low() {
|
||||
self.set_high();
|
||||
} else {
|
||||
self.set_low();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Single digital input pin
|
||||
///
|
||||
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
|
||||
///
|
||||
/// *This version of the trait is now deprecated. Please use the new `InputPin` trait in
|
||||
/// `digital::v2::InputPin`*.
|
||||
#[deprecated(since = "0.2.2", note = "Deprecated because the methods cannot return errors. \
|
||||
Users should use the traits in digital::v2.")]
|
||||
#[cfg(feature = "unproven")]
|
||||
pub trait InputPin {
|
||||
/// Is the input pin high?
|
||||
fn is_high(&self) -> bool;
|
||||
|
||||
/// Is the input pin low?
|
||||
fn is_low(&self) -> bool;
|
||||
}
|
||||
|
||||
/// Improved version of the digital traits where the methods can also return an error.
|
||||
// New / fallible traits
|
||||
pub mod v2;
|
||||
|
||||
// v2 -> v1 compatibility wrappers
|
||||
// These require explicit casts from v2 -> v1
|
||||
pub mod v1_compat;
|
||||
|
||||
// v1 -> v2 compatibility shims
|
||||
// These are implicit over v1 implementations
|
||||
pub mod v2_compat;
|
||||
|
||||
// Re-export old traits so this isn't a breaking change
|
||||
#[allow(deprecated)]
|
||||
pub use self::v1::*;
|
||||
|
||||
|
||||
145
src/digital/v1.rs
Normal file
145
src/digital/v1.rs
Normal file
@@ -0,0 +1,145 @@
|
||||
//! Digital I/O
|
||||
//!
|
||||
//! The traits in this module are now deprecated. Please use the new versions included
|
||||
//! in `digital::v2`.
|
||||
|
||||
#![allow(deprecated)]
|
||||
|
||||
/// Single digital push-pull output pin
|
||||
///
|
||||
/// *This version of the trait is now deprecated. Please use the new `OutputPin` trait in
|
||||
/// `digital::v2::OutputPin`*.
|
||||
|
||||
pub trait OutputPin {
|
||||
/// Drives the pin low
|
||||
///
|
||||
/// *NOTE* the actual electrical state of the pin may not actually be low, e.g. due to external
|
||||
/// electrical sources
|
||||
fn set_low(&mut self);
|
||||
|
||||
/// Drives the pin high
|
||||
///
|
||||
/// *NOTE* the actual electrical state of the pin may not actually be high, e.g. due to external
|
||||
/// electrical sources
|
||||
fn set_high(&mut self);
|
||||
}
|
||||
|
||||
/// Push-pull output pin that can read its output state
|
||||
///
|
||||
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
|
||||
///
|
||||
/// *This version of the trait is now deprecated. Please use the new `StatefulOutputPin` trait in
|
||||
/// `digital::v2::StatefulOutputPin`*.
|
||||
#[cfg(feature = "unproven")]
|
||||
pub trait StatefulOutputPin {
|
||||
/// Is the pin in drive high mode?
|
||||
///
|
||||
/// *NOTE* this does *not* read the electrical state of the pin
|
||||
fn is_set_high(&self) -> bool;
|
||||
|
||||
/// Is the pin in drive low mode?
|
||||
///
|
||||
/// *NOTE* this does *not* read the electrical state of the pin
|
||||
fn is_set_low(&self) -> bool;
|
||||
}
|
||||
|
||||
/// Output pin that can be toggled
|
||||
///
|
||||
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
|
||||
///
|
||||
/// *This version of the trait is now deprecated. Please use the new `ToggleableOutputPin`
|
||||
/// trait in `digital::v2::ToggleableOutputPin`*.
|
||||
///
|
||||
/// See [toggleable](toggleable) to use a software implementation if
|
||||
/// both [OutputPin](trait.OutputPin.html) and
|
||||
/// [StatefulOutputPin](trait.StatefulOutputPin.html) are
|
||||
/// implemented. Otherwise, implement this using hardware mechanisms.
|
||||
#[cfg(feature = "unproven")]
|
||||
pub trait ToggleableOutputPin {
|
||||
/// Toggle pin output.
|
||||
fn toggle(&mut self);
|
||||
}
|
||||
|
||||
/// If you can read **and** write the output state, a pin is
|
||||
/// toggleable by software.
|
||||
///
|
||||
/// *This version of the module is now deprecated. Please use the new `toggleable` module in
|
||||
/// `digital::v2::toggleable`*.
|
||||
///
|
||||
/// ```
|
||||
/// use embedded_hal::digital::{OutputPin, StatefulOutputPin, ToggleableOutputPin};
|
||||
/// use embedded_hal::digital::toggleable;
|
||||
///
|
||||
/// /// A virtual output pin that exists purely in software
|
||||
/// struct MyPin {
|
||||
/// state: bool
|
||||
/// }
|
||||
///
|
||||
/// impl OutputPin for MyPin {
|
||||
/// fn set_low(&mut self) {
|
||||
/// self.state = false;
|
||||
/// }
|
||||
/// fn set_high(&mut self) {
|
||||
/// self.state = true;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl StatefulOutputPin for MyPin {
|
||||
/// fn is_set_low(&self) -> bool {
|
||||
/// !self.state
|
||||
/// }
|
||||
/// fn is_set_high(&self) -> bool {
|
||||
/// self.state
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// /// Opt-in to the software implementation.
|
||||
/// impl toggleable::Default for MyPin {}
|
||||
///
|
||||
/// let mut pin = MyPin { state: false };
|
||||
/// pin.toggle();
|
||||
/// assert!(pin.is_set_high());
|
||||
/// pin.toggle();
|
||||
/// assert!(pin.is_set_low());
|
||||
/// ```
|
||||
#[cfg(feature = "unproven")]
|
||||
pub mod toggleable {
|
||||
#[allow(deprecated)]
|
||||
use super::{OutputPin, StatefulOutputPin, ToggleableOutputPin};
|
||||
|
||||
/// Software-driven `toggle()` implementation.
|
||||
///
|
||||
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
|
||||
#[allow(deprecated)]
|
||||
pub trait Default: OutputPin + StatefulOutputPin {}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<P> ToggleableOutputPin for P
|
||||
where
|
||||
P: Default,
|
||||
{
|
||||
/// Toggle pin output
|
||||
fn toggle(&mut self) {
|
||||
if self.is_set_low() {
|
||||
self.set_high();
|
||||
} else {
|
||||
self.set_low();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Single digital input pin
|
||||
///
|
||||
/// *This trait is available if embedded-hal is built with the `"unproven"` feature.*
|
||||
///
|
||||
/// *This version of the trait is now deprecated. Please use the new `InputPin` trait in
|
||||
/// `digital::v2::InputPin`*.
|
||||
#[cfg(feature = "unproven")]
|
||||
pub trait InputPin {
|
||||
/// Is the input pin high?
|
||||
fn is_high(&self) -> bool;
|
||||
|
||||
/// Is the input pin low?
|
||||
fn is_low(&self) -> bool;
|
||||
}
|
||||
256
src/digital/v1_compat.rs
Normal file
256
src/digital/v1_compat.rs
Normal file
@@ -0,0 +1,256 @@
|
||||
//! v1 compatibility wrapper
|
||||
//! this module adds reverse support for v2 digital traits
|
||||
//! v2 traits must be explicitly cast to the v1 version using `.into()`,
|
||||
//! and will panic on internal errors
|
||||
|
||||
#[allow(deprecated)]
|
||||
use super::v1;
|
||||
use super::v2;
|
||||
|
||||
/// Wrapper to allow fallible `v2::OutputPin` traits to be converted to `v1::OutputPin` traits
|
||||
pub struct OldOutputPin<T> {
|
||||
pin: T,
|
||||
}
|
||||
|
||||
impl <T, E> OldOutputPin<T>
|
||||
where
|
||||
T: v2::OutputPin<Error=E>,
|
||||
E: core::fmt::Debug,
|
||||
{
|
||||
/// Create a new OldOutputPin wrapper around a `v2::OutputPin`
|
||||
pub fn new(pin: T) -> Self {
|
||||
Self{pin}
|
||||
}
|
||||
|
||||
/// Fetch a reference to the inner `v2::OutputPin` impl
|
||||
#[cfg(test)]
|
||||
fn inner(&self) -> &T {
|
||||
&self.pin
|
||||
}
|
||||
}
|
||||
|
||||
impl <T, E> From<T> for OldOutputPin<T>
|
||||
where
|
||||
T: v2::OutputPin<Error=E>,
|
||||
E: core::fmt::Debug,
|
||||
{
|
||||
fn from(pin: T) -> Self {
|
||||
OldOutputPin{pin}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of `v1::OutputPin` trait for fallible `v2::OutputPin` output pins
|
||||
/// where errors will panic.
|
||||
#[allow(deprecated)]
|
||||
impl <T, E> v1::OutputPin for OldOutputPin<T>
|
||||
where
|
||||
T: v2::OutputPin<Error=E>,
|
||||
E: core::fmt::Debug,
|
||||
{
|
||||
fn set_low(&mut self) {
|
||||
self.pin.set_low().unwrap()
|
||||
}
|
||||
|
||||
fn set_high(&mut self) {
|
||||
self.pin.set_high().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of `v1::StatefulOutputPin` trait for `v2::StatefulOutputPin` fallible pins
|
||||
/// where errors will panic.
|
||||
#[cfg(feature = "unproven")]
|
||||
#[allow(deprecated)]
|
||||
impl <T, E> v1::StatefulOutputPin for OldOutputPin<T>
|
||||
where
|
||||
T: v2::StatefulOutputPin<Error=E>,
|
||||
E: core::fmt::Debug,
|
||||
{
|
||||
fn is_set_low(&self) -> bool {
|
||||
self.pin.is_set_low().unwrap()
|
||||
}
|
||||
|
||||
fn is_set_high(&self) -> bool {
|
||||
self.pin.is_set_high().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper to allow fallible `v2::InputPin` traits to be converted to `v1::InputPin` traits
|
||||
/// where errors will panic.
|
||||
#[cfg(feature = "unproven")]
|
||||
pub struct OldInputPin<T> {
|
||||
pin: T,
|
||||
}
|
||||
|
||||
#[cfg(feature = "unproven")]
|
||||
impl <T, E> OldInputPin<T>
|
||||
where
|
||||
T: v2::OutputPin<Error=E>,
|
||||
E: core::fmt::Debug,
|
||||
{
|
||||
/// Create an `OldInputPin` wrapper around a `v2::InputPin`.
|
||||
pub fn new(pin: T) -> Self {
|
||||
Self{pin}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(feature = "unproven")]
|
||||
impl <T, E> From<T> for OldInputPin<T>
|
||||
where
|
||||
T: v2::InputPin<Error=E>,
|
||||
E: core::fmt::Debug,
|
||||
{
|
||||
fn from(pin: T) -> Self {
|
||||
OldInputPin{pin}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of `v1::InputPin` trait for `v2::InputPin` fallible pins
|
||||
/// where errors will panic.
|
||||
#[cfg(feature = "unproven")]
|
||||
#[allow(deprecated)]
|
||||
impl <T, E> v1::InputPin for OldInputPin<T>
|
||||
where
|
||||
T: v2::InputPin<Error=E>,
|
||||
E: core::fmt::Debug,
|
||||
{
|
||||
fn is_low(&self) -> bool {
|
||||
self.pin.is_low().unwrap()
|
||||
}
|
||||
|
||||
fn is_high(&self) -> bool {
|
||||
self.pin.is_high().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(deprecated)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[allow(deprecated)]
|
||||
use crate::digital::v1;
|
||||
use crate::digital::v2;
|
||||
|
||||
use crate::digital::v1::OutputPin;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct NewOutputPinImpl {
|
||||
state: bool,
|
||||
res: Result<(), ()>
|
||||
}
|
||||
|
||||
impl v2::OutputPin for NewOutputPinImpl {
|
||||
type Error = ();
|
||||
|
||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||
self.state = false;
|
||||
self.res
|
||||
}
|
||||
fn set_high(&mut self) -> Result<(), Self::Error>{
|
||||
self.state = true;
|
||||
self.res
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
struct OldOutputPinConsumer<T: v1::OutputPin> {
|
||||
_pin: T,
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl <T>OldOutputPinConsumer<T>
|
||||
where T: v1::OutputPin
|
||||
{
|
||||
pub fn new(pin: T) -> OldOutputPinConsumer<T> {
|
||||
OldOutputPinConsumer{ _pin: pin }
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v1_v2_output_explicit() {
|
||||
let i = NewOutputPinImpl{state: false, res: Ok(())};
|
||||
let _c: OldOutputPinConsumer<OldOutputPin<_>> = OldOutputPinConsumer::new(i.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v1_v2_output_state() {
|
||||
let mut o: OldOutputPin<_> = NewOutputPinImpl{state: false, res: Ok(())}.into();
|
||||
|
||||
o.set_high();
|
||||
assert_eq!(o.inner().state, true);
|
||||
|
||||
o.set_low();
|
||||
assert_eq!(o.inner().state, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn v1_v2_output_panic() {
|
||||
let mut o: OldOutputPin<_> = NewOutputPinImpl{state: false, res: Err(())}.into();
|
||||
|
||||
o.set_high();
|
||||
}
|
||||
|
||||
#[cfg(feature = "unproven")]
|
||||
use crate::digital::v1::InputPin;
|
||||
|
||||
#[cfg(feature = "unproven")]
|
||||
struct NewInputPinImpl {
|
||||
state: Result<bool, ()>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "unproven")]
|
||||
impl v2::InputPin for NewInputPinImpl {
|
||||
type Error = ();
|
||||
|
||||
fn is_low(&self) -> Result<bool, Self::Error> {
|
||||
self.state.map(|v| v == false)
|
||||
}
|
||||
fn is_high(&self) -> Result<bool, Self::Error>{
|
||||
self.state.map(|v| v == true)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unproven")]
|
||||
#[allow(deprecated)]
|
||||
struct OldInputPinConsumer<T: v1::InputPin> {
|
||||
_pin: T,
|
||||
}
|
||||
|
||||
#[cfg(feature = "unproven")]
|
||||
#[allow(deprecated)]
|
||||
impl <T>OldInputPinConsumer<T>
|
||||
where T: v1::InputPin
|
||||
{
|
||||
pub fn new(pin: T) -> OldInputPinConsumer<T> {
|
||||
OldInputPinConsumer{ _pin: pin }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unproven")]
|
||||
#[test]
|
||||
fn v1_v2_input_explicit() {
|
||||
let i = NewInputPinImpl{state: Ok(false)};
|
||||
let _c: OldInputPinConsumer<OldInputPin<_>> = OldInputPinConsumer::new(i.into());
|
||||
}
|
||||
|
||||
#[cfg(feature = "unproven")]
|
||||
#[test]
|
||||
fn v1_v2_input_state() {
|
||||
let i: OldInputPin<_> = NewInputPinImpl{state: Ok(false)}.into();
|
||||
|
||||
assert_eq!(i.is_low(), true);
|
||||
assert_eq!(i.is_high(), false);
|
||||
}
|
||||
|
||||
#[cfg(feature = "unproven")]
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn v1_v2_input_panic() {
|
||||
let i: OldInputPin<_> = NewInputPinImpl{state: Err(())}.into();
|
||||
|
||||
i.is_low();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
/// Digital I/O
|
||||
//! Digital I/O
|
||||
//!
|
||||
//! Version 2 / fallible traits. Infallible implementations should set Error to `!`.
|
||||
|
||||
/// Single digital push-pull output pin
|
||||
pub trait OutputPin {
|
||||
|
||||
157
src/digital/v2_compat.rs
Normal file
157
src/digital/v2_compat.rs
Normal file
@@ -0,0 +1,157 @@
|
||||
//! v2 compatibility shims
|
||||
//! this module adds implicit forward support to v1 digital traits
|
||||
|
||||
#[allow(deprecated)]
|
||||
use super::v1;
|
||||
use super::v2;
|
||||
|
||||
/// Implementation of fallible `v2::OutputPin` for `v1::OutputPin` traits
|
||||
#[allow(deprecated)]
|
||||
impl <T> v2::OutputPin for T
|
||||
where
|
||||
T: v1::OutputPin,
|
||||
{
|
||||
// TODO: update to ! when never_type is stabilized
|
||||
type Error = ();
|
||||
|
||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||
Ok(self.set_low())
|
||||
}
|
||||
|
||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||
Ok(self.set_high())
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of fallible `v2::StatefulOutputPin` for `v1::StatefulOutputPin` digital traits
|
||||
#[cfg(feature = "unproven")]
|
||||
#[allow(deprecated)]
|
||||
impl <T> v2::StatefulOutputPin for T
|
||||
where
|
||||
T: v1::StatefulOutputPin + v1::OutputPin,
|
||||
{
|
||||
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
||||
Ok(self.is_set_low())
|
||||
}
|
||||
|
||||
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
||||
Ok(self.is_set_high())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Implementation of fallible `v2::InputPin` for `v1::InputPin` digital traits
|
||||
#[cfg(feature = "unproven")]
|
||||
#[allow(deprecated)]
|
||||
impl <T> v2::InputPin for T
|
||||
where
|
||||
T: v1::InputPin
|
||||
{
|
||||
// TODO: update to ! when never_type is stabilized
|
||||
type Error = ();
|
||||
|
||||
fn is_low(&self) -> Result<bool, Self::Error> {
|
||||
Ok(self.is_low())
|
||||
}
|
||||
|
||||
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||
Ok(self.is_high())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
#[allow(deprecated)]
|
||||
use crate::digital::v1;
|
||||
use crate::digital::v2;
|
||||
|
||||
#[allow(deprecated)]
|
||||
struct OldOutputPinImpl {
|
||||
state: bool
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl v1::OutputPin for OldOutputPinImpl {
|
||||
fn set_low(&mut self) {
|
||||
self.state = false;
|
||||
}
|
||||
fn set_high(&mut self) {
|
||||
self.state = true;
|
||||
}
|
||||
}
|
||||
|
||||
struct NewOutputPinConsumer<T: v2::OutputPin> {
|
||||
_pin: T,
|
||||
}
|
||||
|
||||
impl <T>NewOutputPinConsumer<T>
|
||||
where T: v2::OutputPin {
|
||||
pub fn new(pin: T) -> NewOutputPinConsumer<T> {
|
||||
NewOutputPinConsumer{ _pin: pin }
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v2_v1_output_implicit() {
|
||||
let i = OldOutputPinImpl{state: false};
|
||||
let _c = NewOutputPinConsumer::new(i);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v2_v1_output_state() {
|
||||
let mut o = OldOutputPinImpl{state: false};
|
||||
|
||||
v2::OutputPin::set_high(&mut o).unwrap();
|
||||
assert_eq!(o.state, true);
|
||||
|
||||
v2::OutputPin::set_low(&mut o).unwrap();
|
||||
assert_eq!(o.state, false);
|
||||
}
|
||||
|
||||
#[cfg(feature = "unproven")]
|
||||
#[allow(deprecated)]
|
||||
struct OldInputPinImpl {
|
||||
state: bool
|
||||
}
|
||||
|
||||
#[cfg(feature = "unproven")]
|
||||
#[allow(deprecated)]
|
||||
impl v1::InputPin for OldInputPinImpl {
|
||||
fn is_low(&self) -> bool {
|
||||
!self.state
|
||||
}
|
||||
fn is_high(&self) -> bool {
|
||||
self.state
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unproven")]
|
||||
struct NewInputPinConsumer<T: v2::InputPin> {
|
||||
_pin: T,
|
||||
}
|
||||
|
||||
#[cfg(feature = "unproven")]
|
||||
impl <T>NewInputPinConsumer<T>
|
||||
where T: v2::InputPin {
|
||||
pub fn new(pin: T) -> NewInputPinConsumer<T> {
|
||||
NewInputPinConsumer{ _pin: pin }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unproven")]
|
||||
#[test]
|
||||
fn v2_v1_input_implicit() {
|
||||
let i = OldInputPinImpl{state: false};
|
||||
let _c = NewInputPinConsumer::new(i);
|
||||
}
|
||||
|
||||
#[cfg(feature = "unproven")]
|
||||
#[test]
|
||||
fn v2_v1_input_state() {
|
||||
let mut i = OldInputPinImpl{state: false};
|
||||
|
||||
assert_eq!(v2::InputPin::is_high(&mut i).unwrap(), false);
|
||||
assert_eq!(v2::InputPin::is_low(&mut i).unwrap(), true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user