Skip to main content

rgpui/
global.rs

1//! # 全局状态系统
2//!
3//! RGPUI 的全局状态系统允许你在应用级别共享数据,而无需通过实体传递。
4//! 全局状态通过 [`Global`] trait 标记类型,通过 [`App`] 的方法进行访问。
5//!
6//! # 使用示例
7//!
8//! ```rust,ignore
9//! use rgpui::Global;
10//!
11//! /// 应用的主题配置
12//! struct ThemeConfig {
13//!     dark_mode: bool,
14//! }
15//!
16//! impl Global for ThemeConfig {}
17//!
18//! // 在 App 中设置全局状态
19//! cx.set_global(ThemeConfig { dark_mode: true });
20//!
21//! // 读取全局状态
22//! let theme = cx.global::<ThemeConfig>();
23//! ```
24//!
25//! # 限制访问
26//!
27//! 可以利用 Rust 的可见性系统限制全局状态的读写访问。
28//! 例如创建私有结构体实现 `Global`,然后通过 newtype 封装暴露有限的操作。
29
30use crate::{App, BorrowAppContext};
31
32/// 全局状态标记 trait - 实现此 trait 的类型可以存储在 RGPUI 的全局状态中。
33///
34/// 此 trait 确保只有实现了 `Global` 的类型才能使用全局访问方法,
35/// 在编译时防止误用。
36///
37/// 此 trait 故意留空,仅作为标记使用。
38/// 可以通过 blanket 实现附加功能到实现了 `Global` 的类型上。
39pub trait Global: 'static {
40    // 此 trait 故意留空,仅作为标记使用
41}
42
43/// 从上下文中读取全局值的 trait。
44pub trait ReadGlobal {
45    /// 返回实现类型的全局实例。
46    ///
47    /// 如果该类型的全局值尚未设置,会触发 panic。
48    fn global(cx: &App) -> &Self;
49}
50
51impl<T: Global> ReadGlobal for T {
52    fn global(cx: &App) -> &Self {
53        cx.global::<T>()
54    }
55}
56
57/// 在上下文中更新全局值的 trait。
58pub trait UpdateGlobal {
59    /// 使用提供的闭包更新全局实例。
60    ///
61    /// 闭包同时接收全局值的可变引用和上下文的可变引用。
62    fn update_global<C, F, R>(cx: &mut C, update: F) -> R
63    where
64        C: BorrowAppContext,
65        F: FnOnce(&mut Self, &mut C) -> R;
66
67    /// 设置全局实例。
68    fn set_global<C>(cx: &mut C, global: Self)
69    where
70        C: BorrowAppContext;
71}
72
73impl<T: Global> UpdateGlobal for T {
74    #[track_caller]
75    fn update_global<C, F, R>(cx: &mut C, update: F) -> R
76    where
77        C: BorrowAppContext,
78        F: FnOnce(&mut Self, &mut C) -> R,
79    {
80        cx.update_global(update)
81    }
82
83    fn set_global<C>(cx: &mut C, global: Self)
84    where
85        C: BorrowAppContext,
86    {
87        cx.set_global(global)
88    }
89}