wl_client/proxy/low_level/owned/
scope.rs

1#[expect(unused_imports)]
2use crate::Connection;
3#[expect(unused_imports)]
4use crate::proxy;
5use {
6    crate::{
7        DispatchLock, Queue,
8        builder::prelude::{CreateEventHandler, EventHandler, UntypedBorrowedProxy},
9        ffi::{wl_argument, wl_interface, wl_message},
10        proxy::{
11            OwnedProxy, get_owned,
12            low_level::{
13                OwnedProxyRegistry, ProxyDataDestruction,
14                owned::{UntypedOwnedProxyData, event_handler_func},
15            },
16        },
17        utils::{
18            on_drop::abort_on_panic,
19            sync_cell::{SyncCell, SyncUnsafeCell},
20        },
21    },
22    parking_lot::{Condvar, Mutex},
23    run_on_drop::on_drop,
24    std::{
25        any::TypeId,
26        ffi::{c_int, c_void},
27        future::poll_fn,
28        marker::PhantomData,
29        mem,
30        pin::pin,
31        ptr::NonNull,
32        sync::{Arc, atomic::Ordering::Relaxed},
33    },
34};
35
36#[cfg(test)]
37mod tests;
38
39/// A scope for event handlers with shorter than `'static` lifetime.
40///
41/// Scopes are created by calling [`Queue::dispatch_scope_blocking`] and
42/// [`Queue::dispatch_scope_async`].
43///
44/// Event handlers attached via a scope have the following, additional restriction: they
45/// will be dropped and therefore not be invoked after the lifetime of the scope has
46/// ended. The proxies can still be used to send requests or as arguments, but no event
47/// callbacks will be invoked. Instead, the [`OwnedProxy::NO_OP_EVENT_HANDLER`] will be
48/// invoked to prevent any memory leaks.
49///
50/// Async scopes created via [`Queue::dispatch_scope_async`] have one more restriction:
51/// event handlers will only be invoked while the returned future is being polled. Until
52/// the future completes, the queue should therefore only be dispatched from inside the
53/// future.
54///
55/// # Example
56///
57/// ```
58/// # use std::cell::Cell;
59/// # use wl_client::Libwayland;
60/// # use wl_client::test_protocols::core::wl_callback::WlCallback;
61/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
62/// #
63/// let lib = Libwayland::open().unwrap();
64/// let con = lib.connect_to_default_display().unwrap();
65/// let queue = con.create_local_queue(c"queue name");
66///
67/// let sync = queue.display::<WlDisplay>().sync();
68/// let done = Cell::new(false);
69/// queue.dispatch_scope_blocking(|scope| {
70///     scope.set_event_handler_local(&sync, WlCallback::on_done(|_, _| done.set(true)));
71///     queue.dispatch_roundtrip_blocking().unwrap();
72/// });
73/// assert!(done.get());
74/// ```
75pub struct Scope<'scope, 'env: 'scope> {
76    /// Shared data of the scope. This data is kept alive even after the scope has ended
77    /// so that proxies can continue to refer to it and check the may_dispatch field.
78    pub(super) data: Arc<ScopeData>,
79    /// Ensure that 'scope and 'env are invariant. If 'scope were covariant, applications
80    /// could use this to attach an event handler with a lifetime shorter than the
81    /// original 'scope. Non-contravariance and non-any-variance of 'env is not required
82    /// but keeps things in line with [`std::thread::Scope`].
83    _inv_scope: PhantomData<&'scope mut &'scope mut ()>,
84    _inv_env: PhantomData<&'env mut &'env mut ()>,
85}
86
87pub(super) struct ScopeData {
88    /// The queue that this scope belongs to.
89    queue: Queue,
90    /// This field is protected by the queue lock. We define the following terms:
91    ///
92    /// - A system stack frame is any stack frame defined by the functions
93    ///
94    ///   - `dispatch_scope_blocking`
95    ///   - `dispatch_scope_async`
96    ///
97    ///   including any closures therein and the stack frame invoking the closures.
98    ///
99    /// - A user stack frame is any other stack frame.
100    ///
101    /// To simplify the invariants below, we coalesce all adjacent system stack frames.
102    /// That is, if we have system stack frames S1, S2, S3 where S1 calls S2 and S3, then
103    /// we treat S1, S2, and S3 as a single system stack frame. Here, S2 and S3 are the
104    /// closures defined in the functions above.
105    ///
106    /// This field has the following invariants:
107    ///
108    /// - It is only modified by system stack frames.
109    /// - If it is set to true by a system stack frame, then it is set back to false by
110    ///   the same stack frame.
111    /// - If it is set to true, then it is not modified again before being set to false as
112    ///   described in the previous bullet point.
113    ///
114    /// It follows that
115    ///
116    /// - For any user stack frame, the value of this field is constant during the
117    ///   execution of the frame. (A child stack frame might modify the value but it will
118    ///   be reset before returning.)
119    /// - If the value of the field is `false`, then it has always been false during the
120    ///   execution of any user parent stack frame.
121    may_dispatch: SyncCell<bool>,
122    /// This field is protected by the queue lock. This field has the following invariant:
123    /// It is false if and only if
124    ///
125    /// - none of the event handlers attached via the scope are currently being referenced
126    ///   by a dispatcher
127    /// - none of the event handlers attached via the scope will ever again be referenced
128    ///   by a dispatcher
129    /// - we're still within 'scope or all of the event handlers attached via the scope
130    ///   have already been dropped
131    defer_destruction: SyncCell<bool>,
132    /// This field is protected by the queue lock. This field contains the number of event
133    /// handlers attached through this scope that a) have a drop impl and b) have not yet
134    /// had their drop impl run. We use this to ensure the following invariant:
135    ///
136    /// - before the end of 'scope, all event handlers have been dropped or the remaining
137    ///   event handlers are leaked.
138    live_event_handlers: SyncCell<u64>,
139    /// This field is protected by the queue lock. If, after the scope has performed
140    /// cleanup in [`Scope::drop`], live_event_handlers is still not 0, then other
141    /// threads must currently be destroying the remaining event handlers. In this case we
142    /// set this field to true to let those destructors know that they must set
143    /// last_event_handler_destroyed to true once live_event_handlers reaches 0.
144    awaiting_last_destruction: SyncCell<bool>,
145    /// See the destruction of awaiting_last_destruction for how the following two fields
146    /// are used.
147    last_event_handler_destroyed: Mutex<bool>,
148    last_event_handler_condvar: Condvar,
149    /// The registry that registers all `Drop`-able proxies that had an event handler
150    /// attached via this scope.
151    pub(super) registry: OwnedProxyRegistry,
152    /// This field is protected by the queue lock. No long-lived references must be
153    /// created to the vector to avoid conflicting access.
154    ///
155    /// The contained destructions have the following property: It must be safe to run the
156    /// destruction once there are no ongoing dispatches of the event handler.
157    destructions: SyncUnsafeCell<Vec<ProxyDataDestruction>>,
158}
159
160impl Queue {
161    /// Creates a blocking scope for event handlers with shorter than `'static` lifetime.
162    ///
163    /// The scope can be used to attach event handlers to proxies. The following
164    /// restriction applies: Such event handlers will only be invoked while inside this
165    /// function. Once this function returns, the [`OwnedProxy::NO_OP_EVENT_HANDLER`] of
166    /// the proxy is invoked instead.
167    ///
168    /// # Panic
169    ///
170    /// Panics if this is a [local queue](Connection::create_local_queue) and the current
171    /// thread is not the thread that this queue was created in.
172    ///
173    /// # Example
174    ///
175    /// ```
176    /// # use std::cell::Cell;
177    /// # use wl_client::Libwayland;
178    /// # use wl_client::test_protocols::core::wl_callback::WlCallback;
179    /// # use wl_client::test_protocols::core::wl_display::WlDisplay;
180    /// #
181    /// let lib = Libwayland::open().unwrap();
182    /// let con = lib.connect_to_default_display().unwrap();
183    /// let queue = con.create_local_queue(c"queue name");
184    ///
185    /// let sync = queue.display::<WlDisplay>().sync();
186    /// let done = Cell::new(false);
187    /// queue.dispatch_scope_blocking(|scope| {
188    ///     scope.set_event_handler_local(&sync, WlCallback::on_done(|_, _| done.set(true)));
189    ///     queue.dispatch_roundtrip_blocking().unwrap();
190    /// });
191    /// assert!(done.get());
192    /// ```
193    pub fn dispatch_scope_blocking<'env, T, F>(&self, f: F) -> T
194    where
195        F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T,
196    {
197        let scope = Scope::new(self);
198        {
199            let _lock = self.lock_dispatch();
200            // SAFETY: - We're holding the queue lock.
201            //         - _cleanup will set may_dispatch to false, or abort, before
202            //           returning to the parent.
203            //         - No other code modifies may_dispatch before this function call
204            //           returns.
205            unsafe {
206                scope.data.may_dispatch.set(true);
207            }
208        }
209        let _cleanup = on_drop(|| {
210            let lock = abort_on_panic(|| self.lock_dispatch());
211            // SAFETY: - We're holding the queue lock.
212            unsafe {
213                scope.data.may_dispatch.set(false);
214            }
215            // SAFETY:  - This function runs when dispatch_scope_blocking returns,
216            //           therefore may_dispatch can never again become true.
217            unsafe {
218                scope.drop(Some(lock));
219            }
220        });
221        f(&scope)
222    }
223
224    /// Creates an async scope for event handlers with shorter than `'static` lifetime.
225    ///
226    /// The scope can be used to attach event handlers to proxies. The following
227    /// restriction applies: Such event handlers will only be invoked while the future is
228    /// being polled. If an event needs to be dispatched in any other situation, the
229    /// [`OwnedProxy::NO_OP_EVENT_HANDLER`] of the proxy is invoked instead.
230    ///
231    /// In particular, dispatching the queue from a outside this future while this future
232    /// exists is unlikely to have the desired effect.
233    ///
234    /// # Panic
235    ///
236    /// Panics if this is a [local queue](Connection::create_local_queue) and the thread
237    /// polling the future is not the thread that this queue was created in.
238    ///
239    /// # Example
240    ///
241    /// ```
242    /// # use std::cell::Cell;
243    /// # use wl_client::Libwayland;
244    /// # use wl_client::test_protocols::core::wl_callback::WlCallback;
245    /// # use wl_client::test_protocols::core::wl_display::WlDisplay;
246    /// #
247    /// # tokio_test::block_on(async {
248    /// let lib = Libwayland::open().unwrap();
249    /// let con = lib.connect_to_default_display().unwrap();
250    /// let queue = con.create_local_queue(c"queue name");
251    ///
252    /// let sync = queue.display::<WlDisplay>().sync();
253    /// let done = Cell::new(false);
254    /// queue.dispatch_scope_async(async |scope| {
255    ///     scope.set_event_handler_local(&sync, WlCallback::on_done(|_, _| done.set(true)));
256    ///     queue.dispatch_roundtrip_async().await.unwrap();
257    /// }).await;
258    /// assert!(done.get());
259    /// # });
260    /// ```
261    pub async fn dispatch_scope_async<'env, T, F>(&self, f: F) -> T
262    where
263        F: for<'scope> AsyncFnOnce(&'scope Scope<'scope, 'env>) -> T,
264    {
265        let scope = Scope::new(self);
266        let _cleanup = on_drop(|| {
267            // SAFETY: - This function runs when the future created by
268            //           dispatch_scope_async is dropped or completes, therefore
269            //           may_dispatch can never again become true.
270            unsafe {
271                scope.drop(None);
272            }
273        });
274        let mut fut = pin!(f(&scope));
275        poll_fn(|ctx| {
276            {
277                let _lock = self.lock_dispatch();
278                // SAFETY: - We're holding the queue lock.
279                //         - _cleanup will set may_dispatch to false, or abort, before the
280                //           poll function returns.
281                //         - The execution of this function implies `&mut` access to the
282                //           future. Therefore may_dispatch is not modified again until
283                //           this function returns.
284                unsafe {
285                    scope.data.may_dispatch.set(true);
286                }
287            }
288            let _cleanup = on_drop(|| {
289                let _lock = abort_on_panic(|| self.lock_dispatch());
290                // SAFETY: - We're holding the queue lock.
291                unsafe {
292                    scope.data.may_dispatch.set(false);
293                }
294                // SAFETY: - We're holding the queue lock.
295                //         - We just set may_dispatch to false.
296                unsafe {
297                    scope.run_destructions(true);
298                }
299            });
300            fut.as_mut().poll(ctx)
301        })
302        .await
303    }
304}
305
306impl<'scope> Scope<'scope, '_> {
307    fn new(queue: &Queue) -> Self {
308        Scope {
309            data: Arc::new(ScopeData {
310                queue: queue.clone(),
311                may_dispatch: SyncCell::new(false),
312                defer_destruction: SyncCell::new(true),
313                live_event_handlers: SyncCell::new(0),
314                awaiting_last_destruction: SyncCell::new(false),
315                last_event_handler_destroyed: Default::default(),
316                last_event_handler_condvar: Default::default(),
317                registry: Default::default(),
318                destructions: SyncUnsafeCell::new(Vec::new()),
319            }),
320            _inv_scope: Default::default(),
321            _inv_env: Default::default(),
322        }
323    }
324
325    /// # Safety
326    ///
327    /// - may_dispatch must be false and must always stay false.
328    unsafe fn drop(&'scope self, lock: Option<DispatchLock<'_>>) {
329        let lock = lock.unwrap_or_else(|| self.data.queue.lock_dispatch());
330        // SAFETY: - We are holding the queue lock.
331        //         - Since we are holding the queue lock and may_dispatch is and stays
332        //           false, event_handler_func_scoped prevents any future access to any
333        //           of the event handlers attached via this scope.
334        //         - Since may_dispatch is false, by the invariants of may_dispatch,
335        //           may_dispatch has always been false in any parent user stack frame.
336        //           Therefore, if any parent stack frame is an execution of
337        //           event_handler_func_scoped, that execution is calling the no-op event
338        //           handler. Therefore, there is currently no execution of any event
339        //           handler attached via this scope.
340        //         - This function will block until all event handlers have been dropped.
341        //           Should this function panic, the following on_drop handler will set
342        //           defer_destruction back to true before the end of 'scope.
343        unsafe {
344            self.data.defer_destruction.set(false);
345        }
346        // If this function panics, then we must reset defer_destruction before the end
347        // of 'scope. This ensures that event handler drop impls that have not yet run
348        // will be leaked.
349        let reset_defer_destruction = on_drop(|| {
350            self.data.queue.run_locked(|| {
351                // SAFETY: run_locked holds the queue lock.
352                unsafe {
353                    self.data.defer_destruction.set(true);
354                }
355            });
356        });
357        // SAFETY: - All proxies in the registry belong to this scope.
358        //         - We're holding a reference to &'scope self.
359        //         - We're holding the queue lock.
360        //         - By the same logic as in the previous safety comment, there are no
361        //           ongoing dispatches and there won't be any in the future.
362        unsafe {
363            self.data.registry.destroy_event_handlers();
364        }
365        // SAFETY: - We're holding the queue lock.
366        //         - By the safety requirements of this function, may_dispatch is false.
367        unsafe {
368            self.run_destructions(false);
369        }
370        // SAFETY: - We're holding the queue lock.
371        let live_event_handlers = unsafe { self.data.live_event_handlers.get() };
372        // This can only happen if a proxy was removed from the registry in another thread
373        // before destroy_event_handlers collected them but whose destruction has not yet
374        // run. Since defer_destruction is false, the destruction should run very soon.
375        // We have to block here until that has happened so that the drop impl completes
376        // before the end of 'scope.
377        if live_event_handlers > 0 {
378            // SAFETY: - We're holding the queue lock.
379            unsafe {
380                self.data.awaiting_last_destruction.set(true);
381            }
382            drop(lock);
383            let mut done = self.data.last_event_handler_destroyed.lock();
384            while !*done {
385                self.data.last_event_handler_condvar.wait(&mut done);
386            }
387        }
388        reset_defer_destruction.forget();
389    }
390
391    /// # Safety
392    ///
393    /// - The queue lock must be held.
394    /// - may_dispatch must be false
395    unsafe fn run_destructions(&self, re_use_memory: bool) {
396        let mut stash = vec![];
397        // SAFETY: - destructions is only ever accessed with the queue lock held
398        //         - no long-lived references to destructions are ever created
399        mem::swap(&mut stash, unsafe { &mut *self.data.destructions.get() });
400        for destruction in stash.drain(..) {
401            // SAFETY: - destructions only contains destructions such that it is safe to
402            //           run the destruction once there are no ongoing dispatches of the
403            //           event handler.
404            //         - Since may_dispatch is false, by the invariants of may_dispatch,
405            //           it has always been false in any parent stack frame.
406            //           Therefore, if any parent stack frame is an execution of
407            //           event_handler_func_scoped, that execution is calling the no-op
408            //           event handler. Therefore, there can be no dispatch referencing
409            //           the event handler going on.
410            unsafe {
411                destruction.run();
412            }
413        }
414        if re_use_memory {
415            // SAFETY: - destructions is only ever accessed with the queue lock held
416            //         - no long-lived references to destructions are ever created
417            mem::swap(&mut stash, unsafe { &mut *self.data.destructions.get() });
418            assert!(stash.is_empty());
419        }
420    }
421
422    /// Sets the event handler of the proxy.
423    ///
424    /// This function is the same as [`proxy::set_event_handler`] except that the event
425    /// handler does not have to implement `'static` and that the event handler will not
426    /// be invoked after `'scope`.
427    ///
428    /// The proxy must belong to the queue that was used to create this scope.
429    ///
430    /// # Panic
431    ///
432    /// This function panics whenever [`proxy::set_event_handler`] panics and also if the
433    /// proxy does not belong to the queue that was used to create this scope.
434    ///
435    /// # Example
436    ///
437    /// ```
438    /// # use std::sync::Arc;
439    /// # use std::sync::atomic::AtomicBool;
440    /// # use std::sync::atomic::Ordering::Relaxed;
441    /// # use wl_client::{proxy, Libwayland};
442    /// # use wl_client::test_protocols::core::wl_callback::{WlCallback, WlCallbackEventHandler, WlCallbackRef};
443    /// # use wl_client::test_protocols::core::wl_display::WlDisplay;
444    /// #
445    /// let lib = Libwayland::open().unwrap();
446    /// let con = lib.connect_to_default_display().unwrap();
447    /// let queue = con.create_queue(c"queue name");
448    /// let display: WlDisplay = queue.display();
449    /// let sync = display.sync();
450    /// let done = AtomicBool::new(false);
451    ///
452    /// queue.dispatch_scope_blocking(|scope| {
453    ///     // Attach the event handler.
454    ///     scope.set_event_handler(&sync, WlCallback::on_done(|_, _| done.store(true, Relaxed)));
455    ///
456    ///     // Wait for the compositor to send the `done` message.
457    ///     queue.dispatch_roundtrip_blocking().unwrap();
458    /// });
459    ///
460    /// // The event handler sets the value to `true`.
461    /// assert!(done.load(Relaxed));
462    /// ```
463    #[inline]
464    pub fn set_event_handler<P, H>(&'scope self, proxy: &P, handler: H)
465    where
466        P: OwnedProxy,
467        P::Api: CreateEventHandler<H>,
468        <P::Api as CreateEventHandler<H>>::EventHandler: Send + 'scope,
469    {
470        // SAFETY: - The event handler is Send
471        unsafe {
472            set_event_handler(self, proxy, P::Api::create_event_handler(handler));
473        }
474    }
475
476    /// Sets the `!Send` event handler of the proxy.
477    ///
478    /// This function is the same as [`proxy::set_event_handler_local`] except that the
479    /// event handler does not have to implement `'static` and that the event handler will
480    /// not be invoked after `'scope`.
481    ///
482    /// The proxy must belong to the queue that was used to create this scope.
483    ///
484    /// # Panic
485    ///
486    /// This function panics whenever [`proxy::set_event_handler_local`] panics and also
487    /// if the proxy does not belong to the queue that was used to create this scope.
488    ///
489    /// # Example
490    ///
491    /// ```
492    /// # use std::cell::Cell;
493    /// # use std::rc::Rc;
494    /// # use std::sync::atomic::Ordering::Relaxed;
495    /// # use wl_client::{proxy, Libwayland};
496    /// # use wl_client::test_protocols::core::wl_callback::{WlCallback, WlCallbackEventHandler, WlCallbackRef};
497    /// # use wl_client::test_protocols::core::wl_display::WlDisplay;
498    /// #
499    /// let lib = Libwayland::open().unwrap();
500    /// let con = lib.connect_to_default_display().unwrap();
501    /// let queue = con.create_local_queue(c"queue name");
502    /// let display: WlDisplay = queue.display();
503    /// let sync = display.sync();
504    /// let done = Cell::new(false);
505    ///
506    /// queue.dispatch_scope_blocking(|scope| {
507    ///     // Attach the event handler.
508    ///     scope.set_event_handler_local(&sync, WlCallback::on_done(|_, _| done.set(true)));
509    ///
510    ///     // Wait for the compositor to send the `done` message.
511    ///     queue.dispatch_roundtrip_blocking().unwrap();
512    /// });
513    ///
514    /// // The event handler sets the value to `true`.
515    /// assert!(done.get());
516    /// ```
517    #[inline]
518    pub fn set_event_handler_local<P, H>(&'scope self, proxy: &P, handler: H)
519    where
520        P: OwnedProxy,
521        P::Api: CreateEventHandler<H>,
522        <P::Api as CreateEventHandler<H>>::EventHandler: 'scope,
523    {
524        if self.data.queue.is_non_local() {
525            panic!("Queue is not a local queue");
526        }
527        // SAFETY: - We've checked that the queue is a local queue.
528        unsafe {
529            set_event_handler(self, proxy, P::Api::create_event_handler(handler));
530        }
531    }
532}
533
534struct ScopeEventHandler<H, D> {
535    event_handler: H,
536    _on_drop: D,
537}
538
539unsafe impl<H, D> EventHandler for ScopeEventHandler<H, D>
540where
541    H: EventHandler,
542{
543    const WL_INTERFACE: &'static wl_interface = H::WL_INTERFACE;
544
545    #[inline]
546    fn mutable_type() -> Option<(TypeId, &'static str)> {
547        H::mutable_type()
548    }
549
550    #[inline]
551    unsafe fn handle_event(
552        &self,
553        queue: &Queue,
554        data: *mut u8,
555        slf: &UntypedBorrowedProxy,
556        opcode: u32,
557        args: *mut wl_argument,
558    ) {
559        unsafe {
560            self.event_handler
561                .handle_event(queue, data, slf, opcode, args);
562        }
563    }
564}
565
566/// # Safety
567///
568/// - if T does not implement Send, then the queue must be a local queue
569unsafe fn set_event_handler<'scope, P, H>(
570    scope: &'scope Scope<'scope, '_>,
571    proxy: &P,
572    event_handler: H,
573) where
574    P: OwnedProxy,
575    H: EventHandler + 'scope,
576{
577    if mem::needs_drop::<H>() {
578        let data = scope.data.clone();
579        let event_handler = ScopeEventHandler {
580            event_handler,
581            _on_drop: on_drop(move || {
582                let d = &*data;
583                let leh = &d.live_event_handlers;
584                // SAFETY: the scope lock is held while dropping event handlers.
585                let live = unsafe { leh.get() };
586                // SAFETY: the scope lock is held while dropping event handlers.
587                unsafe {
588                    leh.set(live - 1);
589                }
590                // SAFETY: the scope lock is held while dropping event handlers.
591                let awaiting_last_destruction = unsafe { d.awaiting_last_destruction.get() };
592                if live == 1 && awaiting_last_destruction {
593                    *d.last_event_handler_destroyed.lock() = true;
594                    d.last_event_handler_condvar.notify_all();
595                }
596            }),
597        };
598        scope.data.queue.run_locked(|| {
599            let leh = &scope.data.live_event_handlers;
600            // SAFETY: We're holding the queue lock.
601            unsafe {
602                leh.set(leh.get() + 1);
603            }
604        });
605        // SAFETY: The requirements are forwarded to the caller.
606        unsafe {
607            set_event_handler2(scope, proxy, event_handler);
608        }
609    } else {
610        // SAFETY: The requirements are forwarded to the caller.
611        unsafe {
612            set_event_handler2(scope, proxy, event_handler);
613        }
614    }
615}
616
617/// # Safety
618///
619/// - if T does not implement Send, then the queue must be a local queue
620unsafe fn set_event_handler2<'scope, P, H>(
621    scope: &'scope Scope<'scope, '_>,
622    proxy: &P,
623    event_handler: H,
624) where
625    P: OwnedProxy,
626    H: EventHandler + 'scope,
627{
628    let proxy = get_owned(proxy);
629    assert_eq!(proxy.queue(), &scope.data.queue);
630    // SAFETY: - all requirements except the callability of event_handler_func as part
631    //           of a libwayland dispatch are trivially satisfied
632    //         - libwayland only ever calls event handlers while preserving a
633    //           valid pointer to the proxy and all pointers in args
634    //         - set_event_handler4 checks that the interface of the proxy is
635    //           H::WL_INTERFACE
636    //         - by the safety requirements, P::WL_INTERFACE is compatible with the
637    //           proxy's interface which is compatible with H::WL_INTERFACE by the
638    //           previous point
639    //         - libwayland ensures that opcode and args conform to the
640    //           interface before calling the event handler
641    //         - set_event_handler4 sets event_handler to a pointer to H
642    //         - if T is not Send, then this function requires that this is a
643    //           local queue which will panic when trying to call this function
644    //           or any dispatching function on a thread other than the thread
645    //           on which the queue was created
646    //         - we always hold the queue lock while dispatching
647    //         - set_event_handler4 sets the scope_data to a pointer to the scope data
648    //           and stores a clone of the Arc so that the pointer will always remain
649    //           valid
650    //         - we only ever invalidate the self.event_handler or self.data
651    //           pointers via handle_destruction which requires that it is safe to run
652    //           the destruction.
653    //         - handle_destruction does not run destructions unless defer_destruction is
654    //           false or run_destructions is called.
655    //           - run_destructions is only ever called within 'scope and
656    //           - defer_destruction is only set to true in drop which blocks until all
657    //             event handlers have been destroyed.
658    unsafe {
659        proxy.set_event_handler3(
660            event_handler,
661            event_handler_func_scoped::<P, H>,
662            Some(scope),
663        );
664    }
665}
666
667impl ScopeData {
668    /// Handles the destruction of proxies attached to this scope.
669    ///
670    /// If this is called within `'scope`, the destruction is either never runs or runs
671    /// also within `'scope`.
672    ///
673    /// # Safety
674    ///
675    /// - The proxy must be attached to this scope.
676    /// - It must be safe to run the destruction once there are no ongoing dispatches
677    ///   of the event handler of the proxy.
678    pub(super) unsafe fn handle_destruction(&self, destruction: ProxyDataDestruction) {
679        let _lock = self.queue.lock_dispatch();
680        // SAFETY: - we're holding the queue lock
681        match unsafe { self.defer_destruction.get() } {
682            true => {
683                // SAFETY: - destructions is only ever accessed with the queue lock held
684                //         - no long-lived references to destructions are ever created
685                let destructions = unsafe { &mut *self.destructions.get() };
686                // SAFETY: - the destructions in destructions are only run within
687                //           'scope, if ever.
688                destructions.push(destruction);
689            }
690            false => {
691                // SAFETY: - by the invariants, defer_destruction being false implies
692                //           that all dispatcher uses of the event handler have
693                //           ceased and if destruction contains an event handlers then we
694                //           are still within 'scope
695                unsafe { destruction.run() }
696            }
697        }
698    }
699}
700
701/// The event handler function for scoped event handlers.
702///
703/// This function is the same as [`event_handler_func`] except that it additionally checks
704/// that [`ScopeData::may_dispatch`] is true. If it is not, then, instead of calling the
705/// normal event handler, [`P::NO_OP_EVENT_HANDLER`] is called.
706///
707/// This allows the event handler to be destroyed long before the proxy itself is
708/// destroyed as long as `may_dispatch` remains false afterwards.
709///
710/// # Safety
711///
712/// - event_handler_data must be a pointer to UntypedOwnedProxyData
713/// - the scope_data field in the UntypedOwnedProxy must contain a pointer to ScopeData
714/// - the queue lock of the proxy must be held
715/// - if scope_data.may_dispatch, then all safety requirements of event_handler_func::<T>
716///   must be satisfied
717/// - the interface of the proxy must be compatible with P::WL_INTERFACE
718/// - P::WL_INTERFACE and T::WL_INTERFACE must be compatible
719unsafe extern "C" fn event_handler_func_scoped<P, T>(
720    event_handler_data: *const c_void,
721    target: *mut c_void,
722    opcode: u32,
723    msg: *const wl_message,
724    args: *mut wl_argument,
725) -> c_int
726where
727    P: OwnedProxy,
728    T: EventHandler,
729{
730    // SAFETY: By the safety requirements of this function, event_handler is a valid pointer
731    //         to UntypedOwnedProxyData.
732    let proxy_data = unsafe { &*(event_handler_data as *const UntypedOwnedProxyData) };
733    // SAFETY: Dito, scope_data is a valid pointer.
734    let scope_data = unsafe { &*proxy_data.scope_data.load(Relaxed) };
735    // SAFETY: Dito, the queue lock is being held.
736    if unsafe { scope_data.may_dispatch.get() } {
737        // SAFETY: Dito, since may_dispatch is true, all safety requirements of
738        //         event_handler_func are satisfied.
739        return unsafe { event_handler_func::<T>(event_handler_data, target, opcode, msg, args) };
740    }
741    // SAFETY: Dito, target is and stays valid.
742    let target = unsafe { NonNull::new_unchecked(target.cast()) };
743    // SAFETY: Dito, target is and stays valid.
744    let target =
745        unsafe { UntypedBorrowedProxy::new_immutable(proxy_data.proxy.libwayland, target) };
746    // SAFETY: Dito, the queue lock is being held.
747    let data = unsafe { proxy_data.queue.data() };
748    // SAFETY: - Dito, the interface of the proxy is compatible with P::WL_INTERFACE
749    //         - Dito, target is a valid pointer and stays valid
750    //         - Dito, opcode and args conform to P::WL_INTERFACE
751    //         - The mutable_type of the NO_OP_EVENT_HANDLER is required to be `None` or
752    //           the type ID of `()`. If it is `None`, then there is nothing to show.
753    //           Otherwise, Queue::data guarantees that `data` can be dereferenced to
754    //           `T::mutable_type` or `()` if `mutable_type` returns None. Any non-null
755    //           pointer can be dereferenced to `()`.
756    unsafe {
757        P::NO_OP_EVENT_HANDLER.handle_event(&proxy_data.queue, data, &target, opcode, args);
758    }
759    0
760}