cu_embedded_registry/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[cfg(not(feature = "std"))]
4extern crate alloc;
5
6#[cfg(not(feature = "std"))]
7use alloc::{boxed::Box, format};
8use core::any::{Any, TypeId};
9use cu29::prelude::*;
10use embedded_io::{Read, Write};
11use spin::Mutex;
12
13type SerialEntry = Box<dyn Any + Send>;
14
15struct SerialSlot {
16 type_id: TypeId,
17 entry: SerialEntry,
18}
19
20pub const MAX_SERIAL_SLOTS: usize = 8;
21
22struct SerialSlots {
23 entries: [Option<SerialSlot>; MAX_SERIAL_SLOTS],
24}
25
26impl SerialSlots {
27 const fn new() -> Self {
28 Self {
29 entries: [None, None, None, None, None, None, None, None],
30 }
31 }
32}
33
34static SERIAL_SLOTS: Mutex<SerialSlots> = Mutex::new(SerialSlots::new());
35
36pub fn register<S, E>(slot: usize, serial: S) -> CuResult<()>
47where
48 S: Write<Error = E> + Read<Error = E> + Send + 'static,
49{
50 if slot >= MAX_SERIAL_SLOTS {
51 return Err(CuError::from(format!(
52 "Serial registry slot {slot} out of range (max {MAX_SERIAL_SLOTS})"
53 )));
54 }
55 let mut slots = SERIAL_SLOTS.lock();
56 slots.entries[slot] = Some(SerialSlot {
57 type_id: TypeId::of::<S>(),
58 entry: Box::new(serial),
59 });
60 Ok(())
61}
62
63pub fn take<S, E>(slot: usize) -> Option<S>
74where
75 S: Write<Error = E> + Read<Error = E> + Send + 'static,
76{
77 if slot >= MAX_SERIAL_SLOTS {
78 return None;
79 }
80 let mut slots = SERIAL_SLOTS.lock();
81 let record = slots.entries[slot].take()?;
82 if record.type_id != TypeId::of::<S>() {
83 slots.entries[slot] = Some(record);
84 return None;
85 }
86 record.entry.downcast::<S>().map(|boxed| *boxed).ok()
87}
88
89pub fn slot_status() -> [bool; MAX_SERIAL_SLOTS] {
95 let slots = SERIAL_SLOTS.lock();
96 let mut status = [false; MAX_SERIAL_SLOTS];
97 for (i, slot) in slots.entries.iter().enumerate() {
98 status[i] = slot.is_some();
99 }
100 status
101}
102
103#[cfg(test)]
105pub fn clear_all() {
106 let mut slots = SERIAL_SLOTS.lock();
107 for slot in &mut slots.entries {
108 *slot = None;
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115 use embedded_io::{ErrorKind, ErrorType};
116
117 #[derive(Debug)]
118 struct TestError;
119
120 impl embedded_io::Error for TestError {
121 fn kind(&self) -> ErrorKind {
122 ErrorKind::Other
123 }
124 }
125
126 struct MockSerial;
127
128 impl ErrorType for MockSerial {
129 type Error = TestError;
130 }
131
132 impl embedded_io::Write for MockSerial {
133 fn write(&mut self, _buf: &[u8]) -> Result<usize, Self::Error> {
134 Ok(0)
135 }
136
137 fn flush(&mut self) -> Result<(), Self::Error> {
138 Ok(())
139 }
140 }
141
142 impl embedded_io::Read for MockSerial {
143 fn read(&mut self, _buf: &mut [u8]) -> Result<usize, Self::Error> {
144 Ok(0)
145 }
146 }
147
148 #[test]
149 fn test_register_and_take() {
150 clear_all();
151
152 let serial = MockSerial;
153 assert!(register(0, serial).is_ok());
154
155 let status = slot_status();
156 assert!(status[0]);
157 assert!(!status[1]);
158
159 let recovered: Option<MockSerial> = take(0);
160 assert!(recovered.is_some());
161
162 let status = slot_status();
163 assert!(!status[0]);
164 }
165
166 #[test]
167 fn test_slot_bounds() {
168 clear_all();
169
170 let serial = MockSerial;
171 assert!(register(MAX_SERIAL_SLOTS, serial).is_err());
172
173 let recovered: Option<MockSerial> = take(MAX_SERIAL_SLOTS);
174 assert!(recovered.is_none());
175 }
176}