1use std::any::Any;
2
3pub(crate) struct ManagedState {
5 state: Vec<Tracked>,
6}
7
8enum Tracked {
9 Begin { id: u64, state: Box<dyn Any + Send + Sync> },
10 End,
11}
12
13#[doc(hidden)]
14pub struct ManagedStateTracker<'a> {
15 tracker: &'a mut ManagedState,
16 index: usize,
17}
18
19impl ManagedState {
20 pub fn tracker(&mut self) -> ManagedStateTracker {
24 ManagedStateTracker {
25 tracker: self,
26 index: 0,
27 }
28 }
29}
30
31impl Default for ManagedState {
32 fn default() -> Self {
33 Self { state: Vec::new() }
34 }
35}
36
37impl Tracked {
38 unsafe fn unchecked_mut_ref<'a, T: Any + Send + Sync>(&mut self) -> &'a mut T {
39 match self {
40 Tracked::Begin { state, .. } => {
41 let state = state
42 .downcast_mut::<T>()
43 .expect("widgets with the same id must always be of the same type");
44
45 (state as *mut T).as_mut().unwrap()
46 }
47 _ => unreachable!(),
48 }
49 }
50}
51
52impl<'a> ManagedStateTracker<'a> {
53 pub(crate) fn begin<'i, T, F>(&mut self, id: u64, default: F) -> &'i mut T
56 where
57 T: Any + Send + Sync,
58 F: FnOnce() -> T,
59 {
60 let search_start = self.index;
61 let mut level = 0;
62
63 while self.index < self.tracker.state.len() {
64 match &self.tracker.state[self.index] {
65 Tracked::End if level > 0 => level -= 1,
66 Tracked::End => {
67 self.index = search_start;
69 break;
70 }
71 &Tracked::Begin { id: tid, state: _ } if level == 0 && tid == id => {
72 self.tracker.state.splice(search_start..self.index, None);
73 unsafe {
74 let i = search_start;
75 self.index = search_start + 1;
76 return self.tracker.state[i].unchecked_mut_ref();
77 }
78 }
79 &Tracked::Begin { .. } => level += 1,
80 }
81 self.index += 1;
82 }
83
84 let i = self.index;
85 let state = Box::new(default()) as Box<dyn Any + Send + Sync>;
86 self.tracker.state.insert(i, Tracked::Begin { id, state });
87 self.tracker.state.insert(i + 1, Tracked::End);
88 self.index += 1;
89 unsafe { self.tracker.state[i].unchecked_mut_ref() }
90 }
91
92 pub(crate) fn end(&mut self) {
95 let search_start = self.index;
96 let mut level = 0;
97
98 while self.index < self.tracker.state.len() {
99 match &self.tracker.state[self.index] {
100 Tracked::Begin { .. } => {
101 self.index += 1;
102 level += 1;
103 }
104 Tracked::End if level > 0 => {
105 self.index += 1;
106 level -= 1;
107 }
108 Tracked::End => {
109 self.tracker.state.splice(search_start..self.index, None);
111 self.index = search_start + 1;
112 return;
113 }
114 }
115 }
116
117 unreachable!("did not find `End` at the end.");
118 }
119}
120
121impl<'a> Drop for ManagedStateTracker<'a> {
122 fn drop(&mut self) {
123 while self.index < self.tracker.state.len() {
124 self.tracker.state.pop();
125 }
126 }
127}