1use std::cell::{Cell, RefCell};
2use std::collections::VecDeque;
3use std::fmt;
4use std::marker::PhantomData;
5use std::rc::{Rc, Weak};
6use std::sync::atomic::{AtomicU64, Ordering};
7
8use crate::core::{NativeWork, NodeId, RuntimeError, WindowToken};
9use crate::element::{Callback, View};
10
11const IMPERATIVE_QUEUE_CAPACITY: usize = 4_096;
12static NEXT_OBSERVATION_ID: AtomicU64 = AtomicU64::new(1);
13
14#[derive(Debug)]
15pub(crate) enum HostRequest {
16 CloseWindow { identity: WindowToken },
17 OpenWindow { identity: WindowToken, root: View },
18}
19
20struct WindowRequestState {
21 active: Option<ActiveWindowRequests>,
22 lifecycle: WindowRequestLifecycle,
23 staged_close: bool,
24 staged_opens: Vec<View>,
25}
26
27#[derive(Default)]
28struct ActiveWindowRequests {
29 close: bool,
30 opens: Vec<View>,
31}
32
33#[derive(Clone, Copy, Eq, PartialEq)]
34enum WindowRequestLifecycle {
35 Open,
36 CloseCommitted,
37 Closed,
38 ClosedCommitted,
39}
40
41#[derive(Clone)]
42pub(crate) struct WindowEndpoint {
43 identity: WindowToken,
44 state: Rc<RefCell<WindowRequestState>>,
45}
46
47impl WindowEndpoint {
48 pub(crate) fn new(identity: WindowToken) -> Self {
49 Self {
50 identity,
51 state: Rc::new(RefCell::new(WindowRequestState {
52 active: None,
53 lifecycle: WindowRequestLifecycle::Open,
54 staged_close: false,
55 staged_opens: Vec::new(),
56 })),
57 }
58 }
59
60 pub(crate) fn begin(&self) {
61 let mut state = self.state.borrow_mut();
62 assert!(
63 state.active.is_none(),
64 "component lifecycle invocation reentered"
65 );
66 state.active = Some(ActiveWindowRequests::default());
67 }
68
69 pub(crate) fn finish(&self) {
70 let mut state = self.state.borrow_mut();
71 let active = state
72 .active
73 .take()
74 .expect("component lifecycle invocation was not active");
75 state.staged_close |= active.close;
76 state.staged_opens.extend(active.opens);
77 }
78
79 pub(crate) fn take_requests(&self) -> Vec<HostRequest> {
80 let mut state = self.state.borrow_mut();
81 let mut requests = state
82 .staged_opens
83 .drain(..)
84 .map(|root| HostRequest::OpenWindow {
85 identity: self.identity,
86 root,
87 })
88 .collect::<Vec<_>>();
89 if state.staged_close {
90 state.staged_close = false;
91 requests.push(HostRequest::CloseWindow {
92 identity: self.identity,
93 });
94 }
95 requests
96 }
97
98 pub(crate) fn close(&self) {
99 let mut state = self.state.borrow_mut();
100 state.lifecycle = match state.lifecycle {
101 WindowRequestLifecycle::Open | WindowRequestLifecycle::Closed => {
102 WindowRequestLifecycle::Closed
103 }
104 WindowRequestLifecycle::CloseCommitted | WindowRequestLifecycle::ClosedCommitted => {
105 WindowRequestLifecycle::ClosedCommitted
106 }
107 };
108 state.active = None;
109 state.staged_close = false;
110 state.staged_opens.clear();
111 }
112
113 pub(crate) fn commit_close(&self) {
114 let mut state = self.state.borrow_mut();
115 state.lifecycle = match state.lifecycle {
116 WindowRequestLifecycle::Open | WindowRequestLifecycle::CloseCommitted => {
117 WindowRequestLifecycle::CloseCommitted
118 }
119 WindowRequestLifecycle::Closed | WindowRequestLifecycle::ClosedCommitted => {
120 WindowRequestLifecycle::ClosedCommitted
121 }
122 };
123 }
124
125 pub(crate) fn reference(&self) -> WindowRef {
126 WindowRef {
127 endpoint: self.clone(),
128 }
129 }
130
131 fn request_open(&self, root: View) -> bool {
132 let mut state = self.state.borrow_mut();
133 if state.lifecycle != WindowRequestLifecycle::Open {
134 return false;
135 }
136 let Some(active) = state.active.as_mut() else {
137 return false;
138 };
139 active.opens.push(root);
140 true
141 }
142}
143
144#[derive(Clone)]
149pub struct WindowRef {
150 endpoint: WindowEndpoint,
151}
152
153impl WindowRef {
154 #[must_use = "false means there is no active component publication"]
156 pub fn request_close(&self) -> bool {
157 let mut state = self.endpoint.state.borrow_mut();
158 if state.lifecycle != WindowRequestLifecycle::Open {
159 return false;
160 }
161 let Some(active) = state.active.as_mut() else {
162 return false;
163 };
164 active.close = true;
165 true
166 }
167
168 #[cfg(test)]
169 pub(crate) fn close_committed(&self) -> bool {
170 matches!(
171 self.endpoint.state.borrow().lifecycle,
172 WindowRequestLifecycle::CloseCommitted | WindowRequestLifecycle::ClosedCommitted
173 )
174 }
175
176 pub(crate) fn request_open(&self, root: View) -> bool {
177 self.endpoint.request_open(root)
178 }
179}
180
181impl fmt::Debug for WindowRef {
182 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
183 let state = self.endpoint.state.borrow();
184 formatter
185 .debug_struct("WindowRef")
186 .field("active", &state.active.is_some())
187 .field(
188 "close_committed",
189 &matches!(
190 state.lifecycle,
191 WindowRequestLifecycle::CloseCommitted
192 | WindowRequestLifecycle::ClosedCommitted
193 ),
194 )
195 .field(
196 "open",
197 &matches!(
198 state.lifecycle,
199 WindowRequestLifecycle::Open | WindowRequestLifecycle::CloseCommitted
200 ),
201 )
202 .finish()
203 }
204}
205
206pub(crate) mod sealed {
207 pub trait Sealed {}
208}
209
210pub trait ReferenceControl: sealed::Sealed + 'static {}
215
216pub struct ElementRef<T> {
240 target: Rc<RefCell<ReferenceTarget>>,
241 marker: PhantomData<fn() -> T>,
242}
243
244impl<T: ReferenceControl> ElementRef<T> {
245 pub fn new() -> Self {
246 Self {
247 target: Rc::new(RefCell::new(ReferenceTarget::default())),
248 marker: PhantomData,
249 }
250 }
251
252 pub(crate) fn binding(&self) -> NativeElementRef {
253 NativeElementRef(Rc::clone(&self.target))
254 }
255}
256
257impl<T: FocusControl> ElementRef<T> {
258 #[must_use = "false means the reference is currently unbound"]
263 pub fn request_focus(&self) -> bool {
264 self.request_focus_result(|_| {})
265 }
266
267 #[must_use = "false means the reference is currently unbound"]
269 pub fn request_focus_result(
270 &self,
271 completion: impl Fn(Result<bool, FocusError>) + 'static,
272 ) -> bool {
273 let Some(binding) = self.target.borrow().binding.clone() else {
274 return false;
275 };
276 binding.endpoint.enqueue(NativeWork {
277 identity: binding.identity,
278 work: ImperativeRequest::Focus {
279 node: binding.node,
280 completion: Callback::new(move |result: Result<bool, RuntimeError>| {
281 completion(result.map_err(FocusError::from_runtime));
282 }),
283 },
284 })
285 }
286}
287
288impl ElementRef<crate::WebView2> {
289 #[must_use = "false means the reference is currently unbound"]
294 pub fn request_core_web_view2(
295 &self,
296 completion: impl Fn(Result<windows_core::IUnknown, WebView2Error>) + 'static,
297 ) -> bool {
298 let Some(binding) = self.target.borrow().binding.clone() else {
299 return false;
300 };
301 binding.endpoint.enqueue(NativeWork {
302 identity: binding.identity,
303 work: ImperativeRequest::InitializeWebView2 {
304 node: binding.node,
305 completion: Callback::new(
306 move |result: Result<windows_core::IUnknown, RuntimeError>| {
307 completion(result.map_err(WebView2Error::from_runtime));
308 },
309 ),
310 },
311 })
312 }
313}
314
315impl ElementRef<crate::SwapChainPanel> {
316 #[must_use = "false means the reference is currently unbound"]
318 pub fn request_set_swap_chain(
319 &self,
320 swap_chain: windows_core::IUnknown,
321 completion: impl Fn(Result<(), SwapChainPanelError>) + 'static,
322 ) -> bool {
323 self.request_swap_chain(Some(swap_chain), completion)
324 }
325
326 #[must_use = "false means the reference is currently unbound"]
328 pub fn request_clear_swap_chain(
329 &self,
330 completion: impl Fn(Result<(), SwapChainPanelError>) + 'static,
331 ) -> bool {
332 self.request_swap_chain(None, completion)
333 }
334
335 #[must_use = "the observation stops when the handle is dropped"]
340 pub fn observe_surface(
341 &self,
342 callback: impl Fn(SwapChainPanelEvent) + 'static,
343 ) -> ElementObservation {
344 self.register_observation(ReferenceObservation::SwapChainPanel(Callback::new(
345 callback,
346 )))
347 }
348
349 fn request_swap_chain(
350 &self,
351 swap_chain: Option<windows_core::IUnknown>,
352 completion: impl Fn(Result<(), SwapChainPanelError>) + 'static,
353 ) -> bool {
354 let Some(binding) = self.target.borrow().binding.clone() else {
355 return false;
356 };
357 binding.endpoint.enqueue(NativeWork {
358 identity: binding.identity,
359 work: ImperativeRequest::SetSwapChain {
360 node: binding.node,
361 swap_chain,
362 completion: Callback::new(move |result: Result<(), RuntimeError>| {
363 completion(result.map_err(SwapChainPanelError::from_runtime));
364 }),
365 },
366 })
367 }
368}
369
370impl ElementRef<crate::Image> {
371 #[must_use = "false means the reference is currently unbound"]
373 pub fn request_set_native_source(
374 &self,
375 source: Option<windows_core::IUnknown>,
376 completion: impl Fn(Result<(), ImageSourceError>) + 'static,
377 ) -> bool {
378 let Some(binding) = self.target.borrow().binding.clone() else {
379 return false;
380 };
381 binding.endpoint.enqueue(NativeWork {
382 identity: binding.identity,
383 work: ImperativeRequest::SetNativeImageSource {
384 node: binding.node,
385 source,
386 completion: Callback::new(move |result: Result<(), RuntimeError>| {
387 completion(result.map_err(ImageSourceError::from_runtime));
388 }),
389 },
390 })
391 }
392
393 #[must_use = "the observation stops when the handle is dropped"]
398 pub fn observe_rasterization_scale(
399 &self,
400 callback: impl Fn(f64) + 'static,
401 ) -> ElementObservation {
402 self.register_observation(ReferenceObservation::ImageScale(Callback::new(callback)))
403 }
404}
405
406impl ElementRef<crate::Grid> {
407 #[must_use = "the observation stops when the handle is dropped"]
412 pub fn observe_composition_host(
413 &self,
414 callback: impl Fn(CompositionHostEvent) + 'static,
415 ) -> ElementObservation {
416 self.register_observation(ReferenceObservation::CompositionHost(Callback::new(
417 callback,
418 )))
419 }
420
421 #[must_use = "false means the reference is currently unbound"]
423 pub fn request_set_child_visual(
424 &self,
425 visual: Option<windows_core::IUnknown>,
426 completion: impl Fn(Result<(), CompositionHostError>) + 'static,
427 ) -> bool {
428 let Some(binding) = self.target.borrow().binding.clone() else {
429 return false;
430 };
431 binding.endpoint.enqueue(NativeWork {
432 identity: binding.identity,
433 work: ImperativeRequest::SetCompositionChildVisual {
434 node: binding.node,
435 visual,
436 completion: Callback::new(move |result: Result<(), RuntimeError>| {
437 completion(result.map_err(CompositionHostError::from_runtime));
438 }),
439 },
440 })
441 }
442}
443
444#[derive(Clone, Debug, PartialEq)]
448pub enum CompositionHostEvent {
449 Ready {
451 compositor: windows_core::IUnknown,
452 width: f64,
453 height: f64,
454 scale: f64,
455 },
456 Metrics { width: f64, height: f64, scale: f64 },
458}
459
460#[derive(Clone, Copy, Debug, Eq, PartialEq)]
462pub enum IntegrationError {
463 Native(i32),
465 Unavailable,
467}
468
469impl IntegrationError {
470 fn from_runtime(error: RuntimeError) -> Self {
471 match error {
472 RuntimeError::Native(code) => Self::Native(code),
473 _ => Self::Unavailable,
474 }
475 }
476}
477
478pub type CompositionHostError = IntegrationError;
480pub type FocusError = IntegrationError;
482pub type ImageSourceError = IntegrationError;
484pub type SwapChainPanelError = IntegrationError;
486pub type WebView2Error = IntegrationError;
488#[derive(Clone, Copy, Debug, PartialEq)]
490pub enum SwapChainPanelEvent {
491 Metrics {
493 width: f64,
494 height: f64,
495 scale_x: f32,
496 scale_y: f32,
497 },
498 Rendering,
500}
501
502impl<T> Clone for ElementRef<T> {
503 fn clone(&self) -> Self {
504 Self {
505 target: Rc::clone(&self.target),
506 marker: PhantomData,
507 }
508 }
509}
510
511impl<T: ReferenceControl> Default for ElementRef<T> {
512 fn default() -> Self {
513 Self::new()
514 }
515}
516
517impl<T> fmt::Debug for ElementRef<T> {
518 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
519 formatter
520 .debug_struct("ElementRef")
521 .field("bound", &self.target.borrow().binding.is_some())
522 .finish()
523 }
524}
525
526impl<T> PartialEq for ElementRef<T> {
527 fn eq(&self, other: &Self) -> bool {
528 Rc::ptr_eq(&self.target, &other.target)
529 }
530}
531
532impl<T> Eq for ElementRef<T> {}
533
534pub trait FocusControl: ReferenceControl {}
539
540#[derive(Clone)]
541pub(crate) struct NativeElementRef(Rc<RefCell<ReferenceTarget>>);
542
543impl NativeElementRef {
544 pub(crate) fn identity(&self) -> usize {
545 Rc::as_ptr(&self.0) as usize
546 }
547
548 pub(crate) fn bind(&self, endpoint: ImperativeEndpoint, identity: WindowToken, node: NodeId) {
549 let reference = self.identity();
550 let previous = self.0.borrow().binding.clone();
551 let observations = {
552 let mut target = self.0.borrow_mut();
553 target.observations.retain(|observation| {
554 observation
555 .upgrade()
556 .is_some_and(|observation| observation.active.get())
557 });
558 target
559 .observations
560 .iter()
561 .filter_map(Weak::upgrade)
562 .collect::<Vec<_>>()
563 };
564 if let Some(previous) = previous {
565 previous.endpoint.retire_observations(reference);
566 for observation in &observations {
567 previous.endpoint.enqueue_observation_revocation(
568 previous.identity,
569 previous.node,
570 observation.id,
571 );
572 }
573 }
574 let binding = ReferenceBinding {
575 endpoint,
576 identity,
577 node,
578 };
579 self.0.borrow_mut().binding = Some(binding.clone());
580 let requests = observations
581 .iter()
582 .map(|observation| {
583 (
584 observation.id,
585 ObservationRegistration::request(observation, &self.0, &binding),
586 )
587 })
588 .collect();
589 binding.endpoint.replace_observations(reference, requests);
590 }
591
592 pub(crate) fn unbind(&self, identity: WindowToken, node: NodeId) {
593 let binding = self.0.borrow().binding.clone();
594 if let Some(binding) = binding
595 && binding.identity == identity
596 && binding.node == node
597 {
598 let reference = self.identity();
599 binding.endpoint.retire_observations(reference);
600 for observation in self
601 .0
602 .borrow()
603 .observations
604 .iter()
605 .filter_map(Weak::upgrade)
606 .filter(|observation| observation.active.get())
607 {
608 binding.endpoint.enqueue_observation_revocation(
609 binding.identity,
610 binding.node,
611 observation.id,
612 );
613 }
614 self.0.borrow_mut().binding = None;
615 }
616 }
617
618 pub(crate) fn binding_target(&self) -> Option<(WindowToken, NodeId)> {
619 self.0
620 .borrow()
621 .binding
622 .as_ref()
623 .map(|binding| (binding.identity, binding.node))
624 }
625}
626
627impl fmt::Debug for NativeElementRef {
628 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
629 formatter.write_str("NativeElementRef")
630 }
631}
632
633impl PartialEq for NativeElementRef {
634 fn eq(&self, other: &Self) -> bool {
635 Rc::ptr_eq(&self.0, &other.0)
636 }
637}
638
639impl Eq for NativeElementRef {}
640
641#[derive(Clone)]
642struct ReferenceBinding {
643 endpoint: ImperativeEndpoint,
644 identity: WindowToken,
645 node: NodeId,
646}
647
648#[derive(Default)]
649struct ReferenceTarget {
650 binding: Option<ReferenceBinding>,
651 observations: Vec<Weak<ObservationRegistration>>,
652}
653
654#[derive(Clone)]
655enum ReferenceObservation {
656 SwapChainPanel(Callback<SwapChainPanelEvent>),
657 ImageScale(Callback<f64>),
658 CompositionHost(Callback<CompositionHostEvent>),
659}
660
661struct ObservationRegistration {
662 active: Cell<bool>,
663 id: u64,
664 observation: ReferenceObservation,
665}
666
667impl ObservationRegistration {
668 fn request(
669 this: &Rc<Self>,
670 target: &Rc<RefCell<ReferenceTarget>>,
671 binding: &ReferenceBinding,
672 ) -> NativeWork<ImperativeRequest> {
673 let identity = binding.identity;
674 let node = binding.node;
675 let target = Rc::downgrade(target);
676 let registration = Rc::downgrade(this);
677 let work = match &this.observation {
678 ReferenceObservation::SwapChainPanel(callback) => {
679 ImperativeRequest::ObserveSwapChainPanel {
680 node,
681 observation: this.id,
682 callback: current_binding_callback(
683 target,
684 registration,
685 identity,
686 node,
687 callback.clone(),
688 ),
689 }
690 }
691 ReferenceObservation::ImageScale(callback) => ImperativeRequest::ObserveImageScale {
692 node,
693 observation: this.id,
694 callback: current_binding_callback(
695 target,
696 registration,
697 identity,
698 node,
699 callback.clone(),
700 ),
701 },
702 ReferenceObservation::CompositionHost(callback) => {
703 ImperativeRequest::ObserveCompositionHost {
704 node,
705 observation: this.id,
706 callback: current_binding_callback(
707 target,
708 registration,
709 identity,
710 node,
711 callback.clone(),
712 ),
713 }
714 }
715 };
716 NativeWork { identity, work }
717 }
718}
719
720fn current_binding_callback<T: 'static>(
721 target: Weak<RefCell<ReferenceTarget>>,
722 registration: Weak<ObservationRegistration>,
723 identity: WindowToken,
724 node: NodeId,
725 callback: Callback<T>,
726) -> Callback<T> {
727 Callback::new_with_acceptance(move |value| {
728 let active = registration
729 .upgrade()
730 .is_some_and(|registration| registration.active.get());
731 let current = active
732 && target.upgrade().is_some_and(|target| {
733 target
734 .borrow()
735 .binding
736 .as_ref()
737 .is_some_and(|binding| binding.identity == identity && binding.node == node)
738 });
739 current && callback.call(value)
740 })
741}
742
743impl<T> ElementRef<T> {
744 fn register_observation(&self, observation: ReferenceObservation) -> ElementObservation {
745 let id = NEXT_OBSERVATION_ID
746 .try_update(Ordering::Relaxed, Ordering::Relaxed, |id| id.checked_add(1))
747 .unwrap_or_else(|_| panic!("element observation identity exhausted"));
748 let registration = Rc::new(ObservationRegistration {
749 active: Cell::new(true),
750 id,
751 observation,
752 });
753 let mut target = self.target.borrow_mut();
754 target.observations.push(Rc::downgrade(®istration));
755 if let Some(binding) = &target.binding {
756 let request = ObservationRegistration::request(®istration, &self.target, binding);
757 binding
758 .endpoint
759 .enqueue_observation(self.target_identity(), registration.id, request);
760 }
761 ElementObservation {
762 reference: self.target_identity(),
763 registration,
764 target: Rc::downgrade(&self.target),
765 }
766 }
767
768 fn target_identity(&self) -> usize {
769 Rc::as_ptr(&self.target) as usize
770 }
771}
772
773pub struct ElementObservation {
779 reference: usize,
780 registration: Rc<ObservationRegistration>,
781 target: Weak<RefCell<ReferenceTarget>>,
782}
783
784impl Drop for ElementObservation {
785 fn drop(&mut self) {
786 self.registration.active.set(false);
787 let Some(target) = self.target.upgrade() else {
788 return;
789 };
790 let registration = self.registration.id;
791 let mut target = target.borrow_mut();
792 target.observations.retain(|observation| {
793 observation
794 .upgrade()
795 .is_some_and(|observation| observation.id != registration)
796 });
797 if let Some(binding) = &target.binding {
798 binding.endpoint.retire_observation(
799 self.reference,
800 registration,
801 binding.identity,
802 binding.node,
803 );
804 }
805 }
806}
807
808#[derive(Clone, Debug, PartialEq)]
809pub(crate) enum ImperativeRequest {
810 Focus {
811 node: NodeId,
812 completion: Callback<Result<bool, RuntimeError>>,
813 },
814 InitializeWebView2 {
815 node: NodeId,
816 completion: Callback<Result<windows_core::IUnknown, RuntimeError>>,
817 },
818 ObserveSwapChainPanel {
819 node: NodeId,
820 observation: u64,
821 callback: Callback<SwapChainPanelEvent>,
822 },
823 SetSwapChain {
824 node: NodeId,
825 swap_chain: Option<windows_core::IUnknown>,
826 completion: Callback<Result<(), RuntimeError>>,
827 },
828 SetNativeImageSource {
829 node: NodeId,
830 source: Option<windows_core::IUnknown>,
831 completion: Callback<Result<(), RuntimeError>>,
832 },
833 ObserveImageScale {
834 node: NodeId,
835 observation: u64,
836 callback: Callback<f64>,
837 },
838 ObserveCompositionHost {
839 node: NodeId,
840 observation: u64,
841 callback: Callback<CompositionHostEvent>,
842 },
843 RevokeObservation {
844 node: NodeId,
845 observation: u64,
846 },
847 SetCompositionChildVisual {
848 node: NodeId,
849 visual: Option<windows_core::IUnknown>,
850 completion: Callback<Result<(), RuntimeError>>,
851 },
852}
853
854impl ImperativeRequest {
855 pub(crate) fn complete_unavailable(self) {
856 match self {
857 Self::Focus { node, completion } => {
858 _ = completion.call(Err(RuntimeError::MissingNode(node)));
859 }
860 Self::InitializeWebView2 { node, completion } => {
861 _ = completion.call(Err(RuntimeError::MissingNode(node)));
862 }
863 Self::SetSwapChain {
864 node, completion, ..
865 }
866 | Self::SetNativeImageSource {
867 node, completion, ..
868 }
869 | Self::SetCompositionChildVisual {
870 node, completion, ..
871 } => {
872 _ = completion.call(Err(RuntimeError::MissingNode(node)));
873 }
874 Self::ObserveSwapChainPanel { .. }
875 | Self::ObserveImageScale { .. }
876 | Self::ObserveCompositionHost { .. }
877 | Self::RevokeObservation { .. } => {}
878 }
879 }
880}
881
882#[derive(Clone)]
883pub(crate) struct ImperativeEndpoint {
884 queue: Rc<RefCell<VecDeque<QueuedImperative>>>,
885 wake: Option<Rc<dyn Fn()>>,
886}
887
888enum QueuedImperative {
889 OneShot(NativeWork<ImperativeRequest>),
890 Observation {
891 reference: usize,
892 registration: u64,
893 request: NativeWork<ImperativeRequest>,
894 },
895}
896
897impl ImperativeEndpoint {
898 pub(crate) fn new(wake: Option<Rc<dyn Fn()>>) -> Self {
899 Self {
900 queue: Rc::new(RefCell::new(VecDeque::new())),
901 wake,
902 }
903 }
904
905 fn enqueue(&self, request: NativeWork<ImperativeRequest>) -> bool {
906 let mut queue = self.queue.borrow_mut();
907 if queue.len() >= IMPERATIVE_QUEUE_CAPACITY {
908 return false;
909 }
910 queue.push_back(QueuedImperative::OneShot(request));
911 drop(queue);
912 self.wake();
913 true
914 }
915
916 fn enqueue_observation(
917 &self,
918 reference: usize,
919 registration: u64,
920 request: NativeWork<ImperativeRequest>,
921 ) {
922 self.queue
923 .borrow_mut()
924 .push_back(QueuedImperative::Observation {
925 reference,
926 registration,
927 request,
928 });
929 self.wake();
930 }
931
932 fn replace_observations(
933 &self,
934 reference: usize,
935 requests: Vec<(u64, NativeWork<ImperativeRequest>)>,
936 ) {
937 let mut queue = self.queue.borrow_mut();
938 queue.retain(|queued| {
939 !matches!(
940 queued,
941 QueuedImperative::Observation {
942 reference: queued,
943 ..
944 } if *queued == reference
945 )
946 });
947 queue.extend(requests.into_iter().map(|(registration, request)| {
948 QueuedImperative::Observation {
949 reference,
950 registration,
951 request,
952 }
953 }));
954 drop(queue);
955 self.wake();
956 }
957
958 fn retire_observations(&self, reference: usize) {
959 self.queue.borrow_mut().retain(|queued| {
960 !matches!(
961 queued,
962 QueuedImperative::Observation {
963 reference: queued,
964 ..
965 } if *queued == reference
966 )
967 });
968 }
969
970 fn retire_observation(
971 &self,
972 reference: usize,
973 registration: u64,
974 identity: WindowToken,
975 node: NodeId,
976 ) {
977 self.queue.borrow_mut().retain(|queued| {
978 !matches!(
979 queued,
980 QueuedImperative::Observation {
981 reference: queued_reference,
982 registration: queued_registration,
983 ..
984 } if *queued_reference == reference && *queued_registration == registration
985 )
986 });
987 self.enqueue_observation_revocation(identity, node, registration);
988 }
989
990 fn enqueue_observation_revocation(
991 &self,
992 identity: WindowToken,
993 node: NodeId,
994 observation: u64,
995 ) {
996 self.queue
997 .borrow_mut()
998 .push_back(QueuedImperative::OneShot(NativeWork {
999 identity,
1000 work: ImperativeRequest::RevokeObservation { node, observation },
1001 }));
1002 self.wake();
1003 }
1004
1005 pub(crate) fn pop_front(&self) -> Option<NativeWork<ImperativeRequest>> {
1006 self.queue
1007 .borrow_mut()
1008 .pop_front()
1009 .map(|queued| match queued {
1010 QueuedImperative::OneShot(request)
1011 | QueuedImperative::Observation { request, .. } => request,
1012 })
1013 }
1014
1015 pub(crate) fn is_empty(&self) -> bool {
1016 self.queue.borrow().is_empty()
1017 }
1018
1019 pub(crate) fn clear(&self) {
1020 self.queue.borrow_mut().clear();
1021 }
1022
1023 pub(crate) fn complete_unavailable(&self) {
1024 let queued = std::mem::take(&mut *self.queue.borrow_mut());
1025 for request in queued {
1026 match request {
1027 QueuedImperative::OneShot(request)
1028 | QueuedImperative::Observation { request, .. } => {
1029 request.work.complete_unavailable();
1030 }
1031 }
1032 }
1033 }
1034
1035 fn wake(&self) {
1036 if let Some(wake) = &self.wake {
1037 wake();
1038 }
1039 }
1040}