1pub const CONFIG_REGION_WASM_OFFSET: u32 = 0x24000;
20
21pub const MAX_CONFIG_PARAMS: usize = 32;
23
24#[derive(Clone, Copy)]
29#[repr(C)]
30pub struct ConfigRegion {
31 pub version: u8,
33 pub param_count: u8,
35 pub update_seq: u16,
37 pub _pad: [u8; 4],
38 pub update_ns: u64,
40 pub params: [i64; MAX_CONFIG_PARAMS],
42 pub types: [u8; MAX_CONFIG_PARAMS],
44}
45
46impl Default for ConfigRegion {
47 fn default() -> Self {
48 Self {
49 version: 1,
50 param_count: 0,
51 update_seq: 0,
52 _pad: [0; 4],
53 update_ns: 0,
54 params: [0; MAX_CONFIG_PARAMS],
55 types: [0; MAX_CONFIG_PARAMS],
56 }
57 }
58}
59
60pub mod ParamType {
62 pub const INT: u8 = 0;
64 pub const FLOAT: u8 = 1;
66 pub const BOOL: u8 = 2;
68 pub const BPS: u8 = 3;
70}
71
72impl ConfigRegion {
73 #[cfg(target_arch = "wasm32")]
78 #[inline(always)]
79 pub unsafe fn read() -> &'static Self {
80 &*(CONFIG_REGION_WASM_OFFSET as *const Self)
81 }
82
83 #[inline(always)]
85 pub fn get_i64(&self, slot: usize) -> i64 {
86 if slot < MAX_CONFIG_PARAMS { self.params[slot] } else { 0 }
87 }
88
89 #[inline(always)]
91 pub fn get_i32(&self, slot: usize) -> i32 {
92 self.get_i64(slot) as i32
93 }
94
95 #[inline(always)]
97 pub fn get_f64(&self, slot: usize) -> f64 {
98 f64::from_bits(self.get_i64(slot) as u64)
99 }
100
101 #[inline(always)]
103 pub fn get_bool(&self, slot: usize) -> bool {
104 self.get_i64(slot) != 0
105 }
106
107 #[inline(always)]
109 pub fn get_bps(&self, slot: usize) -> i32 {
110 self.get_i32(slot)
111 }
112
113 #[inline(always)]
115 pub fn is_updated(&self, last_seq: u16) -> bool {
116 self.update_seq != last_seq
117 }
118
119 #[inline(always)]
121 pub fn count(&self) -> usize {
122 self.param_count as usize
123 }
124}
125
126const _: () = assert!(
128 core::mem::size_of::<ConfigRegion>() == 304,
129 "ConfigRegion must be exactly 304 bytes"
130);
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn config_region_size() {
138 assert_eq!(core::mem::size_of::<ConfigRegion>(), 304);
140 }
141
142 #[test]
143 fn config_region_get_params() {
144 let mut config = ConfigRegion::default();
145 config.param_count = 3;
146 config.params[0] = 50; config.params[1] = 1_000_000_000; config.params[2] = f64::to_bits(0.5) as i64; config.types[0] = ParamType::BPS;
150 config.types[1] = ParamType::INT;
151 config.types[2] = ParamType::FLOAT;
152
153 assert_eq!(config.get_bps(0), 50);
154 assert_eq!(config.get_i64(1), 1_000_000_000);
155 assert!((config.get_f64(2) - 0.5).abs() < 0.001);
156 }
157
158 #[test]
159 fn config_region_update_detection() {
160 let mut config = ConfigRegion::default();
161 assert!(!config.is_updated(0));
162 config.update_seq = 1;
163 assert!(config.is_updated(0));
164 assert!(!config.is_updated(1));
165 }
166
167 #[test]
168 fn config_region_out_of_bounds() {
169 let config = ConfigRegion::default();
170 assert_eq!(config.get_i64(99), 0);
171 assert_eq!(config.get_i32(99), 0);
172 }
173}