1pub const BLOCK_WORDS: usize = 32;
13
14pub const MAX_WORDS: usize = 0xFFFF / BLOCK_WORDS * BLOCK_WORDS;
17
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub enum RleLengthError {
21 Empty,
23 NotWholeBlocks,
26 TooLong,
29 PastBuffer,
31}
32
33impl core::fmt::Display for RleLengthError {
34 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
35 f.write_str(match self {
36 Self::Empty => "no run-length words",
37 Self::NotWholeBlocks => "run-length words not a multiple of 32",
38 Self::TooLong => "run-length words exceed the decode command's 16-bit count",
39 Self::PastBuffer => "run-length words past the end of the buffer",
40 })
41 }
42}
43
44pub const fn dma_block_count(words: usize) -> Result<u16, RleLengthError> {
47 if words == 0 {
48 return Err(RleLengthError::Empty);
49 }
50 if !words.is_multiple_of(BLOCK_WORDS) {
51 return Err(RleLengthError::NotWholeBlocks);
52 }
53 if words > MAX_WORDS {
54 return Err(RleLengthError::TooLong);
55 }
56 Ok((words / BLOCK_WORDS) as u16)
58}
59
60#[derive(Clone, Debug)]
67#[repr(transparent)]
68pub struct RleBuffer<const WORDS: usize>([u32; WORDS]);
69
70impl<const WORDS: usize> RleBuffer<WORDS> {
71 pub const fn new() -> Self {
73 Self([0; WORDS])
74 }
75
76 pub fn as_halfwords_mut(&mut self) -> &mut [u16] {
78 unsafe { core::slice::from_raw_parts_mut(self.0.as_mut_ptr().cast::<u16>(), WORDS * 2) }
82 }
83
84 pub const fn as_words(&self) -> &[u32] {
86 &self.0
87 }
88}
89
90impl<const WORDS: usize> Default for RleBuffer<WORDS> {
91 fn default() -> Self {
92 Self::new()
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn block_counts_cover_every_boundary() {
102 assert_eq!(dma_block_count(0), Err(RleLengthError::Empty));
103 assert_eq!(dma_block_count(8), Err(RleLengthError::NotWholeBlocks));
104 assert_eq!(dma_block_count(31), Err(RleLengthError::NotWholeBlocks));
105 assert_eq!(dma_block_count(32), Ok(1));
106 assert_eq!(dma_block_count(33), Err(RleLengthError::NotWholeBlocks));
107 assert_eq!(dma_block_count(MAX_WORDS), Ok(2047));
108 assert_eq!(MAX_WORDS, 0xFFE0);
109 assert_eq!(
110 dma_block_count(MAX_WORDS + BLOCK_WORDS),
111 Err(RleLengthError::TooLong)
112 );
113 assert_eq!(dma_block_count(32 << 16), Err(RleLengthError::TooLong));
115 }
116
117 #[test]
120 fn buffer_views_share_storage_without_aliasing() {
121 let mut buffer = RleBuffer::<4>::new();
122 let halfwords = buffer.as_halfwords_mut();
123 assert_eq!(halfwords.len(), 8);
124 halfwords[0] = 0x1111;
125 halfwords[1] = 0x2222;
126 halfwords[7] = 0xFE00;
127 let expected = if cfg!(target_endian = "little") {
128 [0x2222_1111, 0, 0, 0xFE00_0000]
129 } else {
130 [0x1111_2222, 0, 0, 0x0000_FE00]
131 };
132 assert_eq!(buffer.as_words(), &expected);
133 buffer.as_halfwords_mut()[2] = 0xAAAA;
134 assert_eq!(buffer.as_words()[1] & 0xFFFF, 0xAAAA);
135 }
136}