use crate::round::State as RoundState;
use futures::task;
use parking_lot::{RwLock, RwLockReadGuard};
use std::{sync::Arc, task::Context};
struct Bridged<H, N> {
inner: RwLock<RoundState<H, N>>,
waker: task::AtomicWaker,
}
impl<H, N> Bridged<H, N> {
fn new(inner: RwLock<RoundState<H, N>>) -> Self {
Bridged { inner, waker: task::AtomicWaker::new() }
}
}
pub(crate) struct PriorView<H, N>(Arc<Bridged<H, N>>);
impl<H, N> PriorView<H, N> {
pub(crate) fn update(&self, new: RoundState<H, N>) {
*self.0.inner.write() = new;
self.0.waker.wake();
}
}
pub(crate) struct LatterView<H, N>(Arc<Bridged<H, N>>);
impl<H, N> LatterView<H, N> {
pub(crate) fn get(&self, cx: &mut Context) -> RwLockReadGuard<RoundState<H, N>> {
self.0.waker.register(cx.waker());
self.0.inner.read()
}
}
pub(crate) fn bridge_state<H, N>(initial: RoundState<H, N>) -> (PriorView<H, N>, LatterView<H, N>) {
let inner = Arc::new(Bridged::new(RwLock::new(initial)));
(PriorView(inner.clone()), LatterView(inner))
}
#[cfg(test)]
mod tests {
use super::*;
use std::{sync::Barrier, task::Poll};
#[test]
fn bridging_state() {
let initial =
RoundState { prevote_ghost: None, finalized: None, estimate: None, completable: false };
let (prior, latter) = bridge_state(initial);
let waits_for_finality = ::futures::future::poll_fn(move |cx| -> Poll<()> {
if latter.get(cx).finalized.is_some() {
Poll::Ready(())
} else {
Poll::Pending
}
});
let barrier = Arc::new(Barrier::new(2));
let barrier_other = barrier.clone();
::std::thread::spawn(move || {
barrier_other.wait();
prior.update(RoundState {
prevote_ghost: Some(("5", 5)),
finalized: Some(("1", 1)),
estimate: Some(("3", 3)),
completable: true,
});
});
barrier.wait();
futures::executor::block_on(waits_for_finality);
}
}