embassy/embassy-hal-common/src/unborrow.rs
2022-07-23 02:40:13 +02:00

82 lines
2 KiB
Rust

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()
}
}