servo_base/generic_channel/
callback.rs1use std::fmt;
63use std::marker::PhantomData;
64use std::sync::{Arc, Mutex};
65
66use ipc_channel::ipc::IpcSender;
67use ipc_channel::router::ROUTER;
68use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
69use serde::de::VariantAccess;
70use serde::{Deserialize, Deserializer, Serialize, Serializer};
71use servo_config::opts;
72
73use crate::generic_channel::{
74 GenericReceiver, GenericReceiverVariants, SendError, SendResult, use_ipc,
75};
76
77pub type MsgCallback<T> = dyn FnMut(Result<T, SendError>) + Send;
84
85pub struct GenericCallback<T>(GenericCallbackVariants<T>)
91where
92 T: Serialize + Send + 'static;
93
94enum GenericCallbackVariants<T>
95where
96 T: Serialize + Send + 'static,
97{
98 CrossProcess(IpcSender<T>),
99 InProcess(Arc<Mutex<MsgCallback<T>>>),
100}
101
102impl<T> Clone for GenericCallback<T>
103where
104 T: Serialize + Send + 'static,
105{
106 fn clone(&self) -> Self {
107 let variant = match &self.0 {
108 GenericCallbackVariants::CrossProcess(sender) => {
109 GenericCallbackVariants::CrossProcess((*sender).clone())
110 },
111 GenericCallbackVariants::InProcess(callback) => {
112 GenericCallbackVariants::InProcess(callback.clone())
113 },
114 };
115 GenericCallback(variant)
116 }
117}
118
119impl<T> MallocSizeOf for GenericCallback<T>
120where
121 T: Serialize + Send + 'static,
122{
123 fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
124 0
125 }
126}
127
128impl<T> GenericCallback<T>
129where
130 T: for<'de> Deserialize<'de> + Serialize + Send + 'static,
131{
132 pub fn new<F: FnMut(Result<T, SendError>) + Send + 'static>(
136 mut callback: F,
137 ) -> Result<Self, SendError> {
138 let generic_callback = if use_ipc() {
139 let (ipc_sender, ipc_receiver) =
140 ipc_channel::ipc::channel().map_err(SendError::from)?;
141 let new_callback = move |msg: Result<T, ipc_channel::SerDeError>| {
142 callback(msg.map_err(|error| error.into()))
143 };
144 ROUTER.add_typed_route(ipc_receiver, Box::new(new_callback));
145 GenericCallback(GenericCallbackVariants::CrossProcess(ipc_sender))
146 } else {
147 let callback = Arc::new(Mutex::new(callback));
148 GenericCallback(GenericCallbackVariants::InProcess(callback))
149 };
150 Ok(generic_callback)
151 }
152
153 pub fn new_blocking() -> Result<(Self, GenericReceiver<T>), SendError> {
155 if use_ipc() {
156 let (sender, receiver) = ipc_channel::ipc::channel().map_err(SendError::from)?;
157 let generic_callback = GenericCallback(GenericCallbackVariants::CrossProcess(sender));
158 let receiver = GenericReceiver(GenericReceiverVariants::Ipc(receiver));
159 Ok((generic_callback, receiver))
160 } else {
161 let (sender, receiver) = crossbeam_channel::bounded(1);
162 let callback = Arc::new(Mutex::new(move |msg| {
163 if sender.send(msg).is_err() {
164 log::error!("Error in callback");
165 }
166 }));
167 let generic_callback = GenericCallback(GenericCallbackVariants::InProcess(callback));
168 let receiver = GenericReceiver(GenericReceiverVariants::Crossbeam(receiver));
169 Ok((generic_callback, receiver))
170 }
171 }
172
173 pub fn send(&self, value: T) -> SendResult {
179 match &self.0 {
180 GenericCallbackVariants::CrossProcess(sender) => {
181 sender.send(value).map_err(|error| match error {
182 ipc_channel::IpcError::SerializationError(ser_de_error) => {
183 SendError::SerializationError(ser_de_error.to_string())
184 },
185 ipc_channel::IpcError::Io(_) | ipc_channel::IpcError::Disconnected => {
186 SendError::Disconnected
187 },
188 })
189 },
190 GenericCallbackVariants::InProcess(callback) => {
191 let mut cb = callback.lock().expect("poisoned");
192 (*cb)(Ok(value));
193 Ok(())
194 },
195 }
196 }
197}
198
199impl<T> Serialize for GenericCallback<T>
200where
201 T: Serialize + Send + 'static,
202{
203 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
204 match &self.0 {
205 GenericCallbackVariants::CrossProcess(sender) => {
206 s.serialize_newtype_variant("GenericCallback", 0, "CrossProcess", sender)
207 },
208 GenericCallbackVariants::InProcess(wrapped_callback) => {
215 if opts::get().multiprocess {
216 return Err(serde::ser::Error::custom(
217 "InProcess callback can't be serialized in multiprocess mode",
218 ));
219 }
220 let cloned_callback = Box::new(wrapped_callback.clone());
224 let sender_clone_addr = Box::leak(cloned_callback) as *mut Arc<_> as usize;
225 s.serialize_newtype_variant("GenericCallback", 1, "InProcess", &sender_clone_addr)
226 },
227 }
228 }
229}
230
231struct GenericCallbackVisitor<T> {
232 marker: PhantomData<T>,
233}
234
235impl<'de, T> serde::de::Visitor<'de> for GenericCallbackVisitor<T>
236where
237 T: Serialize + Deserialize<'de> + Send + 'static,
238{
239 type Value = GenericCallback<T>;
240
241 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
242 formatter.write_str("a GenericCallback variant")
243 }
244
245 fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
246 where
247 A: serde::de::EnumAccess<'de>,
248 {
249 #[derive(Deserialize)]
250 enum GenericCallbackVariantNames {
251 CrossProcess,
252 InProcess,
253 }
254
255 let (variant_name, variant_data): (GenericCallbackVariantNames, _) = data.variant()?;
256
257 match variant_name {
258 GenericCallbackVariantNames::CrossProcess => variant_data
259 .newtype_variant::<IpcSender<T>>()
260 .map(|sender| GenericCallback(GenericCallbackVariants::CrossProcess(sender))),
261 GenericCallbackVariantNames::InProcess => {
262 if use_ipc() {
263 return Err(serde::de::Error::custom(
264 "InProcess callback found in multiprocess mode",
265 ));
266 }
267 let addr = variant_data.newtype_variant::<usize>()?;
268 let ptr = addr as *mut Arc<Mutex<_>>;
269 #[expect(unsafe_code)]
275 let callback = unsafe { Box::from_raw(ptr) };
276 Ok(GenericCallback(GenericCallbackVariants::InProcess(
277 *callback,
278 )))
279 },
280 }
281 }
282}
283
284impl<'a, T> Deserialize<'a> for GenericCallback<T>
285where
286 T: Serialize + Deserialize<'a> + Send + 'static,
287{
288 fn deserialize<D>(d: D) -> Result<GenericCallback<T>, D::Error>
289 where
290 D: Deserializer<'a>,
291 {
292 d.deserialize_enum(
293 "GenericCallback",
294 &["CrossProcess", "InProcess"],
295 GenericCallbackVisitor {
296 marker: PhantomData,
297 },
298 )
299 }
300}
301
302impl<T> fmt::Debug for GenericCallback<T>
303where
304 T: Serialize + Send + 'static,
305{
306 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
307 write!(f, "GenericCallback(..)")
308 }
309}
310
311#[cfg(test)]
312mod single_process_callback_test {
313 use std::sync::Arc;
314 use std::sync::atomic::{AtomicUsize, Ordering};
315
316 use crate::generic_channel::{GenericCallback, SendError};
317
318 #[test]
319 fn generic_callback() {
320 let number = Arc::new(AtomicUsize::new(0));
321 let number_clone = number.clone();
322 let callback =
323 move |msg: Result<usize, SendError>| number_clone.store(msg.unwrap(), Ordering::SeqCst);
324 let generic_callback = GenericCallback::new(callback).unwrap();
325 std::thread::scope(|s| {
326 s.spawn(move || generic_callback.send(42));
327 });
328 assert_eq!(number.load(Ordering::SeqCst), 42);
329 }
330
331 #[test]
332 fn generic_callback_via_generic_sender() {
333 let number = Arc::new(AtomicUsize::new(0));
334 let number_clone = number.clone();
335 let callback =
336 move |msg: Result<usize, SendError>| number_clone.store(msg.unwrap(), Ordering::SeqCst);
337 let generic_callback = GenericCallback::new(callback).unwrap();
338 let (tx, rx) = crate::generic_channel::channel().unwrap();
339
340 tx.send(generic_callback).unwrap();
341 std::thread::scope(|s| {
342 s.spawn(move || {
343 let callback = rx.recv().unwrap();
344 callback.send(42).unwrap();
345 });
346 });
347 assert_eq!(number.load(Ordering::SeqCst), 42);
348 }
349
350 #[test]
351 fn generic_callback_via_ipc_sender() {
352 let number = Arc::new(AtomicUsize::new(0));
353 let number_clone = number.clone();
354 let callback =
355 move |msg: Result<usize, SendError>| number_clone.store(msg.unwrap(), Ordering::SeqCst);
356 let generic_callback = GenericCallback::new(callback).unwrap();
357 let (tx, rx) = ipc_channel::ipc::channel().unwrap();
358
359 tx.send(generic_callback).unwrap();
360 std::thread::scope(|s| {
361 s.spawn(move || {
362 let callback = rx.recv().unwrap();
363 callback.send(42).unwrap();
364 });
365 });
366 assert_eq!(number.load(Ordering::SeqCst), 42);
367 }
368
369 #[test]
370 fn generic_callback_blocking() {
371 let (callback, receiver) = GenericCallback::new_blocking().unwrap();
372 std::thread::spawn(move || {
373 std::thread::sleep(std::time::Duration::from_secs(1));
374 assert!(callback.send(42).is_ok());
375 });
376 assert_eq!(receiver.recv().unwrap(), 42);
377 }
378}