zencan_node/object_dict/
object_flags.rs1use core::cell::UnsafeCell;
2
3use critical_section::Mutex;
4use zencan_common::AtomicCell;
5
6#[derive(Debug)]
9pub struct ObjectFlagSync {
10 inner: Mutex<UnsafeCell<ObjectFlagsInner>>,
11}
12
13impl Default for ObjectFlagSync {
14 fn default() -> Self {
15 Self::new()
16 }
17}
18
19#[derive(Clone, Copy, Debug)]
20struct ObjectFlagsInner {
21 toggle: bool,
23 global_flag: bool,
25}
26
27impl ObjectFlagSync {
28 pub const fn new() -> Self {
30 Self {
31 inner: Mutex::new(UnsafeCell::new(ObjectFlagsInner {
32 toggle: false,
33 global_flag: false,
34 })),
35 }
36 }
37
38 pub fn toggle(&self) -> bool {
40 critical_section::with(|cs| {
41 let inner = self.inner.borrow(cs).get();
42 unsafe {
44 let global = (*inner).global_flag;
45 (*inner).global_flag = false;
46 (*inner).toggle = !(*inner).toggle;
47 global
48 }
49 })
50 }
51
52 pub fn get_flag(&self, setting: bool) -> bool {
56 critical_section::with(|cs| {
57 let inner = unsafe { &mut (*self.inner.borrow(cs).get()) };
58 inner.global_flag |= setting;
59 inner.toggle
60 })
61 }
62}
63
64#[allow(missing_debug_implementations)]
74pub struct ObjectFlags<const N: usize> {
75 sync: &'static ObjectFlagSync,
76 flags0: AtomicCell<[u8; N]>,
77 flags1: AtomicCell<[u8; N]>,
78}
79
80pub trait ObjectFlagAccess {
82 fn set_flag(&self, sub: u8);
86 fn get_flag(&self, sub: u8) -> bool;
91 fn clear(&self);
93}
94
95impl<const N: usize> ObjectFlags<N> {
96 pub const fn new(sync: &'static ObjectFlagSync) -> Self {
98 Self {
99 sync,
100 flags0: AtomicCell::new([0; N]),
101 flags1: AtomicCell::new([0; N]),
102 }
103 }
104}
105
106impl<const N: usize> ObjectFlagAccess for ObjectFlags<N> {
107 fn set_flag(&self, sub: u8) {
108 if sub as usize >= N * 8 {
109 return;
110 }
111 let flags = if self.sync.get_flag(true) {
112 &self.flags0
113 } else {
114 &self.flags1
115 };
116 flags
117 .fetch_update(|mut f| {
118 f[sub as usize / 8] |= 1 << (sub & 7);
119 Some(f)
120 })
121 .unwrap();
122 }
123
124 fn get_flag(&self, sub: u8) -> bool {
125 if sub as usize >= N * 8 {
126 return false;
127 }
128 let flags = if self.sync.get_flag(false) {
129 &self.flags1.load()
130 } else {
131 &self.flags0.load()
132 };
133 flags[(sub / 8) as usize] & (1 << (sub & 7)) != 0
134 }
135
136 fn clear(&self) {
137 if self.sync.get_flag(false) {
138 self.flags1.store([0; N]);
139 } else {
140 self.flags0.store([0; N]);
141 }
142 }
143}