Hello World works

This commit is contained in:
2026-04-24 22:32:41 +00:00
parent 759497ee70
commit 883d56143f
23 changed files with 447 additions and 487 deletions

View File

@@ -13,11 +13,11 @@ async-once-cell = "0.5.4"
bound = "0.6.0"
derive_destructure = "1.0.0"
dyn-clone = "1.0.20"
futures = { version = "0.3.31", default-features = false, features = [
"std",
"async-await",
futures = { version = "0.3.32", default-features = false, features = [
"std",
"async-await",
] }
hashbrown = "0.16.1"
hashbrown = "0.17.0"
itertools = "0.14.0"
lazy_static = "1.5.0"
never = "0.1.0"
@@ -25,14 +25,14 @@ num-traits = "0.2.19"
orchid-api = { version = "0.1.0", path = "../orchid-api" }
orchid-api-derive = { version = "0.1.0", path = "../orchid-api-derive" }
orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" }
ordered-float = "5.1.0"
regex = "1.12.2"
rust-embed = "8.9.0"
ordered-float = "5.3.0"
regex = "1.12.3"
rust-embed = "8.11.0"
substack = "1.1.1"
trait-set = "0.3.0"
task-local = "0.1.0"
task-local = "0.1.1"
[dev-dependencies]
futures = "0.3.31"
rand = "0.10.0"
futures = "0.3.32"
rand = "0.10.1"
rand_chacha = "0.10.0"

View File

@@ -17,7 +17,7 @@ use futures::{
use hashbrown::HashMap;
use orchid_api_traits::{Decode, Encode, Request, UnderRoot};
use orchid_async_utils::debug::{PanicOnDrop, assert_no_drop};
use orchid_async_utils::{cancel_cleanup, local_set, to_task};
use orchid_async_utils::{Handle, cancel_cleanup, local_set, to_task};
use crate::{clone, finish_or_stash, stash, with_stash};
@@ -293,29 +293,35 @@ type IoGuard<T> = Bound<MutexGuard<'static, Pin<Box<T>>>, IoLock<T>>;
/// An incoming request. This holds a lock on the ingress channel.
pub struct IoReqReader {
prefix: u64,
id: u64,
read: IoGuard<dyn AsyncRead>,
o: Rc<Mutex<IoRef<dyn AsyncWrite>>>,
requests: Rc<RefCell<HashMap<u64, Handle<io::Result<()>>>>>,
}
impl ReqReader for IoReqReader {
fn reader(&mut self) -> Pin<&mut dyn AsyncRead> { self.read.as_mut() }
fn finish(self: Box<Self>) -> LocalBoxFuture<'static, Box<dyn ReqHandle>> {
Box::pin(async {
Box::new(IoReqHandle { prefix: self.prefix, write: self.o }) as Box<dyn ReqHandle>
Box::new(IoReqHandle { id: self.id, write: self.o, requests: self.requests })
as Box<dyn ReqHandle>
})
}
}
pub struct IoReqHandle {
prefix: u64,
id: u64,
write: IoLock<dyn AsyncWrite>,
requests: Rc<RefCell<HashMap<u64, Handle<io::Result<()>>>>>,
}
impl ReqHandle for IoReqHandle {
fn start_reply(self: Box<Self>) -> LocalBoxFuture<'static, io::Result<Box<dyn RepWriter>>> {
let write = self.write.clone();
Box::pin(async move {
let mut write = Bound::async_new(write, |l| l.lock()).await;
self.prefix.encode(write.as_mut()).await?;
self.requests.borrow_mut().remove(&self.id);
let mut prefix = self.id.to_be_bytes();
prefix[0] = 0x01;
write.write_all(&prefix).await?;
Ok(Box::new(IoRepWriter { write }) as Box<dyn RepWriter>)
})
}
@@ -552,8 +558,8 @@ impl IoCommServer {
}
});
let running_requests = RefCell::new(HashMap::new());
let (mut task_pool, fork_future) = local_set();
let running_requests = Rc::new(RefCell::new(HashMap::new()));
let (task_pool, fork_future) = local_set();
let mut fork_stream = pin!(fork_future.into_stream());
let mut pending_replies = HashMap::new();
'body: {
@@ -577,7 +583,7 @@ impl IoCommServer {
// ID 0 is reserved for single-fire notifications
Ok(Event::Input(0, read)) => {
let notif = &notif;
task_pool.spawn(notif(Box::new(IoMsgReader { _pd: PhantomData, read }))).await.unwrap();
task_pool.spawn(notif(Box::new(IoMsgReader { _pd: PhantomData, read })))
},
// non-zero IDs are associated with requests
Ok(Event::Input(id, read)) => {
@@ -588,21 +594,16 @@ impl IoCommServer {
match discr {
// request
0x00 => {
let (o, req, reqs) = (o.clone(), &req, &running_requests);
task_pool
.spawn(async move {
id_bytes[0] = 0x01;
let prefix = u64::from_be_bytes(id_bytes);
let reader = Box::new(IoReqReader { prefix, read, o });
let (fut, handle) = to_task(async { req(reader).await.map(|Receipt| ()) });
reqs.borrow_mut().insert(id, handle);
with_stash(fut).await;
// during this await the read guard is released and thus we may receive a
// cancel notification from below
Ok(())
})
.await
.unwrap();
let (o, req, reqs) = (o.clone(), &req, running_requests.clone());
task_pool.spawn(async move {
let reader = Box::new(IoReqReader { id, read, o, requests: reqs.clone() });
let (fut, handle) = to_task(async { req(reader).await.map(|Receipt| ()) });
reqs.borrow_mut().insert(id, handle);
with_stash(fut).await;
// during this await the read guard is released and thus we may receive a
// cancel notification from below
Ok(())
});
},
// response
0x01 => {
@@ -619,21 +620,18 @@ impl IoCommServer {
None => continue,
};
let (o, running_reqs) = (o.clone(), &running_requests);
task_pool
.spawn(async move {
// if the request starts writing back before our abort arrives, we only
// get this mutex once it's done
let mut write = o.lock().await;
// if the request is still in the store, the write didn't begin
let Some(_) = running_reqs.borrow_mut().remove(&id) else { return Ok(()) };
id_bytes[0] = 0x03;
let cancel_code = u64::from_be_bytes(id_bytes);
cancel_code.encode(write.as_mut()).await?;
write.flush().await?;
Ok(())
})
.await
.unwrap();
task_pool.spawn(async move {
// if the request starts writing back before our abort arrives, we only
// get this mutex once it's done
let mut write = o.lock().await;
// if the request is still in the store, the write didn't begin
let Some(_) = running_reqs.borrow_mut().remove(&id) else { return Ok(()) };
id_bytes[0] = 0x03;
let cancel_code = u64::from_be_bytes(id_bytes);
cancel_code.encode(write.as_mut()).await?;
write.flush().await?;
Ok(())
});
},
// stub reply for cancelled request
0x03 => {

View File

@@ -1,17 +1,23 @@
/// Cache a value in a [thread_local!]. Supports synchronous and asynchronous
/// initializers
///
/// Synchronous use-case:
/// ```
/// use std::rc::Rc;
/// #[macro_use]
/// use orchid_base::tl_cache;
/// let foo = tl_cache!(Rc<Vec<usize>>: Rc::new(vec![0; 1024]));
/// ```
///
/// Asynchronous use-case:
/// ```
/// #[macro_use]
/// use orchid_base::tl_cache;
///
/// // simple synchronous case
/// let foo = tl_cache!(Rc<Vec<usize>>: vec![0; 1024]);
/// async fn complex_operation(x: usize) -> usize { x + 1 }
/// async {
/// async fn complex_operation(x: usize) -> usize { x + 1 }
/// // async case
/// let bar = tl_cache!(async usize: complex_operation(0).await)
/// }
/// let bar = tl_cache!(async usize: complex_operation(0).await);
/// };
/// ```
#[macro_export]
macro_rules! tl_cache {