1mod error {
7 use snafu::{Backtrace, Snafu};
8
9 use super::Offset;
10
11 #[derive(Debug, Snafu)]
13 #[snafu(context(suffix(false)), visibility(pub(super)))]
14 #[non_exhaustive]
15 pub enum Error {
16 #[non_exhaustive]
18 Truncated {
19 remaining: Offset<Vec<u8>>,
21
22 backtrace: Backtrace,
24 },
25 }
26}
27
28use etk_ops::shanghai::Op;
29
30pub use self::error::Error;
31
32use snafu::ensure;
33
34use std::collections::VecDeque;
35use std::fmt;
36use std::io::{self, Write};
37
38#[derive(Debug, Clone, Copy, Eq, PartialEq)]
40pub struct Offset<T> {
41 pub offset: usize,
43
44 pub item: T,
46}
47
48impl<T> Offset<T> {
49 pub const fn new(offset: usize, item: T) -> Self {
51 Self { offset, item }
52 }
53}
54
55impl<T> fmt::Display for Offset<T>
56where
57 T: fmt::Display,
58{
59 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
60 write!(f, "{: >4x}: {}", self.offset, self.item)
61 }
62}
63
64#[derive(Debug)]
67pub struct Iter<'a> {
68 disassembler: &'a mut Disassembler,
69}
70
71impl<'a> Iterator for Iter<'a> {
72 type Item = Offset<Op<[u8]>>;
73
74 fn next(&mut self) -> Option<Self::Item> {
75 let buffer = &mut self.disassembler.buffer;
76 let front = *buffer.front()?;
77 let specifier = Op::<()>::from(front);
78 let len = specifier.size();
79 if buffer.len() < len {
80 return None;
81 }
82
83 let remaining = buffer.split_off(len);
84 let mut instruction = std::mem::replace(&mut self.disassembler.buffer, remaining);
85 let instruction = instruction.make_contiguous();
86
87 let item = Op::from_slice(instruction).ok()?;
88 let offset = self.disassembler.offset;
89 self.disassembler.offset += len;
90 Some(Offset::new(offset, item))
91 }
92}
93
94#[derive(Debug, Default)]
118pub struct Disassembler {
119 buffer: VecDeque<u8>,
120 offset: usize,
121}
122
123impl Write for Disassembler {
124 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
125 self.buffer.reserve(buf.len());
126 self.buffer.extend(buf);
127 Ok(buf.len())
128 }
129
130 fn flush(&mut self) -> io::Result<()> {
131 Ok(())
132 }
133}
134
135impl Disassembler {
136 pub fn new() -> Self {
138 Default::default()
139 }
140
141 pub fn ops(&mut self) -> Iter {
143 Iter { disassembler: self }
144 }
145
146 pub fn finish(self) -> Result<(), Error> {
149 ensure!(
150 self.buffer.is_empty(),
151 error::Truncated {
152 remaining: Offset::new(self.offset, self.buffer.into()),
153 }
154 );
155 Ok(())
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use etk_ops::shanghai::*;
162
163 use hex_literal::hex;
164
165 use super::*;
166
167 #[test]
168 fn empty() {
169 let mut dasm = Disassembler::new();
170 assert!(dasm.ops().next().is_none());
171 dasm.finish().unwrap();
172 }
173
174 #[test]
175 fn stop() {
176 let input = hex!("00");
177 let expected = [Offset::new(0, Op::from(Stop))];
178
179 let mut dasm = Disassembler::new();
180 dasm.write_all(&input).unwrap();
181
182 let actual: Vec<_> = dasm.ops().collect();
183
184 assert_eq!(expected, actual.as_slice());
185 dasm.finish().unwrap();
186 }
187
188 #[test]
189 fn partial_push5() {
190 let input = hex!("6401020304");
191 let expected = [Offset::new(0, Op::from(Push5(hex!("0102030406"))))];
192
193 let mut dasm = Disassembler::new();
194 dasm.write_all(&input).unwrap();
195 assert!(dasm.ops().next().is_none());
196
197 dasm.write_all(&hex!("06")).unwrap();
198
199 let actual: Vec<_> = dasm.ops().collect();
200
201 assert_eq!(expected, actual.as_slice());
202 dasm.finish().unwrap();
203 }
204
205 #[test]
206 fn push5() {
207 let input = hex!("640102030405");
208 let expected = [Offset::new(0, Op::from(Push5(hex!("0102030405"))))];
209
210 let mut dasm = Disassembler::new();
211 dasm.write_all(&input).unwrap();
212
213 let actual: Vec<_> = dasm.ops().collect();
214
215 assert_eq!(expected, actual.as_slice());
216 dasm.finish().unwrap();
217 }
218}