emcell/
lib.rs

1#![no_std]
2
3#[cfg(not(feature = "rt-crate-cortex-m-rt"))]
4compile_error!("This crate requires any rt-crate-* to be enabled (when using build-rs feature)! *currently only rt-crate-cortex-m-rt is supported*");
5
6
7#[cfg(feature = "build-rs")]
8mod build_rs;
9
10use core::marker::PhantomData;
11#[cfg(feature = "build-rs")]
12pub use build_rs::*;
13
14use core::sync::atomic::AtomicBool;
15
16pub mod meta;
17
18#[cfg(not(feature = "build-rs"))]
19pub mod device;
20
21#[derive(Copy, Clone)]
22pub enum CellType {
23    Primary,
24    NonPrimary
25}
26
27#[derive(PartialEq, Copy, Clone)]
28pub enum HeaderType {
29    Actual,
30    Dummy
31}
32
33pub unsafe trait WithSignature {
34    const VALID_SIGNATURE: u32;
35}
36
37pub unsafe trait Cell: WithSignature {
38    const CUR_META: meta::CellDefMeta;
39    const CELLS_META: &'static [meta::CellDefMeta];
40    const DEVICE_CONFIG: meta::DeviceConfigMeta;
41    fn check_signature(&self, init_memory: bool) -> bool;
42    fn static_sha256(&self) -> [u8; 32] {
43        Self::CUR_META.struct_sha256
44    }
45}
46
47/// Safe cell header wrapper.
48/// If you create a CellWrapper with new_uninit, you should call ensure_init to handle
49pub struct CellWrapper<T, K>
50where T: 'static {
51    header: &'static T,
52    header_type: HeaderType,
53    is_init: AtomicBool,
54    _phantom: PhantomData<K>
55}
56
57pub struct Forward;
58pub struct Backward;
59
60impl<T> core::ops::Deref for CellWrapper<T, Forward>
61    where T: Cell + 'static {
62    type Target = T;
63    fn deref(&self) -> &Self::Target {
64        if !self.is_init.load(core::sync::atomic::Ordering::Relaxed) {
65            //attempt to initialize
66            if self.ensure_init().is_some() {
67                self.is_init.store(true, core::sync::atomic::Ordering::Relaxed);
68                return self.header;
69            }
70            panic!("CellWrapper initialization failed!");
71        }
72        self.header
73    }
74}
75
76
77impl<T> core::ops::Deref for CellWrapper<T, Backward>
78    where T: Cell + 'static {
79    type Target = T;
80    fn deref(&self) -> &Self::Target {
81        if !self.is_init.load(core::sync::atomic::Ordering::Relaxed) {
82            //attempt to initialize
83            if self.ensure_init().is_some() {
84                self.is_init.store(true, core::sync::atomic::Ordering::Relaxed);
85                return self.header;
86            }
87            panic!("CellWrapper initialization failed!");
88        }
89        self.header
90    }
91}
92
93
94impl<T, K> CellWrapper<T, K>
95    where T: Cell + 'static {
96    pub const unsafe fn _new_uninit(h: &'static T) -> Self {
97        Self {
98            header: h,
99            header_type: HeaderType::Actual,
100            is_init: AtomicBool::new(false),
101            _phantom: PhantomData
102        }
103    }
104
105    pub const fn new_dummy(dummy_header: &'static T) -> Self {
106        Self {
107            header: dummy_header,
108            header_type: HeaderType::Dummy,
109            is_init: AtomicBool::new(true),
110            _phantom: PhantomData
111        }
112    }
113}
114
115
116impl<T> CellWrapper<T, Forward>
117    where T: Cell + 'static {
118    pub unsafe fn _new_init(h: &'static T) -> Option<Self> {
119        if !h.check_signature(true) {
120            return None;
121        }
122
123        Some(Self {
124            header: h,
125            header_type: HeaderType::Actual,
126            is_init: AtomicBool::new(true),
127            _phantom: PhantomData
128        })
129    }
130
131    /// If header wrapper was created with new_uninit, this function must be called to potentially initialize other cell's memory.
132    pub fn ensure_init(&self) -> Option<()> {
133        if self.is_init.load(core::sync::atomic::Ordering::Relaxed) {
134            return Some(());
135        }
136        //init
137        if !self.header.check_signature(true) {
138            return None;
139        }
140        self.is_init.store(true, core::sync::atomic::Ordering::Relaxed);
141        Some(())
142    }
143
144    pub fn is_dummy(&self) -> bool {
145        self.header_type == HeaderType::Dummy
146    }
147}
148
149
150
151impl<T> CellWrapper<T, Backward>
152    where T: Cell + 'static {
153    pub unsafe fn _new_init(h: &'static T) -> Option<Self> {
154        if !h.check_signature(false) {
155            return None;
156        }
157
158        Some(Self {
159            header: h,
160            header_type: HeaderType::Actual,
161            is_init: AtomicBool::new(true),
162            _phantom: PhantomData
163        })
164    }
165
166    /// If header wrapper was created with new_uninit, this function must be called to potentially initialize other cell's memory.
167    pub fn ensure_init(&self) -> Option<()> {
168        if self.is_init.load(core::sync::atomic::Ordering::Relaxed) {
169            return Some(());
170        }
171        //init
172        if !self.header.check_signature(false) {
173            return None;
174        }
175        self.is_init.store(true, core::sync::atomic::Ordering::Relaxed);
176        Some(())
177    }
178
179    pub fn is_dummy(&self) -> bool {
180        self.header_type == HeaderType::Dummy
181    }
182}