1 //! Inline instruction arguments.
2 
3 /// Support for decoding a sequence of bytes or words from the
4 /// instruction stream.
5 #[derive(Copy, Clone, Default, Debug)]
6 pub struct Args<'a> {
7     bytes: &'a [u8],
8     is_words: bool,
9 }
10 
11 impl<'a> Args<'a> {
new(bytes: &'a [u8], is_words: bool) -> Self12     pub(crate) fn new(bytes: &'a [u8], is_words: bool) -> Self {
13         Self { bytes, is_words }
14     }
15 
16     /// Returns the number of arguments in the list.
len(&self) -> usize17     pub fn len(&self) -> usize {
18         if self.is_words {
19             self.bytes.len() / 2
20         } else {
21             self.bytes.len()
22         }
23     }
24 
25     /// Returns true if the argument list is empty.
is_empty(&self) -> bool26     pub fn is_empty(&self) -> bool {
27         self.bytes.is_empty()
28     }
29 
30     /// Returns an iterator over the argument values.
values(&self) -> impl Iterator<Item = i32> + 'a + Clone31     pub fn values(&self) -> impl Iterator<Item = i32> + 'a + Clone {
32         let bytes = if self.is_words { &[] } else { self.bytes };
33         let words = if self.is_words { self.bytes } else { &[] };
34         bytes
35             .iter()
36             .map(|byte| *byte as u32 as i32)
37             .chain(words.chunks_exact(2).map(|chunk| {
38                 let word = ((chunk[0] as u16) << 8) | chunk[1] as u16;
39                 // Double cast to ensure sign extension
40                 word as i16 as i32
41             }))
42     }
43 }
44 
45 /// Mock for testing arguments.
46 #[cfg(test)]
47 pub(crate) struct MockArgs {
48     bytes: Vec<u8>,
49     is_words: bool,
50 }
51 
52 #[cfg(test)]
53 impl MockArgs {
from_bytes(bytes: &[u8]) -> Self54     pub fn from_bytes(bytes: &[u8]) -> Self {
55         Self {
56             bytes: bytes.into(),
57             is_words: false,
58         }
59     }
60 
from_words(words: &[i16]) -> Self61     pub fn from_words(words: &[i16]) -> Self {
62         Self {
63             bytes: words
64                 .iter()
65                 .map(|word| *word as u16)
66                 .flat_map(|word| vec![(word >> 8) as u8, word as u8])
67                 .collect(),
68             is_words: true,
69         }
70     }
71 
args(&self) -> Args72     pub fn args(&self) -> Args {
73         Args {
74             bytes: &self.bytes,
75             is_words: self.is_words,
76         }
77     }
78 }
79 
80 #[cfg(test)]
81 mod tests {
82     use super::MockArgs;
83 
84     #[test]
byte_args()85     fn byte_args() {
86         let values = [5, 2, 85, 92, 26, 42, u8::MIN, u8::MAX];
87         let mock = MockArgs::from_bytes(&values);
88         let decoded = mock.args().values().collect::<Vec<_>>();
89         assert!(values.iter().map(|x| *x as i32).eq(decoded.iter().copied()));
90     }
91 
92     #[test]
word_args()93     fn word_args() {
94         let values = [-5, 2, 2845, 92, -26, 42, i16::MIN, i16::MAX];
95         let mock = MockArgs::from_words(&values);
96         let decoded = mock.args().values().collect::<Vec<_>>();
97         assert!(values.iter().map(|x| *x as i32).eq(decoded.iter().copied()));
98     }
99 }
100