use crate::{Address, Block, ReadCapability, WriteCapability};
use core::marker::PhantomData;
pub trait BufferInterfaceBase {
type Error;
type AddressType: Address;
}
impl<T: BufferInterfaceBase> BufferInterfaceBase for &mut T {
type Error = T::Error;
type AddressType = T::AddressType;
}
#[diagnostic::on_unimplemented(
label = "cannot use blocking buffer operations when the device interface doesn't know how to read and write buffers",
note = "to enable buffer operations, implement the trait on this type"
)]
pub trait BufferInterface: BufferInterfaceBase {
fn write(&mut self, address: Self::AddressType, buf: &[u8]) -> Result<usize, Self::Error>;
fn flush(&mut self, address: Self::AddressType) -> Result<(), Self::Error>;
fn read(&mut self, address: Self::AddressType, buf: &mut [u8]) -> Result<usize, Self::Error>;
}
#[diagnostic::do_not_recommend]
impl<T: BufferInterface> BufferInterface for &mut T {
fn write(&mut self, address: Self::AddressType, buf: &[u8]) -> Result<usize, Self::Error> {
(*self).write(address, buf)
}
fn flush(&mut self, address: Self::AddressType) -> Result<(), Self::Error> {
(*self).flush(address)
}
fn read(&mut self, address: Self::AddressType, buf: &mut [u8]) -> Result<usize, Self::Error> {
(*self).read(address, buf)
}
}
#[diagnostic::on_unimplemented(
label = "cannot use async buffer operations when the device interface doesn't know how to read and write buffers",
note = "to enable buffer operations, implement the trait on this type"
)]
pub trait AsyncBufferInterface: BufferInterfaceBase {
async fn write(&mut self, address: Self::AddressType, buf: &[u8])
-> Result<usize, Self::Error>;
async fn flush(&mut self, address: Self::AddressType) -> Result<(), Self::Error>;
async fn read(
&mut self,
address: Self::AddressType,
buf: &mut [u8],
) -> Result<usize, Self::Error>;
}
#[diagnostic::do_not_recommend]
impl<T: AsyncBufferInterface> AsyncBufferInterface for &mut T {
fn write(
&mut self,
address: Self::AddressType,
buf: &[u8],
) -> impl Future<Output = Result<usize, Self::Error>> {
(*self).write(address, buf)
}
fn flush(
&mut self,
address: Self::AddressType,
) -> impl Future<Output = Result<(), Self::Error>> {
(*self).flush(address)
}
fn read(
&mut self,
address: Self::AddressType,
buf: &mut [u8],
) -> impl Future<Output = Result<usize, Self::Error>> {
(*self).read(address, buf)
}
}
pub struct BufferOperation<'b, B, AddressType, Access>
where
B: Block,
B::Interface: BufferInterfaceBase<AddressType = AddressType>,
AddressType: Address,
{
block: &'b mut B,
address: AddressType,
_phantom: PhantomData<Access>,
}
impl<'b, B, AddressType, Access> BufferOperation<'b, B, AddressType, Access>
where
B: Block,
B::Interface: BufferInterfaceBase<AddressType = AddressType>,
AddressType: Address,
{
#[doc(hidden)]
pub fn new(
interface: &'b mut B,
address: <B::Interface as BufferInterfaceBase>::AddressType,
) -> Self {
Self {
block: interface,
address,
_phantom: PhantomData,
}
}
pub fn write(
&mut self,
buf: &[u8],
) -> Result<usize, <B::Interface as BufferInterfaceBase>::Error>
where
B::Interface: BufferInterface,
Access: WriteCapability,
{
self.block.interface().write(self.address, buf)
}
pub fn write_async(
&mut self,
buf: &[u8],
) -> impl Future<Output = Result<usize, <B::Interface as BufferInterfaceBase>::Error>>
where
B::Interface: AsyncBufferInterface,
Access: WriteCapability,
{
self.block.interface().write(self.address, buf)
}
pub fn write_all(
&mut self,
mut buf: &[u8],
) -> Result<(), <B::Interface as BufferInterfaceBase>::Error>
where
B::Interface: BufferInterface,
Access: WriteCapability,
{
while !buf.is_empty() {
match self.write(buf) {
Ok(0) => panic!("write() returned Ok(0)"),
Ok(n) => buf = &buf[n..],
Err(e) => return Err(e),
}
}
Ok(())
}
pub async fn write_all_async(
&mut self,
mut buf: &[u8],
) -> Result<(), <B::Interface as BufferInterfaceBase>::Error>
where
B::Interface: AsyncBufferInterface,
Access: WriteCapability,
{
while !buf.is_empty() {
match self.write_async(buf).await {
Ok(0) => panic!("write() returned Ok(0)"),
Ok(n) => buf = &buf[n..],
Err(e) => return Err(e),
}
}
Ok(())
}
pub fn flush(&mut self) -> Result<(), <B::Interface as BufferInterfaceBase>::Error>
where
B::Interface: BufferInterface,
Access: WriteCapability,
{
self.block.interface().flush(self.address)
}
pub fn flush_async(
&mut self,
) -> impl Future<Output = Result<(), <B::Interface as BufferInterfaceBase>::Error>>
where
B::Interface: AsyncBufferInterface,
Access: WriteCapability,
{
self.block.interface().flush(self.address)
}
pub fn read(
&mut self,
buf: &mut [u8],
) -> Result<usize, <B::Interface as BufferInterfaceBase>::Error>
where
B::Interface: BufferInterface,
Access: ReadCapability,
{
self.block.interface().read(self.address, buf)
}
pub fn read_async(
&mut self,
buf: &mut [u8],
) -> impl Future<Output = Result<usize, <B::Interface as BufferInterfaceBase>::Error>>
where
B::Interface: AsyncBufferInterface,
Access: ReadCapability,
{
self.block.interface().read(self.address, buf)
}
}
#[cfg(feature = "embedded-io-07")]
impl<B, AddressType, Access> embedded_io::ErrorType for BufferOperation<'_, B, AddressType, Access>
where
B: Block,
B::Interface: BufferInterfaceBase<AddressType = AddressType>,
<B::Interface as BufferInterfaceBase>::Error: embedded_io::Error,
AddressType: Address,
{
type Error = <B::Interface as BufferInterfaceBase>::Error;
}
#[cfg(feature = "embedded-io-07")]
impl<B, AddressType, Access> embedded_io::Write for BufferOperation<'_, B, AddressType, Access>
where
B: Block,
B::Interface: BufferInterface<AddressType = AddressType>,
<B::Interface as BufferInterfaceBase>::Error: embedded_io::Error,
Access: WriteCapability,
AddressType: Address,
{
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write(buf)
}
fn flush(&mut self) -> Result<(), Self::Error> {
self.flush()
}
}
#[cfg(feature = "embedded-io-07")]
impl<B, AddressType, Access> embedded_io::Read for BufferOperation<'_, B, AddressType, Access>
where
B: Block,
B::Interface: BufferInterface<AddressType = AddressType>,
<B::Interface as BufferInterfaceBase>::Error: embedded_io::Error,
Access: ReadCapability,
AddressType: Address,
{
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read(buf)
}
}
#[cfg(feature = "embedded-io-07")]
impl<B, AddressType, Access> embedded_io_async::Write
for BufferOperation<'_, B, AddressType, Access>
where
B: Block,
B::Interface: AsyncBufferInterface<AddressType = AddressType>,
<B::Interface as BufferInterfaceBase>::Error: embedded_io::Error,
Access: WriteCapability,
AddressType: Address,
{
fn write(&mut self, buf: &[u8]) -> impl Future<Output = Result<usize, Self::Error>> {
self.write_async(buf)
}
fn flush(&mut self) -> impl Future<Output = Result<(), Self::Error>> {
self.flush_async()
}
}
#[cfg(feature = "embedded-io-07")]
impl<B, AddressType, Access> embedded_io_async::Read for BufferOperation<'_, B, AddressType, Access>
where
B: Block,
B::Interface: AsyncBufferInterface<AddressType = AddressType>,
<B::Interface as BufferInterfaceBase>::Error: embedded_io::Error,
Access: ReadCapability,
AddressType: Address,
{
fn read(&mut self, buf: &mut [u8]) -> impl Future<Output = Result<usize, Self::Error>> {
self.read_async(buf)
}
}