indexbus_kit/embedded/
static_spsc.rs

1use core::cell::UnsafeCell;
2use core::mem::MaybeUninit;
3use core::sync::atomic::{AtomicBool, Ordering};
4
5use crate::errors::{Error, Result};
6
7use indexbus_abi::layouts::SharedLayout;
8use indexbus_core::{init_shared_layout, split_spsc, SharedLayoutCell, SpscReceiver, SpscSender};
9
10struct StaticShared(UnsafeCell<MaybeUninit<SharedLayout>>);
11
12// Example-only: we rely on single-threaded init and a stable address, without `static mut`.
13unsafe impl Sync for StaticShared {}
14
15static SHARED: StaticShared = StaticShared(UnsafeCell::new(MaybeUninit::uninit()));
16static TAKEN: AtomicBool = AtomicBool::new(false);
17
18/// Create an SPSC sender/receiver backed by a statically allocated `SharedLayout`.
19///
20/// Notes:
21/// - This is intended for embedded-ish demonstrations and algorithmic reuse.
22/// - This is **single-use**: it hands out handles into a single static region.
23/// - Calling this more than once returns an error (to avoid re-initialization while old handles
24///   may still exist).
25pub fn static_spsc() -> Result<(SpscSender, SpscReceiver)> {
26    // This is a demo helper. The core safety issue is re-initializing the same static region
27    // while previously returned handles may still be live.
28    if TAKEN.swap(true, Ordering::AcqRel) {
29        return Err(Error::msg(
30            "static_spsc() is single-use (static region already taken)",
31        ));
32    }
33
34    let shared_ptr: *mut SharedLayout = unsafe {
35        let slot = SHARED.0.get();
36        (*slot).as_mut_ptr().write(core::mem::zeroed());
37        (*slot).as_mut_ptr()
38    };
39
40    let shared: &mut SharedLayout = unsafe { &mut *shared_ptr };
41    init_shared_layout(shared);
42
43    let cell = unsafe { SharedLayoutCell::from_ptr(shared_ptr) };
44    split_spsc(cell).map_err(Error::from)
45}