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
13#[inline]
15fn any_composer_installed() -> bool {
16 INSTALLED_COMPOSERS.load(Ordering::Relaxed) != 0
17}
18
19#[must_use = "ComposerScopeGuard restores the previous composer on drop"]
21pub struct ComposerScopeGuard {
22 previous: Option<Rc<ComposerCore>>,
23}
24
25impl Drop for ComposerScopeGuard {
26 fn drop(&mut self) {
27 replace_current(self.previous.take());
28 }
29}
30
31pub fn enter(composer: &Composer) -> ComposerScopeGuard {
34 ComposerScopeGuard {
35 previous: replace_current(Some(composer.clone_core())),
36 }
37}
38
39fn replace_current(composer: Option<Rc<ComposerCore>>) -> Option<Rc<ComposerCore>> {
40 let installs = composer.is_some();
41 let previous = thread_state::runtimes(|state| state.current_composer.replace(composer));
42 match (previous.is_some(), installs) {
43 (false, true) => {
44 INSTALLED_COMPOSERS.fetch_add(1, Ordering::Relaxed);
45 }
46 (true, false) => {
47 INSTALLED_COMPOSERS.fetch_sub(1, Ordering::Relaxed);
48 }
49 _ => {}
50 }
51 previous
52}
53
54pub(crate) fn without_composer<R>(f: impl FnOnce() -> R) -> R {
55 let _suspended = ComposerScopeGuard {
56 previous: replace_current(None),
57 };
58 f()
59}
60
61pub fn with_composer<R>(f: impl FnOnce(&Composer) -> R) -> R {
66 thread_state::runtimes(|state| {
67 let core = state
68 .current_composer
69 .borrow()
70 .as_ref()
71 .expect("with_composer: no active composer")
72 .clone();
73 let composer = Composer::from_core(core);
74 f(&composer)
75 })
76}
77
78#[doc(hidden)]
83pub fn __current_composer() -> Composer {
84 thread_state::runtimes(|state| {
85 Composer::from_core(
86 state
87 .current_composer
88 .borrow()
89 .as_ref()
90 .expect("with_composer: no active composer")
91 .clone(),
92 )
93 })
94}
95
96#[inline]
101pub(crate) fn with_current_core<R>(f: impl FnOnce(&ComposerCore) -> R) -> Option<R> {
102 if !any_composer_installed() {
103 return None;
104 }
105 with_installed_core(f)
106}
107
108#[inline(never)]
109fn with_installed_core<R>(f: impl FnOnce(&ComposerCore) -> R) -> Option<R> {
110 thread_state::try_runtimes(|state| state.current_composer.borrow().as_deref().map(f)).flatten()
111}
112
113pub fn current_composer() -> Option<Composer> {
115 if !any_composer_installed() {
116 return None;
117 }
118 thread_state::try_runtimes(|state| {
119 let core = state.current_composer.borrow().as_ref()?.clone();
120 Some(Composer::from_core(core))
121 })
122 .flatten()
123}
124
125pub fn note_nested_slots_host(host: &std::rc::Rc<crate::SlotsHost>) {
129 let Some(composer) = current_composer() else {
130 return;
131 };
132 let holder = composer.active_slots_host();
133 if std::rc::Rc::ptr_eq(&holder, host) {
134 return;
135 }
136 holder.note_nested_host(host);
137}
138
139pub fn try_with_composer<R>(f: impl FnOnce(&Composer) -> R) -> Option<R> {
142 current_composer().map(|composer| f(&composer))
143}