ratatui_kit/
context.rs

1use std::{
2    any::Any,
3    cell::{Ref, RefCell, RefMut},
4};
5
6pub enum Context<'a> {
7    Ref(&'a (dyn Any + Send + Sync)),
8    Mut(&'a mut (dyn Any + Send + Sync)),
9    Owned(Box<dyn Any + Send + Sync>),
10}
11
12impl<'a> Context<'a> {
13    pub fn owned<T: Any + Send + Sync>(context: T) -> Self {
14        Context::Owned(Box::new(context))
15    }
16
17    pub fn form_ref<T: Any + Send + Sync>(context: &'a T) -> Self {
18        Context::Ref(context)
19    }
20
21    pub fn form_mut<T: Any + Send + Sync>(context: &'a mut T) -> Self {
22        Context::Mut(context)
23    }
24
25    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
26        match self {
27            Context::Ref(context) => context.downcast_ref(),
28            Context::Mut(context) => context.downcast_ref(),
29            Context::Owned(context) => context.downcast_ref(),
30        }
31    }
32
33    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
34        match self {
35            Context::Ref(_) => None,
36            Context::Mut(context) => context.downcast_mut(),
37            Context::Owned(context) => context.downcast_mut(),
38        }
39    }
40
41    pub fn borrow(&mut self) -> Context {
42        match self {
43            Context::Ref(context) => Context::Ref(*context),
44            Context::Mut(context) => Context::Mut(*context),
45            Context::Owned(context) => Context::Mut(&mut **context),
46        }
47    }
48}
49
50pub struct ContextStack<'a> {
51    stack: Vec<RefCell<Context<'a>>>,
52}
53
54impl<'a> ContextStack<'a> {
55    pub(crate) fn root(root_context: &'a mut (dyn Any + Send + Sync)) -> Self {
56        ContextStack {
57            stack: vec![RefCell::new(Context::Mut(root_context))],
58        }
59    }
60    // 在上下文栈中临时插入一个新的上下文,并在闭包 f 执行期间可用。
61    pub(crate) fn with_context<'b, F>(&'b mut self, context: Option<Context<'b>>, f: F)
62    where
63        F: FnOnce(&mut ContextStack),
64    {
65        if let Some(context) = context {
66            // SAFETY: 可变引用在生命周期上是不变的,为了插入更短生命周期的上下文,需要对 'a 进行转变。
67            // 只有在不允许对栈进行其他更改,并且在调用后立即恢复栈的情况下才是安全的。
68            let shorter_lived_self =
69                unsafe { std::mem::transmute::<&mut Self, &mut ContextStack<'b>>(self) };
70            shorter_lived_self.stack.push(RefCell::new(context));
71            f(shorter_lived_self);
72            shorter_lived_self.stack.pop();
73        } else {
74            f(self);
75        };
76    }
77
78    pub fn get_context<T: Any>(&self) -> Option<Ref<T>> {
79        for context in self.stack.iter().rev() {
80            if let Ok(context) = context.try_borrow() {
81                if let Ok(res) = Ref::filter_map(context, |context| context.downcast_ref::<T>()) {
82                    return Some(res);
83                }
84            }
85        }
86        None
87    }
88
89    pub fn get_context_mut<T: Any>(&self) -> Option<RefMut<T>> {
90        for context in self.stack.iter().rev() {
91            if let Ok(context) = context.try_borrow_mut() {
92                if let Ok(res) = RefMut::filter_map(context, |context| context.downcast_mut::<T>())
93                {
94                    return Some(res);
95                }
96            }
97        }
98        None
99    }
100}
101
102pub struct SystemContext {
103    should_exit: bool,
104}
105
106unsafe impl Send for SystemContext {}
107unsafe impl Sync for SystemContext {}
108
109impl SystemContext {
110    pub(crate) fn new() -> Self {
111        Self { should_exit: false }
112    }
113
114    pub(crate) fn should_exit(&self) -> bool {
115        self.should_exit
116    }
117
118    pub fn exit(&mut self) {
119        self.should_exit = true;
120    }
121}