use core::future::{Future, poll_fn};
use core::pin::pin;
use core::task::Poll;
pub trait CombineReaders {
type ToBeRead<'b>;
fn read<U>(&self, f: impl FnOnce(Self::ToBeRead<'_>) -> U) -> U;
#[allow(async_fn_in_trait)]
async fn wait_for_update(&mut self) -> &mut Self;
}
pub(super) trait Sealed {}
#[allow(private_bounds)]
pub trait CombinableReader: Sealed {
type ToBeRead: 'static;
#[doc(hidden)]
fn borrow(&self) -> core::cell::Ref<'_, Self::ToBeRead>;
#[doc(hidden)]
#[allow(async_fn_in_trait)]
async fn wait_for_update(&mut self);
}
macro_rules! impl_combined_reader_helper {
(
tuples: [
$(($($generic_type:ident)*),)*
],
) => {
$(
impl<$($generic_type,)*> CombineReaders for ( $( &mut $generic_type, )* )
where
$($generic_type: CombinableReader,)*
{
type ToBeRead<'x> = (
$(&'x <$generic_type as CombinableReader>::ToBeRead,)*
);
#[allow(non_snake_case)]
#[cfg_attr(feature = "veecle-telemetry", veecle_telemetry::instrument)]
fn read<A>(&self, f: impl FnOnce(Self::ToBeRead<'_>) -> A) -> A {
let ($($generic_type,)*) = self;
let ($($generic_type,)*) = ($({
$generic_type.borrow()
},)*);
f(($(&*$generic_type,)*))
}
#[allow(non_snake_case)]
#[cfg_attr(feature = "veecle-telemetry", veecle_telemetry::instrument)]
async fn wait_for_update(&mut self) -> &mut Self {
{
let ($($generic_type,)*) = self;
let ($(mut $generic_type,)*) = ($(pin!($generic_type.wait_for_update()),)*);
poll_fn(move |cx| {
let mut update_available = false;
$(
if $generic_type.as_mut().poll(cx).is_ready() {
update_available = true;
}
)*
if update_available {
Poll::Ready(())
} else {
Poll::Pending
}
}).await;
}
self
}
}
)*
};
}
impl_combined_reader_helper!(
tuples: [
(T U),
(T U V),
(T U V W),
(T U V W X),
(T U V W X Y),
(T U V W X Y Z),
],
);
#[cfg(test)]
mod tests {
use core::pin::pin;
use futures::FutureExt;
use crate::datastore::{
CombineReaders, ExclusiveReader, Reader, Slot, Storable, Writer, generational,
};
#[test]
fn read_exclusive_reader() {
#[derive(Eq, PartialEq, Debug, Clone, Storable)]
#[storable(crate = crate)]
struct Sensor0(u8);
#[derive(Eq, PartialEq, Debug, Clone, Storable)]
#[storable(crate = crate)]
struct Sensor1(u8);
let slot0 = pin!(Slot::<Sensor0>::new());
let slot1 = pin!(Slot::<Sensor1>::new());
let mut reader0 = ExclusiveReader::from_slot(slot0.as_ref());
let mut reader1 = ExclusiveReader::from_slot(slot1.as_ref());
(&mut reader0, &mut reader1).read(|(a, b)| assert_eq!(a.is_none(), b.is_none()));
}
#[test]
fn wait_for_update_exclusive_reader() {
#[derive(Eq, PartialEq, Debug, Clone, Storable)]
#[storable(crate = crate)]
struct Sensor0(u8);
#[derive(Eq, PartialEq, Debug, Clone, Storable)]
#[storable(crate = crate)]
struct Sensor1(u8);
let source = pin!(generational::Source::new());
let slot0 = pin!(Slot::<Sensor0>::new());
let slot1 = pin!(Slot::<Sensor1>::new());
let mut writer0 = Writer::new(source.as_ref().waiter(), slot0.as_ref());
let mut writer1 = Writer::new(source.as_ref().waiter(), slot1.as_ref());
let mut reader0 = ExclusiveReader::from_slot(slot0.as_ref());
let mut reader1 = ExclusiveReader::from_slot(slot1.as_ref());
assert!(
(&mut reader0, &mut reader1)
.wait_for_update()
.now_or_never()
.is_none()
);
source.as_ref().increment_generation();
writer0.write(Sensor0(2)).now_or_never().unwrap();
writer1.write(Sensor1(2)).now_or_never().unwrap();
assert!(
(&mut reader0, &mut reader1)
.wait_for_update()
.now_or_never()
.is_some()
);
assert!(
(&mut reader0, &mut reader1)
.wait_for_update()
.now_or_never()
.is_none()
);
}
#[test]
fn read() {
#[derive(Eq, PartialEq, Debug, Clone, Storable)]
#[storable(crate = crate)]
struct Sensor0(u8);
#[derive(Eq, PartialEq, Debug, Clone, Storable)]
#[storable(crate = crate)]
struct Sensor1(u8);
let source = pin!(generational::Source::new());
let slot0 = pin!(Slot::<Sensor0>::new());
let slot1 = pin!(Slot::<Sensor1>::new());
let mut reader0 = Reader::from_slot(slot0.as_ref());
let mut reader1 = Reader::from_slot(slot1.as_ref());
(&mut reader0, &mut reader1).read(|(a, b)| assert_eq!(a.is_none(), b.is_none()));
let mut writer0 = Writer::new(source.as_ref().waiter(), slot0.as_ref());
let mut writer1 = Writer::new(source.as_ref().waiter(), slot1.as_ref());
source.as_ref().increment_generation();
writer0.write(Sensor0(2)).now_or_never().unwrap();
writer1.write(Sensor1(2)).now_or_never().unwrap();
let mut reader0 = reader0.wait_init().now_or_never().unwrap();
let mut reader1 = reader1.wait_init().now_or_never().unwrap();
(&mut reader0, &mut reader1).read(|(a, b)| assert_eq!(a.0, b.0));
}
#[test]
fn wait_for_update() {
#[derive(Eq, PartialEq, Debug, Clone, Storable)]
#[storable(crate = crate)]
struct Sensor0(u8);
#[derive(Eq, PartialEq, Debug, Clone, Storable)]
#[storable(crate = crate)]
struct Sensor1(u8);
let source = pin!(generational::Source::new());
let slot0 = pin!(Slot::<Sensor0>::new());
let slot1 = pin!(Slot::<Sensor1>::new());
let mut writer0 = Writer::new(source.as_ref().waiter(), slot0.as_ref());
let mut writer1 = Writer::new(source.as_ref().waiter(), slot1.as_ref());
let mut reader0 = Reader::from_slot(slot0.as_ref());
let mut reader1 = Reader::from_slot(slot1.as_ref());
assert!(
(&mut reader0, &mut reader1)
.wait_for_update()
.now_or_never()
.is_none()
);
source.as_ref().increment_generation();
writer0.write(Sensor0(2)).now_or_never().unwrap();
writer1.write(Sensor1(2)).now_or_never().unwrap();
assert!(
(&mut reader0, &mut reader1)
.wait_for_update()
.now_or_never()
.is_some()
);
assert!(
(&mut reader0, &mut reader1)
.wait_for_update()
.now_or_never()
.is_none()
);
let mut reader0 = reader0.wait_init().now_or_never().unwrap();
let mut reader1 = reader1.wait_init().now_or_never().unwrap();
assert!(
(&mut reader0, &mut reader1)
.wait_for_update()
.now_or_never()
.is_none()
);
source.as_ref().increment_generation();
writer0.write(Sensor0(3)).now_or_never().unwrap();
writer1.write(Sensor1(3)).now_or_never().unwrap();
(&mut reader0, &mut reader1)
.wait_for_update()
.now_or_never()
.unwrap()
.read(|(a, b)| assert_eq!(a.0, b.0));
assert!(
(&mut reader0, &mut reader1)
.wait_for_update()
.now_or_never()
.is_none()
);
}
#[test]
fn read_mixed() {
#[derive(Eq, PartialEq, Debug, Clone, Storable)]
#[storable(crate = crate)]
struct Sensor0(u8);
#[derive(Eq, PartialEq, Debug, Clone, Storable)]
#[storable(crate = crate)]
struct Sensor1(u8);
let source = pin!(generational::Source::new());
let slot0 = pin!(Slot::<Sensor0>::new());
let slot1 = pin!(Slot::<Sensor1>::new());
let mut reader0 = Reader::from_slot(slot0.as_ref());
let mut reader1 = ExclusiveReader::from_slot(slot1.as_ref());
(&mut reader0, &mut reader1).read(|(a, b)| assert_eq!(a.is_none(), b.is_none()));
let mut writer0 = Writer::new(source.as_ref().waiter(), slot0.as_ref());
let mut writer1 = Writer::new(source.as_ref().waiter(), slot1.as_ref());
source.as_ref().increment_generation();
writer0.write(Sensor0(2)).now_or_never().unwrap();
writer1.write(Sensor1(2)).now_or_never().unwrap();
let mut reader0 = reader0.wait_init().now_or_never().unwrap();
(&mut reader0, &mut reader1)
.read(|(a, b): (&Sensor0, &Option<Sensor1>)| assert_eq!(a.0, b.as_ref().unwrap().0));
}
}