added a new test for comm
This commit is contained in:
@@ -62,7 +62,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn not_called_if_finished() {
|
fn not_called_if_finished() {
|
||||||
spin_on(false, async {
|
spin_on(async {
|
||||||
let (mut req_in, mut req_out) = mpsc::channel(0);
|
let (mut req_in, mut req_out) = mpsc::channel(0);
|
||||||
let (mut rep_in, mut rep_out) = mpsc::channel(0);
|
let (mut rep_in, mut rep_out) = mpsc::channel(0);
|
||||||
join(
|
join(
|
||||||
|
|||||||
@@ -143,15 +143,26 @@ pub fn eprint_stream_events<'a, S: Stream + 'a>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
static WAKE_LODUD: RefCell<bool> = const { RefCell::new(false) };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Equivalent to [spin_on], but also logs on wake
|
||||||
|
pub fn spin_on_loud<Fut: Future>(fut: Fut) -> Fut::Output {
|
||||||
|
let prev = WAKE_LODUD.replace(true);
|
||||||
|
let ret = spin_on(fut);
|
||||||
|
WAKE_LODUD.set(prev);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
struct SpinWaker {
|
struct SpinWaker {
|
||||||
repeat: AtomicBool,
|
repeat: AtomicBool,
|
||||||
loud: bool,
|
|
||||||
}
|
}
|
||||||
impl Wake for SpinWaker {
|
impl Wake for SpinWaker {
|
||||||
fn wake(self: Arc<Self>) {
|
fn wake(self: Arc<Self>) {
|
||||||
self.repeat.store(true, Ordering::SeqCst);
|
self.repeat.store(true, Ordering::SeqCst);
|
||||||
if self.loud {
|
if WAKE_LODUD.with_borrow(|k| *k) {
|
||||||
eprintln!("Triggered repeat for spin_on")
|
eprintln!("{Label} Triggered repeat for spin_on")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,11 +171,13 @@ impl Wake for SpinWaker {
|
|||||||
/// keeps synchronously waking itself. This is useful for deterministic tests
|
/// keeps synchronously waking itself. This is useful for deterministic tests
|
||||||
/// that don't contain side effects or threading.
|
/// that don't contain side effects or threading.
|
||||||
///
|
///
|
||||||
|
/// Use [spin_on_loud] to get messages on wake for debugging
|
||||||
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// If the future doesn't wake itself and doesn't settle.
|
/// If the future doesn't wake itself and doesn't settle.
|
||||||
pub fn spin_on<Fut: Future>(loud: bool, f: Fut) -> Fut::Output {
|
pub fn spin_on<Fut: Future>(f: Fut) -> Fut::Output {
|
||||||
let spin_waker = Arc::new(SpinWaker { repeat: AtomicBool::new(false), loud });
|
let spin_waker = Arc::new(SpinWaker { repeat: AtomicBool::new(false) });
|
||||||
let mut f = pin!(f);
|
let mut f = pin!(f);
|
||||||
let waker = spin_waker.clone().into();
|
let waker = spin_waker.clone().into();
|
||||||
let mut cx = Context::from_waker(&waker);
|
let mut cx = Context::from_waker(&waker);
|
||||||
|
|||||||
@@ -354,7 +354,7 @@ struct ReplySub {
|
|||||||
cb: oneshot::Sender<ReplyRecord>,
|
cb: oneshot::Sender<ReplyRecord>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct IoClient {
|
pub struct IoClient {
|
||||||
output: IoLock<dyn AsyncWrite>,
|
output: IoLock<dyn AsyncWrite>,
|
||||||
id: Rc<RefCell<u64>>,
|
id: Rc<RefCell<u64>>,
|
||||||
subscribe: Rc<Sender<ReplySub>>,
|
subscribe: Rc<Sender<ReplySub>>,
|
||||||
@@ -491,30 +491,33 @@ impl MsgWriter for IoNotifWriter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CommCtx {
|
pub struct CommCx {
|
||||||
exit: Sender<()>,
|
exit: Sender<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommCtx {
|
impl CommCx {
|
||||||
pub async fn exit(self) -> io::Result<()> {
|
pub async fn exit(self) -> io::Result<()> {
|
||||||
self.exit.clone().send(()).await.expect("quit channel dropped");
|
self.exit.clone().send(()).await.expect("quit channel dropped");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct IoComm {
|
||||||
|
pub client: IoClient,
|
||||||
|
pub cx: CommCx,
|
||||||
|
pub srv: IoCommServer,
|
||||||
|
}
|
||||||
|
|
||||||
/// Establish bidirectional request-notification communication over a duplex
|
/// Establish bidirectional request-notification communication over a duplex
|
||||||
/// channel. The returned [IoClient] can be used for notifications immediately,
|
/// channel. The returned [IoClient] can be used for notifications immediately,
|
||||||
/// but requests can only be received while the future is running. The future
|
/// but requests can only be received while the future is running. The future
|
||||||
/// will only resolve when [CommCtx::exit] is called.
|
/// will only resolve when [CommCtx::exit] is called.
|
||||||
pub fn io_comm(
|
pub fn io_comm(o: Pin<Box<dyn AsyncWrite>>, i: Pin<Box<dyn AsyncRead>>) -> IoComm {
|
||||||
o: Pin<Box<dyn AsyncWrite>>,
|
|
||||||
i: Pin<Box<dyn AsyncRead>>,
|
|
||||||
) -> (impl Client + 'static, CommCtx, IoCommServer) {
|
|
||||||
let i = Rc::new(Mutex::new(i));
|
let i = Rc::new(Mutex::new(i));
|
||||||
let o = Rc::new(Mutex::new(o));
|
let o = Rc::new(Mutex::new(o));
|
||||||
let (onsub, client) = IoClient::new(o.clone());
|
let (onsub, client) = IoClient::new(o.clone());
|
||||||
let (exit, onexit) = channel(1);
|
let (exit, onexit) = channel(1);
|
||||||
(client, CommCtx { exit }, IoCommServer { o, i, onsub, onexit })
|
IoComm { client, cx: CommCx { exit }, srv: IoCommServer { o, i, onsub, onexit } }
|
||||||
}
|
}
|
||||||
pub struct IoCommServer {
|
pub struct IoCommServer {
|
||||||
o: Rc<Mutex<Pin<Box<dyn AsyncWrite>>>>,
|
o: Rc<Mutex<Pin<Box<dyn AsyncWrite>>>>,
|
||||||
@@ -657,53 +660,61 @@ impl IoCommServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
pub mod test {
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
use futures::{FutureExt, SinkExt, StreamExt, join, select};
|
use futures::future::{join3, select};
|
||||||
|
use futures::{SinkExt, StreamExt};
|
||||||
use orchid_api_derive::{Coding, Hierarchy};
|
use orchid_api_derive::{Coding, Hierarchy};
|
||||||
use orchid_api_traits::Request;
|
use orchid_api_traits::Request;
|
||||||
use orchid_async_utils::debug::{spin_on, with_label};
|
use orchid_async_utils::debug::{spin_on, with_label};
|
||||||
use unsync_pipe::pipe;
|
use unsync_pipe::pipe;
|
||||||
|
|
||||||
use crate::comm::{ClientExt, MsgReaderExt, ReqReaderExt, io_comm};
|
use super::*;
|
||||||
use crate::with_stash;
|
use crate::with_stash;
|
||||||
|
|
||||||
|
pub fn test_pair() -> (IoComm, IoComm) {
|
||||||
|
let (right_in, left_out) = pipe(1024);
|
||||||
|
let (left_in, right_out) = pipe(1024);
|
||||||
|
(
|
||||||
|
io_comm(Box::pin(left_in), Box::pin(left_out)),
|
||||||
|
io_comm(Box::pin(right_in), Box::pin(right_out)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn listen_no_ingress(srv: IoCommServer) {
|
||||||
|
srv
|
||||||
|
.listen(
|
||||||
|
async |_| panic!("Not expecting ingress notif"),
|
||||||
|
async |_| panic!("Not expecting ingress req"),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Coding, Hierarchy)]
|
#[derive(Clone, Debug, PartialEq, Coding, Hierarchy)]
|
||||||
#[extendable]
|
#[extendable]
|
||||||
struct TestNotif(u64);
|
struct TestNotif(u64);
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn notification() {
|
fn notification() {
|
||||||
spin_on(false, async {
|
let (left, right) = test_pair();
|
||||||
let (in1, out2) = pipe(1024);
|
|
||||||
let (in2, out1) = pipe(1024);
|
|
||||||
let (received, mut on_receive) = mpsc::channel(2);
|
let (received, mut on_receive) = mpsc::channel(2);
|
||||||
let (_, recv_ctx, recv_srv) = io_comm(Box::pin(in2), Box::pin(out2));
|
let right_srv_fut = right.srv.listen(
|
||||||
let (sender, ..) = io_comm(Box::pin(in1), Box::pin(out1));
|
|
||||||
join!(
|
|
||||||
async {
|
|
||||||
recv_srv
|
|
||||||
.listen(
|
|
||||||
async |notif| {
|
async |notif| {
|
||||||
received.clone().send(notif.read::<TestNotif>().await?).await.unwrap();
|
received.clone().send(notif.read::<TestNotif>().await?).await.unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
async |_| panic!("Should receive notif, not request"),
|
async |_| panic!("Should receive notif, not request"),
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
},
|
|
||||||
async {
|
|
||||||
sender.notify(TestNotif(3)).await.unwrap();
|
|
||||||
assert_eq!(on_receive.next().await, Some(TestNotif(3)));
|
|
||||||
sender.notify(TestNotif(4)).await.unwrap();
|
|
||||||
assert_eq!(on_receive.next().await, Some(TestNotif(4)));
|
|
||||||
recv_ctx.exit().await.unwrap();
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
})
|
spin_on(join(async { right_srv_fut.await.unwrap() }, async {
|
||||||
|
left.client.notify(TestNotif(3)).await.unwrap();
|
||||||
|
assert_eq!(on_receive.next().await, Some(TestNotif(3)));
|
||||||
|
left.client.notify(TestNotif(4)).await.unwrap();
|
||||||
|
assert_eq!(on_receive.next().await, Some(TestNotif(4)));
|
||||||
|
right.cx.exit().await.unwrap();
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
@@ -715,57 +726,36 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn request() {
|
fn request() {
|
||||||
spin_on(false, async {
|
let (left, right) = test_pair();
|
||||||
let (in1, out2) = pipe(1024);
|
let right_srv_fut = right.srv.listen(
|
||||||
let (in2, out1) = pipe(1024);
|
|
||||||
let (_, srv_ctx, srv) = io_comm(Box::pin(in2), Box::pin(out2));
|
|
||||||
let (client, client_ctx, client_srv) = io_comm(Box::pin(in1), Box::pin(out1));
|
|
||||||
join!(
|
|
||||||
async {
|
|
||||||
srv
|
|
||||||
.listen(
|
|
||||||
async |_| panic!("No notifs expected"),
|
async |_| panic!("No notifs expected"),
|
||||||
async |mut req| {
|
async |mut req| {
|
||||||
let val = req.read_req::<DummyRequest>().await?;
|
let val = req.read_req::<DummyRequest>().await?;
|
||||||
req.reply(&val, val.0 + 1).await
|
req.reply(&val, val.0 + 1).await
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
.await
|
let left_srv_fut = left.srv.listen(
|
||||||
.unwrap()
|
|
||||||
},
|
|
||||||
async {
|
|
||||||
client_srv
|
|
||||||
.listen(
|
|
||||||
async |_| panic!("Not expecting ingress notif"),
|
async |_| panic!("Not expecting ingress notif"),
|
||||||
async |_| panic!("Not expecting ingress req"),
|
async |_| panic!("Not expecting ingress req"),
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
},
|
|
||||||
async {
|
|
||||||
let response = client.request(DummyRequest(5)).await.unwrap();
|
|
||||||
assert_eq!(response, 6);
|
|
||||||
srv_ctx.exit().await.unwrap();
|
|
||||||
client_ctx.exit().await.unwrap();
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
})
|
spin_on(join3(
|
||||||
|
async { right_srv_fut.await.unwrap() },
|
||||||
|
async { left_srv_fut.await.unwrap() },
|
||||||
|
async {
|
||||||
|
let response = left.client.request(DummyRequest(5)).await.unwrap();
|
||||||
|
assert_eq!(response, 6);
|
||||||
|
right.cx.exit().await.unwrap();
|
||||||
|
left.cx.exit().await.unwrap();
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exit() {
|
fn exit() {
|
||||||
spin_on(false, async {
|
let (left, right) = test_pair();
|
||||||
let (input1, output1) = pipe(1024);
|
let reply_context = RefCell::new(Some(right.cx));
|
||||||
let (input2, output2) = pipe(1024);
|
let (exit, onexit) = oneshot::channel::<()>();
|
||||||
let (reply_client, reply_context, reply_server) =
|
let right_srv_fut = right.srv.listen(
|
||||||
io_comm(Box::pin(input1), Box::pin(output2));
|
|
||||||
let (req_client, req_context, req_server) = io_comm(Box::pin(input2), Box::pin(output1));
|
|
||||||
let reply_context = RefCell::new(Some(reply_context));
|
|
||||||
let (exit, onexit) = futures::channel::oneshot::channel::<()>();
|
|
||||||
join!(
|
|
||||||
with_label("reply", async move {
|
|
||||||
reply_server
|
|
||||||
.listen(
|
|
||||||
async |hand| {
|
async |hand| {
|
||||||
let _notif = hand.read::<TestNotif>().await.unwrap();
|
let _notif = hand.read::<TestNotif>().await.unwrap();
|
||||||
let context = reply_context.borrow_mut().take().unwrap();
|
let context = reply_context.borrow_mut().take().unwrap();
|
||||||
@@ -776,43 +766,34 @@ mod test {
|
|||||||
let req = hand.read_req::<DummyRequest>().await?;
|
let req = hand.read_req::<DummyRequest>().await?;
|
||||||
hand.reply(&req, req.0 + 1).await
|
hand.reply(&req, req.0 + 1).await
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
.await
|
let left_srv_fut = left.srv.listen(
|
||||||
.unwrap();
|
|
||||||
exit.send(()).unwrap();
|
|
||||||
let _client = reply_client;
|
|
||||||
}),
|
|
||||||
with_label("client", async move {
|
|
||||||
req_server
|
|
||||||
.listen(
|
|
||||||
async |_| panic!("Only the other server expected notifs"),
|
async |_| panic!("Only the other server expected notifs"),
|
||||||
async |_| panic!("Only the other server expected requests"),
|
async |_| panic!("Only the other server expected requests"),
|
||||||
)
|
);
|
||||||
.await
|
spin_on(join3(
|
||||||
.unwrap();
|
with_label("reply", async move {
|
||||||
let _ctx = req_context;
|
right_srv_fut.await.unwrap();
|
||||||
|
exit.send(()).unwrap();
|
||||||
|
let _client = right.client;
|
||||||
|
}),
|
||||||
|
with_label("client", async move {
|
||||||
|
left_srv_fut.await.unwrap();
|
||||||
|
let _ctx = left.cx;
|
||||||
}),
|
}),
|
||||||
async move {
|
async move {
|
||||||
req_client.request(DummyRequest(0)).await.unwrap();
|
left.client.request(DummyRequest(0)).await.unwrap();
|
||||||
req_client.notify(TestNotif(0)).await.unwrap();
|
left.client.notify(TestNotif(0)).await.unwrap();
|
||||||
onexit.await.unwrap();
|
onexit.await.unwrap();
|
||||||
}
|
},
|
||||||
)
|
));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn timely_cancel() {
|
fn timely_cancel() {
|
||||||
spin_on(false, async {
|
let (left, right) = test_pair();
|
||||||
let (in1, out2) = pipe(1024);
|
|
||||||
let (in2, out1) = pipe(1024);
|
|
||||||
let (wait_in, mut wait_out) = mpsc::channel(0);
|
let (wait_in, mut wait_out) = mpsc::channel(0);
|
||||||
let (_, srv_ctx, srv) = io_comm(Box::pin(in2), Box::pin(out2));
|
let right_srv_fut = right.srv.listen(
|
||||||
let (client, client_ctx, client_srv) = io_comm(Box::pin(in1), Box::pin(out1));
|
|
||||||
join!(
|
|
||||||
with_label("server", async {
|
|
||||||
srv
|
|
||||||
.listen(
|
|
||||||
async |_| panic!("No notifs expected"),
|
async |_| panic!("No notifs expected"),
|
||||||
async |mut req| {
|
async |mut req| {
|
||||||
let _ = req.read_req::<DummyRequest>().await?;
|
let _ = req.read_req::<DummyRequest>().await?;
|
||||||
@@ -822,33 +803,67 @@ mod test {
|
|||||||
// the loop
|
// the loop
|
||||||
futures::future::pending().await
|
futures::future::pending().await
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
.await
|
spin_on(join3(
|
||||||
.unwrap();
|
with_label("server", async { right_srv_fut.await.unwrap() }),
|
||||||
}),
|
with_label("client", listen_no_ingress(left.srv)),
|
||||||
with_label("client", async {
|
with_label(
|
||||||
client_srv
|
"outer_stash",
|
||||||
.listen(
|
|
||||||
async |_| panic!("Not expecting ingress notif"),
|
|
||||||
async |_| panic!("Not expecting ingress req"),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}),
|
|
||||||
with_stash(async {
|
with_stash(async {
|
||||||
with_stash(async {
|
with_stash(async {
|
||||||
select! {
|
select(
|
||||||
_ = client.request(DummyRequest(5)).fuse() => {
|
Box::pin(async {
|
||||||
panic!("This one should not run")
|
left.client.request(DummyRequest(5)).await.unwrap();
|
||||||
},
|
panic!("This one should not run");
|
||||||
rep = wait_out.next() => rep.expect("something?"),
|
}),
|
||||||
}
|
Box::pin(async {
|
||||||
|
wait_out.next().await.expect("something?");
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
srv_ctx.exit().await.unwrap();
|
right.cx.exit().await.unwrap();
|
||||||
client_ctx.exit().await.unwrap();
|
left.cx.exit().await.unwrap();
|
||||||
})
|
}),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn late_cancel() {
|
||||||
|
let (left, right) = test_pair();
|
||||||
|
let (send, mut recv) = mpsc::channel(0);
|
||||||
|
let right_srv_fut = right.srv.listen(
|
||||||
|
async |_| panic!("Expected a request"),
|
||||||
|
async |mut req| {
|
||||||
|
req.read_req::<DummyRequest>().await?;
|
||||||
|
let mut reply_writer = req.start_reply().await?;
|
||||||
|
let (stop_wait, wait) = oneshot::channel();
|
||||||
|
send.clone().send(stop_wait).await.unwrap();
|
||||||
|
wait.await.unwrap();
|
||||||
|
(1 as <DummyRequest as Request>::Response).encode(reply_writer.writer()).await?;
|
||||||
|
reply_writer.finish().await
|
||||||
|
},
|
||||||
);
|
);
|
||||||
})
|
spin_on(join3(
|
||||||
|
async { right_srv_fut.await.unwrap() },
|
||||||
|
with_label("client", listen_no_ingress(left.srv)),
|
||||||
|
async {
|
||||||
|
with_stash(Box::pin(async {
|
||||||
|
select(
|
||||||
|
Box::pin(async {
|
||||||
|
left.client.request(DummyRequest(5)).await.unwrap();
|
||||||
|
panic!("This one should not run");
|
||||||
|
}),
|
||||||
|
Box::pin(async { recv.next().await.unwrap().send(()) }),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}))
|
||||||
|
.await;
|
||||||
|
right.cx.exit().await.unwrap();
|
||||||
|
left.cx.exit().await.unwrap();
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,9 +148,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn run_stashed_future() {
|
fn run_stashed_future() {
|
||||||
let (mut send, recv) = mpsc::channel(0);
|
let (mut send, recv) = mpsc::channel(0);
|
||||||
spin_on(
|
spin_on(join(
|
||||||
false,
|
|
||||||
join(
|
|
||||||
with_stash(async {
|
with_stash(async {
|
||||||
let mut send1 = send.clone();
|
let mut send1 = send.clone();
|
||||||
stash(async move {
|
stash(async move {
|
||||||
@@ -176,13 +174,8 @@ mod test {
|
|||||||
async {
|
async {
|
||||||
let mut results = recv.take(6).collect::<Vec<_>>().await;
|
let mut results = recv.take(6).collect::<Vec<_>>().await;
|
||||||
results.sort();
|
results.sort();
|
||||||
assert_eq!(
|
assert_eq!(&results, &[1, 2, 3, 4, 5, 6], "all variations completed in unspecified order");
|
||||||
&results,
|
|
||||||
&[1, 2, 3, 4, 5, 6],
|
|
||||||
"all variations completed in unspecified order"
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use itertools::Itertools;
|
|||||||
use orchid_api_traits::{Decode, Encode, Request, UnderRoot, enc_vec};
|
use orchid_api_traits::{Decode, Encode, Request, UnderRoot, enc_vec};
|
||||||
use orchid_async_utils::{Handle, JoinError, to_task};
|
use orchid_async_utils::{Handle, JoinError, to_task};
|
||||||
use orchid_base::{
|
use orchid_base::{
|
||||||
Client, ClientExt, CommCtx, Comment, MsgReader, MsgReaderExt, ReqHandleExt, ReqReaderExt,
|
Client, ClientExt, CommCx, Comment, IoComm, MsgReader, MsgReaderExt, ReqHandleExt, ReqReaderExt,
|
||||||
Snippet, Sym, TokenVariant, Witness, char_filter_match, char_filter_union, es, io_comm, is, log,
|
Snippet, Sym, TokenVariant, Witness, char_filter_match, char_filter_union, es, io_comm, is, log,
|
||||||
mk_char_filter, try_with_reporter, ttv_from_api, with_interner, with_logger, with_stash,
|
mk_char_filter, try_with_reporter, ttv_from_api, with_interner, with_logger, with_stash,
|
||||||
};
|
};
|
||||||
@@ -37,7 +37,7 @@ use crate::{
|
|||||||
|
|
||||||
task_local::task_local! {
|
task_local::task_local! {
|
||||||
static CLIENT: Rc<dyn Client>;
|
static CLIENT: Rc<dyn Client>;
|
||||||
static CTX: Rc<RefCell<Option<CommCtx>>>;
|
static CTX: Rc<RefCell<Option<CommCx>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_client() -> Rc<dyn Client> { CLIENT.get() }
|
fn get_client() -> Rc<dyn Client> { CLIENT.get() }
|
||||||
@@ -51,7 +51,7 @@ pub async fn exit() {
|
|||||||
|
|
||||||
/// Set the client used for global [request] and [notify] functions within the
|
/// Set the client used for global [request] and [notify] functions within the
|
||||||
/// runtime of this future
|
/// runtime of this future
|
||||||
pub async fn with_comm<F: Future>(c: Rc<dyn Client>, ctx: CommCtx, fut: F) -> F::Output {
|
pub async fn with_comm<F: Future>(c: Rc<dyn Client>, ctx: CommCx, fut: F) -> F::Output {
|
||||||
CLIENT.scope(c, CTX.scope(Rc::new(RefCell::new(Some(ctx))), fut)).await
|
CLIENT.scope(c, CTX.scope(Rc::new(RefCell::new(Some(ctx))), fut)).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,9 +194,9 @@ impl ExtensionBuilder {
|
|||||||
ctx.output.as_mut().flush().await.unwrap();
|
ctx.output.as_mut().flush().await.unwrap();
|
||||||
let logger1 = LoggerImpl::from_api(&host_header.logger);
|
let logger1 = LoggerImpl::from_api(&host_header.logger);
|
||||||
let logger2 = logger1.clone();
|
let logger2 = logger1.clone();
|
||||||
let (client, comm_ctx, extension_srv) = io_comm(ctx.output, ctx.input);
|
let IoComm { client, cx: comm_ctx, srv } = io_comm(ctx.output, ctx.input);
|
||||||
// this future will be ready once the extension cleanly exits
|
// this future will be ready once the extension cleanly exits
|
||||||
let extension_fut = extension_srv.listen(
|
let extension_fut = srv.listen(
|
||||||
async |n: Box<dyn MsgReader<'_>>| {
|
async |n: Box<dyn MsgReader<'_>>| {
|
||||||
let notif = n.read().await.unwrap();
|
let notif = n.read().await.unwrap();
|
||||||
match notif {
|
match notif {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use hashbrown::{HashMap, HashSet};
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_api_traits::{Decode, Encode, Request};
|
use orchid_api_traits::{Decode, Encode, Request};
|
||||||
use orchid_base::{
|
use orchid_base::{
|
||||||
AtomRepr, Client, ClientExt, CommCtx, FmtCtxImpl, Format, IStr, IStrv, MsgReaderExt, Pos,
|
AtomRepr, Client, ClientExt, CommCx, FmtCtxImpl, Format, IStr, IStrv, IoComm, MsgReaderExt, Pos,
|
||||||
ReqHandleExt, ReqReaderExt, Sym, Witness, es, ev, io_comm, is, iv, log, stash, with_stash,
|
ReqHandleExt, ReqReaderExt, Sym, Witness, es, ev, io_comm, is, iv, log, stash, with_stash,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ pub struct ReqPair<R: Request>(R, Sender<R::Response>);
|
|||||||
pub struct ExtensionData {
|
pub struct ExtensionData {
|
||||||
name: String,
|
name: String,
|
||||||
ctx: Ctx,
|
ctx: Ctx,
|
||||||
comm_cx: Option<CommCtx>,
|
comm_cx: Option<CommCx>,
|
||||||
join_ext: Option<Box<dyn JoinHandle>>,
|
join_ext: Option<Box<dyn JoinHandle>>,
|
||||||
client: Rc<dyn Client>,
|
client: Rc<dyn Client>,
|
||||||
systems: Vec<SystemCtor>,
|
systems: Vec<SystemCtor>,
|
||||||
@@ -82,12 +82,12 @@ impl Extension {
|
|||||||
let header2 = header.clone();
|
let header2 = header.clone();
|
||||||
Ok(Self(Rc::new_cyclic(|weak: &Weak<ExtensionData>| {
|
Ok(Self(Rc::new_cyclic(|weak: &Weak<ExtensionData>| {
|
||||||
// context not needed because exit is extension-initiated
|
// context not needed because exit is extension-initiated
|
||||||
let (client, comm_cx, comm) = io_comm(init.input, init.output);
|
let IoComm { client, cx: comm_cx, srv } = io_comm(init.input, init.output);
|
||||||
let weak2 = weak;
|
let weak2 = weak;
|
||||||
let weak = weak.clone();
|
let weak = weak.clone();
|
||||||
let ctx2 = ctx.clone();
|
let ctx2 = ctx.clone();
|
||||||
let join_ext = ctx.clone().spawn(Duration::ZERO, async move {
|
let join_ext = ctx.clone().spawn(Duration::ZERO, async move {
|
||||||
comm
|
srv
|
||||||
.listen(
|
.listen(
|
||||||
async |reader| {
|
async |reader| {
|
||||||
with_stash(async {
|
with_stash(async {
|
||||||
|
|||||||
@@ -47,6 +47,9 @@
|
|||||||
"--logs=msg>stderr",
|
"--logs=msg>stderr",
|
||||||
"exec",
|
"exec",
|
||||||
"1 + 1"
|
"1 + 1"
|
||||||
|
],
|
||||||
|
"initCommands": [
|
||||||
|
"settings set target.disable-aslr false"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user