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