Skip to main content

reifydb_runtime/actor/mailbox/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4#[cfg(all(reifydb_single_threaded, not(reifydb_dst)))]
5use std::cell::{Cell, RefCell};
6use std::fmt;
7#[cfg(all(reifydb_single_threaded, not(reifydb_dst)))]
8use std::rc::Rc;
9#[cfg(all(reifydb_single_threaded, not(reifydb_dst)))]
10use std::sync::Arc;
11#[cfg(all(reifydb_single_threaded, not(reifydb_dst)))]
12use std::sync::atomic::AtomicBool;
13
14use cfg_if::cfg_if;
15
16#[cfg(not(reifydb_single_threaded))]
17pub(crate) mod host;
18
19#[cfg(all(reifydb_single_threaded, not(reifydb_dst)))]
20pub(crate) mod wasm;
21
22#[cfg(reifydb_dst)]
23pub(crate) mod dst;
24
25cfg_if! {
26	if #[cfg(reifydb_dst)] {
27		type ActorRefInnerImpl<M> = dst::ActorRefInner<M>;
28	} else if #[cfg(not(reifydb_single_threaded))] {
29		type ActorRefInnerImpl<M> = host::ActorRefInner<M>;
30	} else {
31		type ActorRefInnerImpl<M> = wasm::ActorRefInner<M>;
32	}
33}
34
35#[derive(Debug, Clone, PartialEq, Eq)]
36pub enum SendError<M> {
37	Closed(M),
38
39	Full(M),
40}
41
42impl<M> SendError<M> {
43	#[inline]
44	pub fn into_inner(self) -> M {
45		match self {
46			SendError::Closed(m) => m,
47			SendError::Full(m) => m,
48		}
49	}
50}
51
52impl<M: fmt::Debug> fmt::Display for SendError<M> {
53	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54		match self {
55			SendError::Closed(_) => write!(f, "actor mailbox closed"),
56			SendError::Full(_) => write!(f, "actor mailbox full"),
57		}
58	}
59}
60
61impl<M: fmt::Debug> error::Error for SendError<M> {}
62
63#[derive(Debug, Clone, PartialEq, Eq)]
64pub enum AskError {
65	SendFailed,
66
67	ResponseClosed,
68}
69
70impl fmt::Display for AskError {
71	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72		match self {
73			AskError::SendFailed => write!(f, "failed to send ask request"),
74			AskError::ResponseClosed => write!(f, "response channel closed"),
75		}
76	}
77}
78
79impl error::Error for AskError {}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub enum TryRecvError {
83	Empty,
84
85	Closed,
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89pub enum RecvError {
90	Closed,
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq)]
94pub enum RecvTimeoutError {
95	Timeout,
96
97	Closed,
98}
99
100pub struct ActorRef<M> {
101	inner: ActorRefInnerImpl<M>,
102}
103
104impl<M> Clone for ActorRef<M> {
105	#[inline]
106	fn clone(&self) -> Self {
107		Self {
108			inner: self.inner.clone(),
109		}
110	}
111}
112
113impl<M> fmt::Debug for ActorRef<M> {
114	#[inline]
115	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116		self.inner.fmt(f)
117	}
118}
119
120// SAFETY: under reifydb_single_threaded there is no second thread, so an ActorRef can never be reached
121// from another one. These impls only satisfy Send + Sync bounds and never back a real transfer.
122#[cfg(reifydb_single_threaded)]
123unsafe impl<M> Send for ActorRef<M> {}
124
125#[cfg(reifydb_single_threaded)]
126unsafe impl<M> Sync for ActorRef<M> {}
127
128impl<M> ActorRef<M> {
129	#[inline]
130	pub(crate) fn from_inner(inner: ActorRefInnerImpl<M>) -> Self {
131		Self {
132			inner,
133		}
134	}
135}
136
137#[cfg(not(reifydb_single_threaded))]
138impl<M: Send> ActorRef<M> {
139	#[inline]
140	pub(crate) fn new(tx: Sender<M>) -> Self {
141		Self {
142			inner: host::ActorRefInner::new(tx),
143		}
144	}
145
146	#[inline]
147	pub(crate) fn set_notify(&self, f: sync::Arc<dyn Fn() + Send + Sync>) {
148		self.inner.set_notify(f)
149	}
150
151	#[inline]
152	pub fn send(&self, msg: M) -> Result<(), SendError<M>> {
153		self.inner.send(msg)
154	}
155
156	#[inline]
157	pub fn send_blocking(&self, msg: M) -> Result<(), SendError<M>> {
158		self.inner.send_blocking(msg)
159	}
160
161	#[inline]
162	pub fn is_alive(&self) -> bool {
163		self.inner.is_alive()
164	}
165}
166
167#[cfg(reifydb_dst)]
168impl<M> ActorRef<M> {
169	#[inline]
170	pub fn send(&self, msg: M) -> Result<(), SendError<M>> {
171		self.inner.send(msg)
172	}
173
174	#[inline]
175	pub fn send_blocking(&self, msg: M) -> Result<(), SendError<M>> {
176		self.inner.send_blocking(msg)
177	}
178
179	#[inline]
180	pub fn is_alive(&self) -> bool {
181		self.inner.is_alive()
182	}
183
184	#[inline]
185	pub(crate) fn mark_stopped(&self) {
186		self.inner.mark_stopped()
187	}
188
189	#[inline]
190	pub(crate) fn set_notify(&self, f: Box<dyn Fn()>) {
191		self.inner.set_notify(f)
192	}
193}
194
195#[cfg(all(reifydb_single_threaded, not(reifydb_dst)))]
196impl<M> ActorRef<M> {
197	#[inline]
198	pub(crate) fn new(
199		processor: Rc<RefCell<Option<Box<dyn FnMut(M)>>>>,
200		alive: Arc<AtomicBool>,
201		queue: Rc<RefCell<Vec<M>>>,
202		processing: Rc<Cell<bool>>,
203	) -> Self {
204		Self {
205			inner: wasm::ActorRefInner::new(processor, alive, queue, processing),
206		}
207	}
208
209	#[inline]
210	pub(crate) fn from_wasm_inner(
211		processor: Rc<RefCell<Option<Box<dyn FnMut(M)>>>>,
212		alive: Arc<AtomicBool>,
213		queue: Rc<RefCell<Vec<M>>>,
214		processing: Rc<Cell<bool>>,
215	) -> Self {
216		Self {
217			inner: wasm::ActorRefInner::new(processor, alive, queue, processing),
218		}
219	}
220
221	#[inline]
222	pub fn send(&self, msg: M) -> Result<(), SendError<M>> {
223		self.inner.send(msg)
224	}
225
226	#[inline]
227	pub fn send_blocking(&self, msg: M) -> Result<(), SendError<M>> {
228		self.inner.send_blocking(msg)
229	}
230
231	#[inline]
232	pub fn is_alive(&self) -> bool {
233		self.inner.is_alive()
234	}
235
236	#[inline]
237	pub(crate) fn mark_stopped(&self) {
238		self.inner.mark_stopped()
239	}
240
241	#[inline]
242	pub(crate) fn processor(&self) -> &Rc<RefCell<Option<Box<dyn FnMut(M)>>>> {
243		&self.inner.processor
244	}
245}
246
247use std::error;
248#[cfg(not(reifydb_single_threaded))]
249use std::sync;
250
251#[cfg(not(reifydb_single_threaded))]
252use crossbeam_channel::Sender;
253#[cfg(reifydb_dst)]
254pub(crate) use dst::create_mailbox as create_dst_mailbox;
255#[cfg(not(reifydb_single_threaded))]
256pub(crate) use host::create_mailbox;
257#[cfg(all(reifydb_single_threaded, not(reifydb_dst)))]
258pub(crate) use wasm::create_actor_ref;