Add PeripheralRef::map_into (#2326)

* Add PeripheralRef::map_into

* Update clone_unchecked to take shared self

* Simplify pin erasure
This commit is contained in:
Dániel Buga 2024-10-16 15:34:11 +02:00 committed by GitHub
parent 6e2606b367
commit 472d5f93e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 100 additions and 62 deletions

View File

@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Add burst transfer support to DMA buffers (#2236)
- `AnyPin` now implements `From<GpioPin<N>>`. (#2326)
### Changed
### Fixed

View File

@ -48,7 +48,7 @@ impl Clone for InputSignal {
impl Peripheral for InputSignal {
type P = Self;
unsafe fn clone_unchecked(&mut self) -> Self::P {
unsafe fn clone_unchecked(&self) -> Self::P {
self.clone()
}
}
@ -187,7 +187,7 @@ pub struct OutputSignal {
impl Peripheral for OutputSignal {
type P = Self;
unsafe fn clone_unchecked(&mut self) -> Self::P {
unsafe fn clone_unchecked(&self) -> Self::P {
Self {
pin: self.pin.clone_unchecked(),
is_inverted: self.is_inverted,
@ -345,7 +345,7 @@ pub struct AnyInputSignal(AnyInputSignalInner);
impl Peripheral for AnyInputSignal {
type P = Self;
unsafe fn clone_unchecked(&mut self) -> Self::P {
unsafe fn clone_unchecked(&self) -> Self::P {
self.clone()
}
}

View File

@ -448,7 +448,7 @@ pub trait PeripheralOutput: PeripheralSignal {
}
/// Trait implemented by pins which can be used as inputs.
pub trait InputPin: Pin + PeripheralInput {
pub trait InputPin: Pin + PeripheralInput + Into<AnyPin> + 'static {
/// Listen for interrupts
#[doc(hidden)]
fn listen(&mut self, event: Event, _: private::Internal) {
@ -519,7 +519,7 @@ pub trait InputPin: Pin + PeripheralInput {
}
/// Trait implemented by pins which can be used as outputs.
pub trait OutputPin: Pin + PeripheralOutput {}
pub trait OutputPin: Pin + PeripheralOutput + Into<AnyPin> + 'static {}
/// Trait implemented by pins which can be used as analog pins
pub trait AnalogPin: Pin {
@ -776,7 +776,7 @@ where
{
type P = GpioPin<GPIONUM>;
unsafe fn clone_unchecked(&mut self) -> Self::P {
unsafe fn clone_unchecked(&self) -> Self::P {
core::ptr::read(self as *const _)
}
}
@ -1131,6 +1131,13 @@ macro_rules! gpio {
input_signals
}
}
impl From<GpioPin<$gpionum>> for AnyPin {
fn from(pin: GpioPin<$gpionum>) -> Self {
use $crate::gpio::Pin;
pin.degrade()
}
}
)+
pub(crate) enum AnyPinInner {
@ -1142,8 +1149,9 @@ macro_rules! gpio {
/// Type-erased GPIO pin
pub struct AnyPin(pub(crate) AnyPinInner);
impl AnyPin {
pub(crate) unsafe fn clone_unchecked(&self) -> Self {
impl $crate::peripheral::Peripheral for AnyPin {
type P = AnyPin;
unsafe fn clone_unchecked(&self) -> Self {
match self.0 {
$(AnyPinInner::[<Gpio $gpionum >](_) => {
Self(AnyPinInner::[< Gpio $gpionum >](unsafe { GpioPin::steal() }))
@ -1152,13 +1160,6 @@ macro_rules! gpio {
}
}
impl $crate::peripheral::Peripheral for AnyPin {
type P = AnyPin;
unsafe fn clone_unchecked(&mut self) -> Self {
AnyPin::clone_unchecked(self)
}
}
// These macros call the code block on the actually contained GPIO pin.
#[doc(hidden)]
@ -1598,18 +1599,17 @@ impl<P> private::Sealed for Output<'_, P> {}
impl<'d, P> Peripheral for Output<'d, P> {
type P = P;
unsafe fn clone_unchecked(&mut self) -> P {
unsafe fn clone_unchecked(&self) -> P {
self.pin.clone_unchecked()
}
}
impl<'d> Output<'d> {
/// Create GPIO output driver for a [GpioPin] with the provided level
/// Create GPIO open-drain output driver for a [Pin] with the provided
/// initial output-level and [Pull] configuration.
#[inline]
pub fn new<P: OutputPin>(pin: impl Peripheral<P = P> + 'd, initial_output: Level) -> Self {
let pin = Flex::new(pin);
Self::new_inner(pin, initial_output)
pub fn new(pin: impl Peripheral<P = impl OutputPin> + 'd, initial_output: Level) -> Self {
Self::new_typed(pin.map_into(), initial_output)
}
}
@ -1702,7 +1702,7 @@ impl<P> private::Sealed for Input<'_, P> {}
impl<'d, P> Peripheral for Input<'d, P> {
type P = P;
unsafe fn clone_unchecked(&mut self) -> P {
unsafe fn clone_unchecked(&self) -> P {
self.pin.clone_unchecked()
}
}
@ -1711,10 +1711,8 @@ impl<'d> Input<'d> {
/// Create GPIO input driver for a [Pin] with the provided [Pull]
/// configuration.
#[inline]
pub fn new<P: InputPin>(pin: impl Peripheral<P = P> + 'd, pull: Pull) -> Self {
let pin = Flex::new(pin);
Self::new_inner(pin, pull)
pub fn new(pin: impl Peripheral<P = impl InputPin> + 'd, pull: Pull) -> Self {
Self::new_typed(pin.map_into(), pull)
}
}
@ -1726,12 +1724,8 @@ where
/// configuration.
#[inline]
pub fn new_typed(pin: impl Peripheral<P = P> + 'd, pull: Pull) -> Self {
let pin = Flex::new_typed(pin);
let mut pin = Flex::new_typed(pin);
Self::new_inner(pin, pull)
}
fn new_inner(mut pin: Flex<'d, P>, pull: Pull) -> Self {
pin.set_as_input(pull);
Self { pin }
@ -1806,7 +1800,7 @@ impl<P> private::Sealed for OutputOpenDrain<'_, P> {}
impl<'d, P> Peripheral for OutputOpenDrain<'d, P> {
type P = P;
unsafe fn clone_unchecked(&mut self) -> P {
unsafe fn clone_unchecked(&self) -> P {
self.pin.clone_unchecked()
}
}
@ -1815,14 +1809,12 @@ impl<'d> OutputOpenDrain<'d> {
/// Create GPIO open-drain output driver for a [Pin] with the provided
/// initial output-level and [Pull] configuration.
#[inline]
pub fn new<P: InputPin + OutputPin>(
pin: impl Peripheral<P = P> + 'd,
pub fn new(
pin: impl Peripheral<P = impl InputPin + OutputPin> + 'd,
initial_output: Level,
pull: Pull,
) -> Self {
let pin = Flex::new(pin);
Self::new_inner(pin, initial_output, pull)
Self::new_typed(pin.map_into(), initial_output, pull)
}
}
@ -1834,15 +1826,9 @@ where
/// initial output-level and [Pull] configuration.
#[inline]
pub fn new_typed(pin: impl Peripheral<P = P> + 'd, initial_output: Level, pull: Pull) -> Self {
let pin = Flex::new_typed(pin);
Self::new_inner(pin, initial_output, pull)
}
fn new_inner(mut pin: Flex<'d, P>, initial_output: Level, pull: Pull) -> Self {
pin.pin
.set_output_high(initial_output.into(), private::Internal);
let mut pin = Flex::new_typed(pin);
pin.set_level(initial_output);
pin.set_as_open_drain(pull);
Self { pin }
@ -1945,7 +1931,7 @@ impl<P> private::Sealed for Flex<'_, P> {}
impl<'d, P> Peripheral for Flex<'d, P> {
type P = P;
unsafe fn clone_unchecked(&mut self) -> P {
unsafe fn clone_unchecked(&self) -> P {
core::ptr::read(&*self.pin as *const _)
}
}
@ -1954,10 +1940,8 @@ impl<'d> Flex<'d> {
/// Create flexible pin driver for a [Pin].
/// No mode change happens.
#[inline]
pub fn new<P: Pin>(pin: impl Peripheral<P = P> + 'd) -> Self {
crate::into_ref!(pin);
let pin = pin.degrade_pin(private::Internal);
Self::new_typed(pin)
pub fn new(pin: impl Peripheral<P = impl Into<AnyPin>> + 'd) -> Self {
Self::new_typed(pin.map_into())
}
}

View File

@ -10,7 +10,7 @@ use super::*;
impl crate::peripheral::Peripheral for Level {
type P = Self;
unsafe fn clone_unchecked(&mut self) -> Self::P {
unsafe fn clone_unchecked(&self) -> Self::P {
*self
}
}
@ -96,7 +96,7 @@ pub struct NoPin;
impl crate::peripheral::Peripheral for NoPin {
type P = Self;
unsafe fn clone_unchecked(&mut self) -> Self::P {
unsafe fn clone_unchecked(&self) -> Self::P {
Self
}
}

View File

@ -138,7 +138,7 @@ impl<const NUM: u8> crate::peripheral::Peripheral for SoftwareInterrupt<NUM> {
type P = SoftwareInterrupt<NUM>;
#[inline]
unsafe fn clone_unchecked(&mut self) -> Self::P {
unsafe fn clone_unchecked(&self) -> Self::P {
Self::steal()
}
}

View File

@ -44,7 +44,7 @@ impl<'a, T> PeripheralRef<'a, T> {
/// You should strongly prefer using `reborrow()` instead. It returns a
/// `PeripheralRef` that borrows `self`, which allows the borrow checker
/// to enforce this at compile time.
pub unsafe fn clone_unchecked(&mut self) -> PeripheralRef<'a, T>
pub unsafe fn clone_unchecked(&self) -> PeripheralRef<'a, T>
where
T: Peripheral<P = T>,
{
@ -62,6 +62,24 @@ impl<'a, T> PeripheralRef<'a, T> {
// self, so user code can't use both at the same time.
PeripheralRef::new(unsafe { self.inner.clone_unchecked() })
}
/// Map the inner peripheral using `Into`.
///
/// This converts from `PeripheralRef<'a, T>` to `PeripheralRef<'a, U>`,
/// using an `Into` impl to convert from `T` to `U`.
///
/// For example, this can be useful to degrade GPIO pins: converting from
/// PeripheralRef<'a, GpioPin<11>>` to `PeripheralRef<'a, AnyPin>`.
#[inline]
pub fn map_into<U>(self) -> PeripheralRef<'a, U>
where
T: Into<U>,
{
PeripheralRef {
inner: self.inner.into(),
_lifetime: PhantomData,
}
}
}
impl<'a, T> Deref for PeripheralRef<'a, T> {
@ -137,19 +155,32 @@ pub trait Peripheral: Sized + crate::private::Sealed {
/// You should strongly prefer using `into_ref()` instead. It returns a
/// `PeripheralRef`, which allows the borrow checker to enforce this at
/// compile time.
unsafe fn clone_unchecked(&mut self) -> Self::P;
unsafe fn clone_unchecked(&self) -> Self::P;
/// Convert a value into a `PeripheralRef`.
///
/// When called on an owned `T`, yields a `PeripheralRef<'static, T>`.
/// When called on an `&'a mut T`, yields a `PeripheralRef<'a, T>`.
#[inline]
fn into_ref<'a>(mut self) -> PeripheralRef<'a, Self::P>
fn into_ref<'a>(self) -> PeripheralRef<'a, Self::P>
where
Self: 'a,
{
PeripheralRef::new(unsafe { self.clone_unchecked() })
}
/// Map the peripheral using `Into`.
///
/// This converts from `Peripheral<P = T>` to `Peripheral<P = U>`,
/// using an `Into` impl to convert from `T` to `U`.
#[inline]
fn map_into<U>(self) -> U
where
Self::P: Into<U>,
U: Peripheral<P = U>,
{
unsafe { self.clone_unchecked().into() }
}
}
impl<T, P> Peripheral for &mut T
@ -158,12 +189,22 @@ where
{
type P = P;
unsafe fn clone_unchecked(&mut self) -> Self::P {
unsafe fn clone_unchecked(&self) -> Self::P {
T::clone_unchecked(self)
}
}
impl<T> crate::private::Sealed for &mut T where T: crate::private::Sealed {}
impl<T> crate::private::Sealed for PeripheralRef<'_, T> where T: crate::private::Sealed {}
impl<T: Peripheral> Peripheral for PeripheralRef<'_, T> {
type P = T::P;
#[inline]
unsafe fn clone_unchecked(&self) -> Self::P {
T::clone_unchecked(self)
}
}
mod peripheral_macros {
#[doc(hidden)]
@ -257,6 +298,17 @@ mod peripheral_macros {
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! into_mapped_ref {
($($name:ident),*) => {
$(
#[allow(unused_mut)]
let mut $name = $name.map_into().into_ref();
)*
}
}
#[doc(hidden)]
#[macro_export]
/// Macro to create a peripheral structure.
@ -288,7 +340,7 @@ mod peripheral_macros {
type P = $name;
#[inline]
unsafe fn clone_unchecked(&mut self) -> Self::P {
unsafe fn clone_unchecked(&self) -> Self::P {
Self::steal()
}
}
@ -346,7 +398,7 @@ mod peripheral_macros {
type P = $name;
#[inline]
unsafe fn clone_unchecked(&mut self) -> Self::P {
unsafe fn clone_unchecked(&self) -> Self::P {
Self::steal()
}
}

View File

@ -461,7 +461,7 @@ impl Peripheral for AnyTimer {
type P = Self;
#[inline]
unsafe fn clone_unchecked(&mut self) -> Self::P {
unsafe fn clone_unchecked(&self) -> Self::P {
core::ptr::read(self as *const _)
}
}

View File

@ -1003,7 +1003,7 @@ where
type P = Self;
#[inline]
unsafe fn clone_unchecked(&mut self) -> Self::P {
unsafe fn clone_unchecked(&self) -> Self::P {
core::ptr::read(self as *const _)
}
}

View File

@ -591,7 +591,7 @@ where
type P = Self;
#[inline]
unsafe fn clone_unchecked(&mut self) -> Self::P {
unsafe fn clone_unchecked(&self) -> Self::P {
core::ptr::read(self as *const _)
}
}