1use std::{
2 cell::RefCell,
3 collections::HashMap,
4 fmt::{Debug, Formatter},
5};
6
7use crossbeam_channel::Sender;
8
9use crate::{Notifier, Status, ThreadStatuses};
10
11pub struct Installer {
13 sender: Sender<(String, Status)>,
14 thread_statuses: ThreadStatuses,
15 ops: RefCell<HashMap<String, Box<dyn FnOnce() + Send>>>,
16}
17
18impl Installer {
19 pub(crate) fn new(thread_statuses: ThreadStatuses, sender: Sender<(String, Status)>) -> Self {
20 Self {
21 sender,
22 thread_statuses,
23 ops: RefCell::new(HashMap::new()),
24 }
25 }
26
27 pub(crate) fn into_ops(self) -> HashMap<String, Box<dyn FnOnce() + Send>> {
28 self.ops.take()
29 }
30
31 #[inline]
34 pub fn spawn<InstallFn, ThreadFn>(&self, name: &str, install: InstallFn)
35 where
36 InstallFn: FnOnce(Notifier) -> ThreadFn,
37 ThreadFn: FnOnce() + Send + 'static,
38 {
39 self.thread_statuses.register_thread(name, Status::New);
40 let sender = self.sender.clone();
41 let notifier = Notifier::new(name, sender);
42 let _previous = self
43 .ops
44 .borrow_mut()
45 .insert(String::from(name), Box::new(install(notifier)));
46 }
47}
48
49impl Debug for Installer {
50 #[inline]
51 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
52 f.debug_struct("Installer")
53 .field("sender", &self.sender)
54 .field("thread_statuses", &self.thread_statuses)
55 .finish_non_exhaustive()
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use std::sync::{
62 atomic::{AtomicBool, Ordering},
63 Arc,
64 };
65
66 use crossbeam_channel::unbounded;
67
68 use super::*;
69 use crate::Threadable;
70
71 struct Thread {
72 called: Arc<AtomicBool>,
73 }
74
75 impl Thread {
76 fn new() -> Self {
77 Self {
78 called: Arc::new(AtomicBool::new(false)),
79 }
80 }
81 }
82
83 impl Threadable for Thread {
84 fn install(&self, installer: &Installer) {
85 let called = Arc::clone(&self.called);
86 installer.spawn("name", |_| {
87 move || {
88 called.store(true, Ordering::Relaxed);
89 }
90 });
91 }
92 }
93
94 #[test]
95 fn test() {
96 let (sender, _receiver) = unbounded();
97 let installer = Installer::new(ThreadStatuses::new(), sender);
98
99 let thread = Thread::new();
100 thread.install(&installer);
101
102 let mut ops = installer.into_ops();
103 let func = ops.remove("name").unwrap();
104 func();
105
106 assert!(thread.called.load(Ordering::Acquire));
107 }
108
109 #[test]
110 fn debug() {
111 let (sender, _receiver) = unbounded();
112 let installer = Installer::new(ThreadStatuses::new(), sender);
113 assert_eq!(
114 format!("{installer:?}"),
115 "Installer { sender: Sender { .. }, thread_statuses: ThreadStatuses { statuses: Mutex { data: {} } }, .. }"
116 );
117 }
118}