Rename Unborrowed -> PeripheralRef, Unborrow -> Peripheral
This commit is contained in:
@ -6,10 +6,10 @@ pub(crate) mod fmt;
|
||||
|
||||
pub mod drop;
|
||||
mod macros;
|
||||
mod peripheral;
|
||||
pub mod ratio;
|
||||
pub mod ring_buffer;
|
||||
mod unborrow;
|
||||
pub use unborrow::{Unborrow, Unborrowed};
|
||||
pub use peripheral::{Peripheral, PeripheralRef};
|
||||
|
||||
/// Low power blocking wait loop using WFE/SEV.
|
||||
pub fn low_power_wait_until(mut condition: impl FnMut() -> bool) {
|
||||
|
@ -21,7 +21,7 @@ macro_rules! peripherals {
|
||||
}
|
||||
|
||||
$(#[$cfg])?
|
||||
$crate::impl_unborrow!($name);
|
||||
$crate::impl_peripheral!($name);
|
||||
)*
|
||||
}
|
||||
|
||||
@ -71,22 +71,22 @@ macro_rules! peripherals {
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! unborrow {
|
||||
macro_rules! into_ref {
|
||||
($($name:ident),*) => {
|
||||
$(
|
||||
let mut $name = $name.unborrow();
|
||||
let mut $name = $name.into_ref();
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_unborrow {
|
||||
macro_rules! impl_peripheral {
|
||||
($type:ident) => {
|
||||
impl $crate::Unborrow for $type {
|
||||
type Target = $type;
|
||||
impl $crate::Peripheral for $type {
|
||||
type P = $type;
|
||||
|
||||
#[inline]
|
||||
unsafe fn unborrow_unchecked(&mut self) -> Self::Target {
|
||||
unsafe fn clone_unchecked(&mut self) -> Self::P {
|
||||
$type { ..*self }
|
||||
}
|
||||
}
|
||||
|
141
embassy-hal-common/src/peripheral.rs
Normal file
141
embassy-hal-common/src/peripheral.rs
Normal file
@ -0,0 +1,141 @@
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
/// An exclusive reference to a peripheral.
|
||||
///
|
||||
/// This is functionally the same as a `&'a mut T`. The reason for having a
|
||||
/// dedicated struct is memory efficiency:
|
||||
///
|
||||
/// Peripheral singletons are typically either zero-sized (for concrete peripehrals
|
||||
/// like `PA9` or `Spi4`) or very small (for example `AnyPin` which is 1 byte).
|
||||
/// However `&mut T` is always 4 bytes for 32-bit targets, even if T is zero-sized.
|
||||
/// PeripheralRef stores a copy of `T` instead, so it's the same size.
|
||||
///
|
||||
/// but it is the size of `T` not the size
|
||||
/// of a pointer. This is useful if T is a zero sized type.
|
||||
pub struct PeripheralRef<'a, T> {
|
||||
inner: T,
|
||||
_lifetime: PhantomData<&'a mut T>,
|
||||
}
|
||||
|
||||
impl<'a, T> PeripheralRef<'a, T> {
|
||||
#[inline]
|
||||
pub fn new(inner: T) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
_lifetime: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn map_into<U>(self) -> PeripheralRef<'a, U>
|
||||
where
|
||||
T: Into<U>,
|
||||
{
|
||||
PeripheralRef {
|
||||
inner: self.inner.into(),
|
||||
_lifetime: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn into_inner(self) -> T {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Deref for PeripheralRef<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> DerefMut for PeripheralRef<'a, T> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for any type that can be used as a peripheral of type `P`.
|
||||
///
|
||||
/// This is used in driver constructors, to allow passing either owned peripherals (e.g. `TWISPI0`),
|
||||
/// or borrowed peripherals (e.g. `&mut TWISPI0`).
|
||||
///
|
||||
/// For example, if you have a driver with a constructor like this:
|
||||
///
|
||||
/// ```ignore
|
||||
/// impl<'d, T: Instance> Twim<'d, T> {
|
||||
/// pub fn new(
|
||||
/// twim: impl Peripheral<P = T> + 'd,
|
||||
/// irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
/// sda: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
/// scl: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
/// config: Config,
|
||||
/// ) -> Self { .. }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// You may call it with owned peripherals, which yields an instance that can live forever (`'static`):
|
||||
///
|
||||
/// ```ignore
|
||||
/// let mut twi: Twim<'static, ...> = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
|
||||
/// ```
|
||||
///
|
||||
/// Or you may call it with borrowed peripherals, which yields an instance that can only live for as long
|
||||
/// as the borrows last:
|
||||
///
|
||||
/// ```ignore
|
||||
/// let mut twi: Twim<'_, ...> = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config);
|
||||
/// ```
|
||||
///
|
||||
/// # Implementation details, for HAL authors
|
||||
///
|
||||
/// When writing a HAL, the intended way to use this trait is to take `impl Peripheral<P = ..>` in
|
||||
/// the HAL's public API (such as driver constructors), calling `.into_ref()` to obtain a `PeripheralRef`,
|
||||
/// and storing that in the driver struct.
|
||||
///
|
||||
/// `.into_ref()` on an owned `T` yields a `PeripheralRef<'static, T>`.
|
||||
/// `.into_ref()` on an `&'a mut T` yields a `PeripheralRef<'a, T>`.
|
||||
pub trait Peripheral: Sized {
|
||||
/// Peripheral singleton type
|
||||
type P;
|
||||
|
||||
/// Unsafely clone (duplicate) a peripheral singleton.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This returns an owned clone of the peripheral. You must manually ensure
|
||||
/// only one copy of the peripheral is in use at a time. For example, don't
|
||||
/// create two SPI drivers on `SPI1`, because they will "fight" each other.
|
||||
///
|
||||
/// 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;
|
||||
|
||||
/// 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>
|
||||
where
|
||||
Self: 'a,
|
||||
{
|
||||
PeripheralRef::new(unsafe { self.clone_unchecked() })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, T: DerefMut> Peripheral for T
|
||||
where
|
||||
T::Target: Peripheral,
|
||||
{
|
||||
type P = <T::Target as Peripheral>::P;
|
||||
|
||||
#[inline]
|
||||
unsafe fn clone_unchecked(&mut self) -> Self::P {
|
||||
self.deref_mut().clone_unchecked()
|
||||
}
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
/// This is essentially a `&mut T`, but it is the size of `T` not the size
|
||||
/// of a pointer. This is useful if T is a zero sized type.
|
||||
pub struct Unborrowed<'a, T> {
|
||||
inner: T,
|
||||
_lifetime: PhantomData<&'a mut T>,
|
||||
}
|
||||
|
||||
impl<'a, T> Unborrowed<'a, T> {
|
||||
pub fn new(inner: T) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
_lifetime: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_into<U>(self) -> Unborrowed<'a, U>
|
||||
where
|
||||
T: Into<U>,
|
||||
{
|
||||
Unborrowed {
|
||||
inner: self.inner.into(),
|
||||
_lifetime: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn into_inner(self) -> T {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Deref for Unborrowed<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> DerefMut for Unborrowed<'a, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
|
||||
/// Unsafely unborrow an owned singleton out of a `&mut`.
|
||||
///
|
||||
/// It is intended to be implemented for owned peripheral singletons, such as `USART3` or `AnyPin`.
|
||||
/// Unborrowing an owned `T` yields an `Unborrowed<'static, T>`.
|
||||
/// Unborrowing a `&'a mut T` yields an `Unborrowed<'a, T>`.
|
||||
///
|
||||
/// This allows writing HAL drivers that either own or borrow their peripherals, but that don't have
|
||||
/// to store pointers in the borrowed case.
|
||||
pub trait Unborrow: Sized {
|
||||
/// Unborrow result type
|
||||
type Target;
|
||||
|
||||
unsafe fn unborrow_unchecked(&mut self) -> Self::Target;
|
||||
|
||||
/// Unborrow a value.
|
||||
#[inline]
|
||||
fn unborrow<'a>(mut self) -> Unborrowed<'a, Self::Target>
|
||||
where
|
||||
Self: 'a,
|
||||
{
|
||||
Unborrowed::new(unsafe { self.unborrow_unchecked() })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, T: DerefMut> Unborrow for T
|
||||
where
|
||||
T::Target: Unborrow,
|
||||
{
|
||||
type Target = <T::Target as Unborrow>::Target;
|
||||
|
||||
#[inline]
|
||||
unsafe fn unborrow_unchecked(&mut self) -> Self::Target {
|
||||
self.deref_mut().unborrow_unchecked()
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user