use core::future::Future;
use core::marker::PhantomData;
use core::task::{Context, Poll, Waker};
use core::pin::Pin;
extern crate std;
use std::boxed::Box;
use async_trait::async_trait;
use crate::{Transmit, Receive, Power};
pub struct AsyncOptions {
pub power: Option<i8>,
}
impl Default for AsyncOptions {
fn default() -> Self {
Self {
power: None,
}
}
}
#[cfg_attr(feature = "mock", doc = r##"
```
extern crate async_std;
use async_std::task;
# use radio::*;
# use radio::mock::*;
use radio::nonblocking::{AsyncTransmit, AsyncOptions};
# let mut radio = MockRadio::new(&[
# Transaction::start_transmit(vec![0xaa, 0xbb], None),
# Transaction::check_transmit(Ok(false)),
# Transaction::check_transmit(Ok(true)),
# ]);
#
task::block_on(async {
// Transmit using a future
let res = radio.async_transmit(&[0xaa, 0xbb], AsyncOptions::default()).await;
assert_eq!(res, Ok(()));
});
# radio.done();
```
"##)]
#[async_trait]
pub trait AsyncTransmit<E> {
async fn async_transmit(&mut self, data: &[u8], tx_options: AsyncOptions) -> Result<(), E> where E: 'async_trait;
}
#[async_trait]
impl <T, E> AsyncTransmit<E> for T
where
T: Transmit<Error = E> + Power<Error = E> + Send,
E: core::fmt::Debug + Send + Unpin,
{
async fn async_transmit(&mut self, data: &[u8], tx_options: AsyncOptions) -> Result<(), E> where E: 'async_trait,
{
if let Some(p) = tx_options.power {
self.set_power(p)?;
}
self.start_transmit(data)?;
let f: TransmitFuture<_, E> = TransmitFuture{radio: self, waker: None, _err: PhantomData};
let res = f.await?;
Ok(res)
}
}
struct TransmitFuture<'a, T, E> {
radio: &'a mut T,
waker: Option<Waker>,
_err: PhantomData<E>,
}
impl <'a, T, E> Future for TransmitFuture<'a, T, E>
where
T: Transmit<Error = E> + Power<Error = E> + Send,
E: core::fmt::Debug + Send + Unpin,
{
type Output = Result<(), E>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let s = self.get_mut();
if s.radio.check_transmit()? {
return Poll::Ready(Ok(()))
};
cx.waker().clone().wake();
s.waker = Some(cx.waker().clone());
Poll::Pending
}
}
#[cfg_attr(feature = "mock", doc = r##"
```
extern crate async_std;
use async_std::task;
# use radio::*;
# use radio::mock::*;
use radio::nonblocking::{AsyncReceive, AsyncOptions};
let data = [0xaa, 0xbb];
let info = BasicInfo::new(-81, 0);
# let mut radio = MockRadio::new(&[
# Transaction::start_receive(None),
# Transaction::check_receive(true, Ok(false)),
# Transaction::check_receive(true, Ok(true)),
# Transaction::get_received(Ok((data.to_vec(), info.clone()))),
# ]);
#
task::block_on(async {
// Setup buffer and receive info
let mut buff = [0u8; 128];
let mut i = BasicInfo::new(0, 0);
// Receive using a future
let res = radio.async_receive(&mut i, &mut buff, AsyncOptions::default()).await;
assert_eq!(res, Ok(data.len()));
assert_eq!(&buff[..data.len()], &data);
});
# radio.done();
```
"##)]
#[async_trait]
pub trait AsyncReceive<I, E> {
async fn async_receive(&mut self, info: &mut I, buff: &mut [u8], rx_options: AsyncOptions) -> Result<usize, E> where E: 'async_trait;
}
#[async_trait]
impl <T, I, E> AsyncReceive<I, E> for T
where
T: Receive<Error = E, Info = I> + Send,
I: core::fmt::Debug + Send,
E: core::fmt::Debug + Send + Unpin,
{
async fn async_receive(&mut self, info: &mut I, buff: &mut [u8], _rx_options: AsyncOptions) -> Result<usize, E> where E: 'async_trait {
self.start_receive()?;
let f: ReceiveFuture<_, I, E> = ReceiveFuture {
radio: self, info, buff, waker: None, _err: PhantomData
};
let r = f.await?;
Ok(r)
}
}
struct ReceiveFuture<'a, T, I, E> {
radio: &'a mut T,
info: &'a mut I,
buff: &'a mut [u8],
waker: Option<Waker>,
_err: PhantomData<E>,
}
impl <'a, T, I, E> Future for ReceiveFuture<'a, T, I, E>
where
T: Receive<Error = E, Info = I> + Send,
I: core::fmt::Debug + Send,
E: core::fmt::Debug + Send + Unpin,
{
type Output = Result<usize, E>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let s = self.get_mut();
if s.radio.check_receive(true)? {
let n = s.radio.get_received(s.info, s.buff)?;
return Poll::Ready(Ok(n));
}
cx.waker().clone().wake();
s.waker = Some(cx.waker().clone());
Poll::Pending
}
}