Index: Cargo.toml ================================================================== --- Cargo.toml +++ Cargo.toml @@ -1,8 +1,8 @@ [package] name = "ump-ng-server" -version = "0.1.1" +version = "0.1.2" edition = "2021" license = "0BSD" categories = [ "concurrency", "asynchronous" ] keywords = [ "channel", "threads", "sync", "message-passing" ] repository = "https://repos.qrnch.tech/pub/ump-ng-server" Index: src/lib.rs ================================================================== --- src/lib.rs +++ src/lib.rs @@ -40,17 +40,25 @@ #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] pub mod task; pub mod thread; -pub use ump_ng::{self, channel, Client, MsgType, ReplyContext, WeakClient}; +pub use ump_ng::{ + self, channel, Client, MsgType, ReplyContext, Server, WeakClient +}; -pub use thread::{spawn as spawn_thread, Handler as ThreadedHandler}; +pub use thread::{ + spawn as spawn_thread, spawn_preinit as spawn_thread_preinit, + Handler as ThreadedHandler +}; #[cfg(feature = "tokio")] #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] -pub use task::{spawn as spawn_task, Handler as AsyncHandler}; +pub use task::{ + spawn as spawn_task, spawn_preinit as spawn_task_preinit, + Handler as AsyncHandler +}; #[cfg(feature = "tokio")] #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] pub use async_trait::async_trait; Index: src/task.rs ================================================================== --- src/task.rs +++ src/task.rs @@ -2,11 +2,11 @@ use tokio::task::{self, JoinHandle}; use async_trait::async_trait; -use super::{channel, Client, MsgType, ReplyContext}; +use super::{channel, Client, MsgType, ReplyContext, Server}; #[async_trait] pub trait Handler { /// Optional initialization callback. /// @@ -80,6 +80,42 @@ }); (client, jh) } + +/// Spawn a task to run a pre-initialized handler. +/// +/// It is assumed that the caller has initialized the handler, thus its +/// `init()` method will not be called. +pub fn spawn_preinit( + server: Server, + mut handler: impl Handler + Send + 'static +) -> JoinHandle> +where + P: 'static + Send, + S: 'static + Send, + R: 'static + Send, + E: 'static + Send, + RV: 'static + Send +{ + task::spawn(async move { + let ret = loop { + match server.async_wait().await { + Ok(msg) => match msg { + MsgType::Put(m) => match handler.post(m).await { + ControlFlow::Continue(_) => {} + ControlFlow::Break(rv) => break Some(rv) + }, + MsgType::Request(m, rctx) => match handler.req(m, rctx).await { + ControlFlow::Continue(_) => {} + ControlFlow::Break(rv) => break Some(rv) + } + }, + Err(_) => break None + } + }; + handler.term(ret) + }) +} + // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : Index: src/thread.rs ================================================================== --- src/thread.rs +++ src/thread.rs @@ -1,11 +1,11 @@ use std::{ ops::ControlFlow, thread::{self, JoinHandle} }; -use super::{channel, Client, MsgType, ReplyContext}; +use super::{channel, Client, MsgType, ReplyContext, Server}; pub trait Handler { /// Optional initialization callback. /// /// This is called on the dispatcher thread before the main message @@ -74,6 +74,71 @@ }); (client, jh) } + +/// Spawn a thread to run a pre-initialized handler. +/// +/// It is assumed that the caller has initialized the handler, thus its +/// `init()` method will not be called. +/// +/// ``` +/// use std::ops::ControlFlow; +/// use ump_ng_server::{ump_ng, spawn_thread_preinit, ThreadedHandler, +/// ReplyContext}; +/// let (server, client) = ump_ng::channel::<(), (), (), ()>(); +/// +/// struct MyHandler { +/// wclnt: ump_ng::WeakClient<(), (), (), ()> +/// } +/// impl ThreadedHandler<(), (), (), (), ()> for MyHandler { +/// fn post(&mut self, _: ()) -> ControlFlow<(), ()> { +/// ControlFlow::Continue(()) +/// } +/// fn req(&mut self, _: (), rctx: ReplyContext<(), ()>) +/// -> ControlFlow<(), ()> { +/// ControlFlow::Continue(()) +/// } +/// } +/// let handler = MyHandler { +/// wclnt: client.weak() +/// }; +/// let jh = spawn_thread_preinit(server, handler); +/// +/// // drop client to force dispatch loop to terminate +/// drop(client); +/// +/// jh.join(); +/// ``` +pub fn spawn_preinit( + server: Server, + mut handler: impl Handler + Send + 'static +) -> JoinHandle> +where + P: 'static + Send, + S: 'static + Send, + R: 'static + Send, + E: 'static + Send, + RV: 'static + Send +{ + thread::spawn(move || { + let ret = loop { + match server.wait() { + Ok(msg) => match msg { + MsgType::Put(m) => match handler.post(m) { + ControlFlow::Continue(_) => {} + ControlFlow::Break(rv) => break Some(rv) + }, + MsgType::Request(m, rctx) => match handler.req(m, rctx) { + ControlFlow::Continue(_) => {} + ControlFlow::Break(rv) => break Some(rv) + } + }, + Err(_) => break None + } + }; + handler.term(ret) + }) +} + // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : Index: www/changelog.md ================================================================== --- www/changelog.md +++ www/changelog.md @@ -1,17 +1,30 @@ # Change Log ## [Unreleased] -[Details](/vdiff?from=ump-ng-server-0.1.1&to=trunk) +[Details](/vdiff?from=ump-ng-server-0.1.2&to=trunk) ### Added ### Changed ### Removed +--- + +## [0.1.2] - 2024-01-21 + +[Details](/vdiff?from=ump-ng-server-0.1.1&to=ump-ng-server-0.1.2) + +### Added + +- There are new spawn thread/task functions (with the suffix `_preinit`) that + take in a ump-ng `Server` and assumes that the message handler has already + been initialized. This is useful if the handler itself needs contain a + (weak) client reference, and one does not wish to store it in an `Option`. + --- ## [0.1.1] - 2024-01-14 [Details](/vdiff?from=ump-ng-server-0.1.0&to=ump-ng-server-0.1.1) Index: www/index.md ================================================================== --- www/index.md +++ www/index.md @@ -8,11 +8,12 @@ The crate's documentation uses automatically generated feature labels, which currently requires nightly featuers. To build the documentation locally use: ``` -RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features +$ RUSTFLAGS="--cfg docsrs" RUSTDOCFLAGS="--cfg docsrs" \ +cargo +nightly doc --all-features ``` ## Change log