1#![doc = include_str!("../README.md")]
2
3use std::{
4 sync::{Arc, Mutex, OnceLock},
5 time::Duration,
6};
7
8pub mod matchers;
9pub mod utils;
10use crate::utils::Regmock;
11
12thread_local! {
13 #[allow(clippy::missing_const_for_thread_local)]
14 pub(crate) static MOCK: ThreadLocalRegmock = const {OnceLock::new()};
17}
18
19type ThreadLocalRegmock = OnceLock<Arc<Mutex<Regmock>>>;
20
21#[derive(Debug, Clone)]
23pub enum MockError {
24 MockNotInitialized,
26 LockError,
28}
29
30impl From<MockError> for String {
31 fn from(value: MockError) -> Self {
32 format!("failed due to: {:?}", value)
33 }
34}
35
36pub fn with_mock<F, R>(f: F) -> Result<R, MockError>
38where
39 F: FnOnce(&mut Regmock) -> R,
40{
41 MOCK.with(|mock| -> Result<R, MockError> {
42 let mut mock = mock
43 .get()
44 .ok_or(MockError::MockNotInitialized)?
45 .lock()
46 .map_err(|_| MockError::LockError)?;
47 Ok((f)(&mut mock))
48 })
49}
50
51pub fn init_regmock(mock: Arc<Mutex<Regmock>>) {
58 MOCK.with(|m| match m.set(mock) {
59 Ok(_) => {}
60 Err(e) => panic!("Failed to initialize thread_local Regmock with: {:?}", e),
61 })
62}
63
64pub fn silent<T>(f: impl FnOnce() -> T) -> T {
94 let prev_state = with_mock(|regmock| {
95 let state = (regmock.log_enabled, regmock.callback_enabled);
96 regmock.log_enabled = false;
97 regmock.callback_enabled = false;
98 state
99 })
100 .expect("Could not access regmock thread-local for silent access. Most likely you forgot to initialize regmock.");
101
102 let ret = f();
103
104 with_mock(|regmock| {
105 (regmock.log_enabled, regmock.callback_enabled) = prev_state;
106 })
107 .expect("Could not access regmock thread-local for silent access. Most likely your forgot to initialize regmock.");
108
109 ret
110}
111
112pub fn logging(state: bool) {
118 with_mock(|mock| {
119 mock.log_enabled = state;
120 })
121 .expect("Could not access regmock thread-local for setting logging state. Most likely your forgot to initialize regmock.")
122}
123
124pub fn wait_until_polled(
134 addr: usize,
135 count: usize,
136 timeout: Option<std::time::Duration>,
137) -> Result<(), String> {
138 let timeout = timeout.unwrap_or(Duration::from_secs(5));
139 let start = std::time::Instant::now();
140 loop {
141 match with_mock(|mock| mock.log.is_being_polled(addr, count)).expect("Could not access regmock thread-local for setting logging state. Most likely your forgot to initialize regmock.") {
142 true => return Ok(()),
143 false if start.elapsed() > timeout => return Err(format!(
144 "Timed out waiting for 0x{:08X} to be polled. Last access: {:?}",
145 addr,
146 with_mock(|mock| mock.log.log.last().cloned())
147 )),
148 _ => std::thread::yield_now(),
149 };
150 }
151}
152
153pub fn callbacks(state: bool) {
159 with_mock(|mock| {
160 mock.callback_enabled = state;
161 })
162 .expect("Couldn't get regmock thread-local for setting callback state. Most likely your forgot to initialize regmock.")
163}
164
165pub fn logs() -> utils::RegmockLog {
171 with_mock(|mock| mock.get_logs()).expect("Coudn't get regmock thead-local for getting logs. Most likely your forgot to initialize regmock.")
172}
173
174pub fn read_fn(reg: usize, len: usize) -> u64 {
181 with_mock(|mock| mock.read_volatile(reg, len)).unwrap_or_else(|e| {
182 panic!(
183 "Cound not `read_volatile(0x{:08X}, {:?})` due to: {:?}",
184 reg, len, e
185 )
186 })
187}
188
189pub fn write_fn(reg: usize, len: usize, value: u64) {
197 with_mock(|mock| mock.write_volatile(reg, len, value)).unwrap_or_else(|e| {
198 panic!(
199 "Cound not `write_volatile(reg: 0x{:08X}, len: {:?}, value: 0x{:08X})` due to: {:?}",
200 reg, len, value, e
201 )
202 })
203}
204
205#[cfg(feature = "aurix")]
213pub fn ldmst_fn(reg: usize, len: usize, value: u64) {
214 with_mock(|mock| mock.load_modify_store(reg, len, value)).unwrap_or_else(|e| {
215 panic!(
216 "Cound not `load_modify_store(reg: 0x{:08X}, value: 0x{:08X})` due to: {:?}",
217 reg, len, e
218 )
219 })
220}