embedded_shadow/
lib.rs

1//! A `no_std`, no-alloc shadow register table for embedded systems.
2//!
3//! This crate provides efficient shadow register management with dirty tracking,
4//! suitable for memory-mapped I/O, peripheral register caching, and state synchronization
5//! between application and hardware layers.
6//!
7//! # Features
8//!
9//! - **Zero heap allocation** - All storage statically allocated
10//! - **Block-based dirty tracking** - Efficiently track modifications
11//! - **Dual access patterns** - Host (application) and Kernel (hardware) views
12//! - **Flexible policies** - Customizable access control and persistence
13//! - **Transactional writes** - Optional staging with commit/rollback
14//!
15//! # Architecture
16//!
17//! The shadow registry uses a **one-way dirty tracking model**:
18//!
19//! ```text
20//! ┌──────────────────┐         ┌──────────────────────────┐
21//! │   Host (App)     │         │   Kernel (HW)            │
22//! │                  │         │                          │
23//! │  write_range()   │────────▶│  for_each_dirty_block()  │
24//! │  (marks dirty)   │  dirty  │  (reads dirty)           │
25//! │                  │  bits   │                          │
26//! │                  │◀────────│  clear_dirty()           │
27//! │                  │  reset  │  write_range()           │
28//! │                  │         │  (no dirty mark)         │
29//! └──────────────────┘         └──────────────────────────┘
30//! ```
31//!
32//! - **Host writes** mark blocks as dirty and may trigger persistence
33//! - **Kernel reads** dirty state to sync changes to hardware
34//! - **Kernel writes** update the shadow (e.g., after reading from hardware) without marking dirty
35//! - **Kernel clears** dirty bits after syncing
36//!
37//! This design enables efficient one-way synchronization from application to hardware.
38//!
39//! # Example
40//!
41//! ```rust,no_run
42//! use embedded_shadow::prelude::*;
43//!
44//! // Create storage: 1KB total, 64-byte blocks, 16 blocks
45//! let storage = ShadowStorageBuilder::new()
46//!     .total_size::<1024>()
47//!     .block_size::<64>()
48//!     .block_count::<16>()
49//!     .default_access()
50//!     .no_persist()
51//!     .build();
52//!
53//! // Load factory defaults at boot (doesn't mark dirty)
54//! storage.load_defaults(|write| {
55//!     write(0x000, &[0x01, 0x02, 0x03, 0x04])?;
56//!     write(0x100, &[0xAA, 0xBB, 0xCC, 0xDD])?;
57//!     Ok(())
58//! }).unwrap();
59//!
60//! // host_shadow() and kernel_shadow() return short-lived references,
61//! // typically constructed each iteration and passed via context, e.g.:
62//! //   fn update(ctx: &mut HostContext) { ctx.shadow.with_view(|view| { ... }); }
63//! //   fn run_once(ctx: &mut KernelContext) { ctx.shadow.with_view_unchecked(|view| { ... }); }
64//!
65//! // Host side (main loop): use with_view for critical section safety
66//! storage.host_shadow().with_view(|view| {
67//!     view.write_range(0x100, &[0xDE, 0xAD, 0xBE, 0xEF]).unwrap();
68//!
69//!     let mut buf = [0u8; 4];
70//!     view.read_range(0x100, &mut buf).unwrap();
71//! });
72//!
73//! // Kernel side (ISR): use with_view_unchecked since ISR already has exclusive access
74//! unsafe {
75//!     storage.kernel_shadow().with_view_unchecked(|view| {
76//!         view.for_each_dirty_block(|addr, data| {
77//!             // Write to hardware registers here
78//!             Ok(())
79//!         }).unwrap();
80//!         view.clear_dirty();
81//!     });
82//! }
83//! ```
84
85#![deny(unsafe_code)]
86#![no_std]
87
88pub mod builder;
89pub mod error;
90pub mod helpers;
91pub mod persist;
92pub mod policy;
93pub mod shadow;
94pub mod staged;
95pub mod storage;
96pub(crate) mod table;
97pub mod types;
98pub mod view;
99
100pub use builder::ShadowStorageBuilder;
101pub use error::ShadowError;
102pub use persist::{NoPersist, PersistTrigger};
103pub use policy::{AccessPolicy, AllowAllPolicy, NoPersistPolicy, PersistPolicy};
104pub use shadow::{HostShadow, KernelShadow};
105pub use staged::PatchStagingBuffer;
106pub use storage::{ShadowStorage, WriteFn};
107pub use types::StagingBuffer;
108pub use view::{HostView, HostViewStaged, KernelView};
109
110#[cfg(test)]
111mod test_support;
112
113pub mod prelude {
114    pub use crate::{
115        builder::ShadowStorageBuilder,
116        error::ShadowError,
117        persist::{NoPersist, PersistTrigger},
118        policy::{AccessPolicy, AllowAllPolicy, NoPersistPolicy, PersistPolicy},
119        shadow::{HostShadow, KernelShadow},
120        staged::PatchStagingBuffer,
121        storage::ShadowStorage,
122        types::StagingBuffer,
123        view::{HostView, HostViewStaged, KernelView},
124    };
125}