1use std::cell::RefCell;
2use std::future::Future;
3use std::io;
4use std::sync::atomic::{AtomicUsize, Ordering};
5
6use futures::channel::mpsc::UnboundedSender;
7use tokio::task::LocalSet;
8
9use crate::arbiter::{Arbiter, SystemCommand};
10use crate::builder::{Builder, SystemRunner};
11
12static SYSTEM_COUNT: AtomicUsize = AtomicUsize::new(0);
13
14#[derive(Clone, Debug)]
16pub struct System {
17 id: usize,
18 sys: UnboundedSender<SystemCommand>,
19 arbiter: Arbiter,
20 stop_on_panic: bool,
21}
22
23thread_local!(
24 static CURRENT: RefCell<Option<System>> = RefCell::new(None);
25);
26
27impl System {
28 pub(crate) fn construct(
30 sys: UnboundedSender<SystemCommand>,
31 arbiter: Arbiter,
32 stop_on_panic: bool,
33 ) -> Self {
34 let sys = System {
35 sys,
36 arbiter,
37 stop_on_panic,
38 id: SYSTEM_COUNT.fetch_add(1, Ordering::SeqCst),
39 };
40 System::set_current(sys.clone());
41 sys
42 }
43
44 pub fn builder() -> Builder {
49 Builder::new()
50 }
51
52 #[allow(clippy::new_ret_no_self)]
53 pub fn new<T: Into<String>>(name: T) -> SystemRunner {
57 Self::builder().name(name).build()
58 }
59
60 #[allow(clippy::new_ret_no_self)]
61 pub fn run_in_tokio<T: Into<String>>(
65 name: T,
66 local: &LocalSet,
67 ) -> impl Future<Output = io::Result<()>> {
68 Self::builder()
69 .name(name)
70 .build_async(local)
71 .run_nonblocking()
72 }
73
74 pub fn current() -> System {
76 CURRENT.with(|cell| match *cell.borrow() {
77 Some(ref sys) => sys.clone(),
78 None => panic!("System is not running"),
79 })
80 }
81
82 pub(crate) fn is_set() -> bool {
84 CURRENT.with(|cell| cell.borrow().is_some())
85 }
86
87 #[doc(hidden)]
89 pub fn set_current(sys: System) {
90 CURRENT.with(|s| {
91 *s.borrow_mut() = Some(sys);
92 })
93 }
94
95 pub fn with_current<F, R>(f: F) -> R
97 where
98 F: FnOnce(&System) -> R,
99 {
100 CURRENT.with(|cell| match *cell.borrow() {
101 Some(ref sys) => f(sys),
102 None => panic!("System is not running"),
103 })
104 }
105
106 pub fn id(&self) -> usize {
108 self.id
109 }
110
111 pub fn stop(&self) {
113 self.stop_with_code(0)
114 }
115
116 pub fn stop_with_code(&self, code: i32) {
118 let _ = self.sys.unbounded_send(SystemCommand::Exit(code));
119 }
120
121 pub(crate) fn sys(&self) -> &UnboundedSender<SystemCommand> {
122 &self.sys
123 }
124
125 pub fn stop_on_panic(&self) -> bool {
128 self.stop_on_panic
129 }
130
131 pub fn arbiter(&self) -> &Arbiter {
133 &self.arbiter
134 }
135
136 pub fn run<F>(f: F) -> io::Result<()>
140 where
141 F: FnOnce() + 'static,
142 {
143 Self::builder().run(f)
144 }
145}