notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

commit 5cdf3698d2f64c75332894307ce8f93d57bcbfaa
parent 7bb871d3776873fe13b1b9f7891961fa44236956
Author: kernelkind <kernelkind@gmail.com>
Date:   Thu, 10 Apr 2025 16:37:28 -0400

introduce & use `JobPool`

Signed-off-by: kernelkind <kernelkind@gmail.com>

Diffstat:
Mcrates/notedeck/src/app.rs | 5+++++
Mcrates/notedeck/src/context.rs | 3++-
Acrates/notedeck/src/job_pool.rs | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/notedeck/src/lib.rs | 2++
4 files changed, 108 insertions(+), 1 deletion(-)

diff --git a/crates/notedeck/src/app.rs b/crates/notedeck/src/app.rs @@ -1,6 +1,7 @@ use crate::persist::{AppSizeHandler, ZoomHandler}; use crate::wallet::GlobalWallet; use crate::zaps::Zaps; +use crate::JobPool; use crate::{ frame_history::FrameHistory, AccountStorage, Accounts, AppContext, Args, DataPath, DataPathType, Directory, Images, NoteAction, NoteCache, RelayDebugView, ThemeHandler, @@ -43,6 +44,7 @@ pub struct Notedeck { clipboard: Clipboard, zaps: Zaps, frame_history: FrameHistory, + job_pool: JobPool, } /// Our chrome, which is basically nothing @@ -219,6 +221,7 @@ impl Notedeck { let global_wallet = GlobalWallet::new(&path); let zaps = Zaps::default(); + let job_pool = JobPool::default(); Self { ndb, @@ -238,6 +241,7 @@ impl Notedeck { frame_history: FrameHistory::default(), clipboard: Clipboard::new(None), zaps, + job_pool, } } @@ -261,6 +265,7 @@ impl Notedeck { clipboard: &mut self.clipboard, zaps: &mut self.zaps, frame_history: &mut self.frame_history, + job_pool: &mut self.job_pool, } } diff --git a/crates/notedeck/src/context.rs b/crates/notedeck/src/context.rs @@ -1,6 +1,6 @@ use crate::{ frame_history::FrameHistory, wallet::GlobalWallet, zaps::Zaps, Accounts, Args, DataPath, - Images, NoteCache, ThemeHandler, UnknownIds, + Images, JobPool, NoteCache, ThemeHandler, UnknownIds, }; use egui_winit::clipboard::Clipboard; @@ -23,4 +23,5 @@ pub struct AppContext<'a> { pub clipboard: &'a mut Clipboard, pub zaps: &'a mut Zaps, pub frame_history: &'a mut FrameHistory, + pub job_pool: &'a mut JobPool, } diff --git a/crates/notedeck/src/job_pool.rs b/crates/notedeck/src/job_pool.rs @@ -0,0 +1,99 @@ +use std::{ + future::Future, + sync::{ + mpsc::{self, Sender}, + Arc, Mutex, + }, +}; +use tokio::sync::oneshot; + +type Job = Box<dyn FnOnce() + Send + 'static>; + +pub struct JobPool { + tx: Sender<Job>, +} + +impl Default for JobPool { + fn default() -> Self { + JobPool::new(2) + } +} + +impl JobPool { + pub fn new(num_threads: usize) -> Self { + let (tx, rx) = mpsc::channel::<Job>(); + + let arc_rx = Arc::new(Mutex::new(rx)); + for _ in 0..num_threads { + let arc_rx_clone = arc_rx.clone(); + std::thread::spawn(move || loop { + let job = { + let Ok(unlocked) = arc_rx_clone.lock() else { + continue; + }; + let Ok(job) = unlocked.recv() else { + continue; + }; + + job + }; + + job(); + }); + } + + Self { tx } + } + + pub fn schedule<F, T>(&self, job: F) -> impl Future<Output = T> + where + F: FnOnce() -> T + Send + 'static, + T: Send + 'static, + { + let (tx_result, rx_result) = oneshot::channel::<T>(); + + let job = Box::new(move || { + let output = job(); + let _ = tx_result.send(output); + }); + + self.tx + .send(job) + .expect("receiver should not be deallocated"); + + async move { + rx_result.await.unwrap_or_else(|_| { + panic!("Worker thread or channel dropped before returning the result.") + }) + } + } +} + +#[cfg(test)] +mod tests { + use crate::job_pool::JobPool; + + fn test_fn(a: u32, b: u32) -> u32 { + a + b + } + + #[tokio::test] + async fn test() { + let pool = JobPool::default(); + + // Now each job can return different T + let future_str = pool.schedule(|| -> String { "hello from string job".into() }); + + let a = 5; + let b = 6; + let future_int = pool.schedule(move || -> u32 { test_fn(a, b) }); + + println!("(Meanwhile we can do more async work) ..."); + + let s = future_str.await; + let i = future_int.await; + + println!("Got string: {:?}", s); + println!("Got integer: {}", i); + } +} diff --git a/crates/notedeck/src/lib.rs b/crates/notedeck/src/lib.rs @@ -9,6 +9,7 @@ pub mod filter; pub mod fonts; mod frame_history; mod imgcache; +mod job_pool; mod muted; pub mod name; pub mod note; @@ -43,6 +44,7 @@ pub use imgcache::{ Animation, GifState, GifStateMap, ImageFrame, Images, MediaCache, MediaCacheType, MediaCacheValue, TextureFrame, TexturedImage, }; +pub use job_pool::JobPool; pub use muted::{MuteFun, Muted}; pub use name::NostrName; pub use note::{