embedded_shadow/
helpers.rs

1use crate::ShadowError;
2
3pub fn block_span<const TS: usize, const BS: usize, const BC: usize>(
4    addr: u16,
5    len: usize,
6) -> Result<(usize, usize), ShadowError> {
7    let (offset, end) = range_span::<TS>(addr, len)?;
8    let sb = offset / BS;
9    let eb = (end - 1) / BS; // inclusive
10
11    if eb >= BC {
12        return Err(ShadowError::OutOfBounds);
13    }
14
15    Ok((sb, eb))
16}
17
18pub fn range_span<const TS: usize>(addr: u16, len: usize) -> Result<(usize, usize), ShadowError> {
19    if len == 0 {
20        return Err(ShadowError::ZeroLength);
21    }
22
23    let offset = addr as usize;
24    let end = offset.checked_add(len).ok_or(ShadowError::OutOfBounds)?;
25
26    if end > TS {
27        return Err(ShadowError::OutOfBounds);
28    }
29
30    Ok((offset, end))
31}
32
33#[test]
34fn block_span_edge_cases() {
35    // Zero length
36    assert_eq!(block_span::<16, 4, 4>(0, 0), Err(ShadowError::ZeroLength));
37
38    // Out of bounds
39    assert_eq!(block_span::<16, 4, 4>(15, 2), Err(ShadowError::OutOfBounds));
40
41    // Single byte at block boundary
42    assert_eq!(block_span::<16, 4, 4>(4, 1), Ok((1, 1)));
43
44    // Exact block
45    assert_eq!(block_span::<16, 4, 4>(4, 4), Ok((1, 1)));
46
47    // Spanning all blocks
48    assert_eq!(block_span::<16, 4, 4>(0, 16), Ok((0, 3)));
49
50    // Last byte of table
51    assert_eq!(block_span::<16, 4, 4>(15, 1), Ok((3, 3)));
52}