cranpose_core/
composer_context.rs1use std::{
2 rc::Rc,
3 sync::atomic::{AtomicUsize, Ordering},
4};
5
6use crate::{Composer, ComposerCore, thread_state};
7
8static INSTALLED_COMPOSERS: AtomicUsize = AtomicUsize::new(0);
12
13fn any_composer_installed() -> bool {
15 INSTALLED_COMPOSERS.load(Ordering::Relaxed) != 0
16}
17
18#[must_use = "ComposerScopeGuard restores the previous composer on drop"]
20pub struct ComposerScopeGuard {
21 previous: Option<Rc<ComposerCore>>,
22}
23
24impl Drop for ComposerScopeGuard {
25 fn drop(&mut self) {
26 replace_current(self.previous.take());
27 }
28}
29
30pub fn enter(composer: &Composer) -> ComposerScopeGuard {
33 ComposerScopeGuard {
34 previous: replace_current(Some(composer.clone_core())),
35 }
36}
37
38fn replace_current(composer: Option<Rc<ComposerCore>>) -> Option<Rc<ComposerCore>> {
39 let installs = composer.is_some();
40 let previous = thread_state::runtimes(|state| state.current_composer.replace(composer));
41 match (previous.is_some(), installs) {
42 (false, true) => {
43 INSTALLED_COMPOSERS.fetch_add(1, Ordering::Relaxed);
44 }
45 (true, false) => {
46 INSTALLED_COMPOSERS.fetch_sub(1, Ordering::Relaxed);
47 }
48 _ => {}
49 }
50 previous
51}
52
53pub(crate) fn without_composer<R>(f: impl FnOnce() -> R) -> R {
54 let _suspended = ComposerScopeGuard {
55 previous: replace_current(None),
56 };
57 f()
58}
59
60pub fn with_composer<R>(f: impl FnOnce(&Composer) -> R) -> R {
65 thread_state::runtimes(|state| {
66 let core = state
67 .current_composer
68 .borrow()
69 .as_ref()
70 .expect("with_composer: no active composer")
71 .clone();
72 let composer = Composer::from_core(core);
73 f(&composer)
74 })
75}
76
77#[doc(hidden)]
82pub fn __current_composer() -> Composer {
83 thread_state::runtimes(|state| {
84 Composer::from_core(
85 state
86 .current_composer
87 .borrow()
88 .as_ref()
89 .expect("with_composer: no active composer")
90 .clone(),
91 )
92 })
93}
94
95pub(crate) fn with_current_core<R>(f: impl FnOnce(&ComposerCore) -> R) -> Option<R> {
96 if !any_composer_installed() {
97 return None;
98 }
99 thread_state::try_runtimes(|state| state.current_composer.borrow().as_deref().map(f)).flatten()
100}
101
102pub fn current_composer() -> Option<Composer> {
104 if !any_composer_installed() {
105 return None;
106 }
107 thread_state::try_runtimes(|state| {
108 let core = state.current_composer.borrow().as_ref()?.clone();
109 Some(Composer::from_core(core))
110 })
111 .flatten()
112}
113
114pub fn note_nested_slots_host(host: &std::rc::Rc<crate::SlotsHost>) {
115 let Some(composer) = current_composer() else {
116 return;
117 };
118 let holder = composer.active_slots_host();
119 if std::rc::Rc::ptr_eq(&holder, host) {
120 return;
121 }
122 holder.note_nested_host(host);
123}
124
125pub fn try_with_composer<R>(f: impl FnOnce(&Composer) -> R) -> Option<R> {
128 current_composer().map(|composer| f(&composer))
129}