alure/encoding/
cursor.rs

1// AluRE: AluVM runtime environment.
2// This is rust implementation of AluVM (arithmetic logic unit virtual machine).
3//
4// Designed & written in 2021 by
5//     Dr. Maxim Orlovsky <orlovsky@pandoracore.com>
6//
7// This software is licensed under the terms of MIT License.
8// You should have received a copy of the MIT License along with this software.
9// If not, see <https://opensource.org/licenses/MIT>.
10
11use amplify_num::{u2, u3, u4, u5, u6, u7};
12use core::convert::TryInto;
13use core::fmt::{self, Debug, Display, Formatter};
14
15use super::{Read, Write};
16use crate::reg::{Reg, Value};
17
18// I had an idea of putting Read/Write functionality into `amplify` crate,
19// but it is quire specific to the fact that it uses `u16`-sized underlying
20// bytestring, which is specific to client-side-validation and this VM and not
21// generic enough to become part of the `amplify` library
22
23/// Errors with cursor-based operations
24#[derive(Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
25#[display(doc_comments)]
26#[cfg_attr(feature = "std", derive(Error))]
27#[allow(clippy::branches_sharing_code)]
28pub enum CursorError {
29    /// Attempt to read or write after end of data
30    Eof,
31
32    /// Attempt to read or write at a position outside of data boundaries ({0})
33    OutOfBoundaries(usize),
34}
35
36/// Cursor for accessing byte string data bounded by `u16::MAX` length
37pub struct Cursor<T>
38where
39    T: AsRef<[u8]>,
40{
41    bytecode: T,
42    byte_pos: u16,
43    bit_pos: u3,
44    eof: bool,
45}
46
47impl<T> Debug for Cursor<T>
48where
49    T: AsRef<[u8]>,
50{
51    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
52        use bitcoin_hashes::hex::ToHex;
53        f.debug_struct("Cursor")
54            .field("bytecode", &self.bytecode.as_ref().to_hex())
55            .field("byte_pos", &self.byte_pos)
56            .field("bit_pos", &self.bit_pos)
57            .field("eof", &self.eof)
58            .finish()
59    }
60}
61
62impl<T> Display for Cursor<T>
63where
64    T: AsRef<[u8]>,
65{
66    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
67        use bitcoin_hashes::hex::ToHex;
68        write!(f, "{}:{} @ ", self.byte_pos, self.bit_pos)?;
69        let hex = self.bytecode.as_ref().to_hex();
70        if f.alternate() {
71            write!(f, "{}..{}", &hex[..4], &hex[hex.len() - 4..])
72        } else {
73            f.write_str(&hex)
74        }
75    }
76}
77
78impl<T> Cursor<T>
79where
80    T: AsRef<[u8]>,
81{
82    /// Creates cursor from the provided byte string
83    pub fn with(bytecode: T) -> Cursor<T> {
84        Cursor {
85            bytecode,
86            byte_pos: 0,
87            bit_pos: u3::MIN,
88            eof: false,
89        }
90    }
91
92    /// Returns whether cursor is at the upper length boundary for any byte
93    /// string (equal to `u16::MAX`)
94    pub fn is_eof(&self) -> bool {
95        self.eof
96    }
97
98    /// Returns current byte offset of the cursor. Does not accounts bits.
99    pub fn pos(&self) -> u16 {
100        self.byte_pos
101    }
102
103    /// Sets current cursor byte offset to the provided value
104    pub fn seek(&mut self, byte_pos: u16) {
105        self.byte_pos = byte_pos;
106    }
107
108    fn extract(&mut self, bit_count: u3) -> Result<u8, CursorError> {
109        if self.eof {
110            return Err(CursorError::Eof);
111        }
112        let byte = self.bytecode.as_ref()[self.byte_pos as usize];
113        let mut mask = 0x00u8;
114        let mut cnt = bit_count.as_u8();
115        while cnt > 0 {
116            mask <<= 1;
117            mask |= 0x01;
118            cnt -= 1;
119        }
120        mask <<= self.bit_pos.as_u8();
121        let val = (byte & mask) >> self.bit_pos.as_u8();
122        self.inc_bits(bit_count).map(|_| val)
123    }
124
125    fn inc_bits(&mut self, bit_count: u3) -> Result<(), CursorError> {
126        if self.eof {
127            return Err(CursorError::Eof);
128        }
129        let pos = self.bit_pos.as_u8() + bit_count.as_u8();
130        self.bit_pos = u3::with(pos % 8);
131        self._inc_bytes_inner(pos as u16 / 8)
132    }
133
134    fn inc_bytes(&mut self, byte_count: u16) -> Result<(), CursorError> {
135        assert_eq!(
136            self.bit_pos.as_u8(),
137            0,
138            "attempt to access (multiple) bytes at a non-byte aligned position"
139        );
140        if self.eof {
141            return Err(CursorError::Eof);
142        }
143        self._inc_bytes_inner(byte_count)
144    }
145
146    fn _inc_bytes_inner(&mut self, byte_count: u16) -> Result<(), CursorError> {
147        if byte_count == 1 && self.byte_pos == u16::MAX {
148            self.eof = true
149        } else {
150            self.byte_pos =
151                self.byte_pos
152                    .checked_add(byte_count)
153                    .ok_or(CursorError::OutOfBoundaries(
154                        self.byte_pos as usize + byte_count as usize,
155                    ))?;
156        }
157        Ok(())
158    }
159}
160
161impl Read for Cursor<&[u8]> {
162    type Error = CursorError;
163
164    fn is_end(&self) -> bool {
165        self.byte_pos as usize >= self.bytecode.len()
166    }
167
168    fn peek_u8(&self) -> Result<u8, CursorError> {
169        if self.eof {
170            return Err(CursorError::Eof);
171        }
172        Ok(self.bytecode[self.byte_pos as usize])
173    }
174
175    fn read_bool(&mut self) -> Result<bool, CursorError> {
176        if self.eof {
177            return Err(CursorError::Eof);
178        }
179        let byte = self.extract(u3::with(1))?;
180        Ok(byte == 0x01)
181    }
182
183    fn read_u2(&mut self) -> Result<u2, CursorError> {
184        Ok(self
185            .extract(u3::with(2))?
186            .try_into()
187            .expect("bit extractor failure"))
188    }
189
190    fn read_u3(&mut self) -> Result<u3, CursorError> {
191        Ok(self
192            .extract(u3::with(3))?
193            .try_into()
194            .expect("bit extractor failure"))
195    }
196
197    fn read_u4(&mut self) -> Result<u4, CursorError> {
198        Ok(self
199            .extract(u3::with(4))?
200            .try_into()
201            .expect("bit extractor failure"))
202    }
203
204    fn read_u5(&mut self) -> Result<u5, CursorError> {
205        Ok(self
206            .extract(u3::with(5))?
207            .try_into()
208            .expect("bit extractor failure"))
209    }
210
211    fn read_u6(&mut self) -> Result<u6, CursorError> {
212        Ok(self
213            .extract(u3::with(6))?
214            .try_into()
215            .expect("bit extractor failure"))
216    }
217
218    fn read_u7(&mut self) -> Result<u7, CursorError> {
219        Ok(self
220            .extract(u3::with(7))?
221            .try_into()
222            .expect("bit extractor failure"))
223    }
224
225    fn read_u8(&mut self) -> Result<u8, CursorError> {
226        if self.eof {
227            return Err(CursorError::Eof);
228        }
229        let byte = self.bytecode[self.byte_pos as usize];
230        self.inc_bytes(1).map(|_| byte)
231    }
232
233    fn read_u16(&mut self) -> Result<u16, CursorError> {
234        if self.eof {
235            return Err(CursorError::Eof);
236        }
237        let pos = self.byte_pos as usize;
238        let mut buf = [0u8; 2];
239        buf.copy_from_slice(&self.bytecode[pos..pos + 2]);
240        let word = u16::from_le_bytes(buf);
241        self.inc_bytes(2).map(|_| word)
242    }
243
244    fn read_bytes32(&mut self) -> Result<[u8; 32], CursorError> {
245        if self.eof {
246            return Err(CursorError::Eof);
247        }
248        let pos = self.byte_pos as usize;
249        let mut buf = [0u8; 32];
250        buf.copy_from_slice(&self.bytecode[pos..pos + 32]);
251        self.inc_bytes(32).map(|_| buf)
252    }
253
254    fn read_slice(&mut self) -> Result<&[u8], CursorError> {
255        if self.eof {
256            return Err(CursorError::Eof);
257        }
258        let len = self.read_u16()? as usize;
259        let pos = self.byte_pos as usize;
260        self.inc_bytes(2u16 + len as u16)
261            .map(|_| &self.bytecode[pos..pos + len])
262    }
263
264    fn read_value(&mut self, reg: Reg) -> Result<Value, CursorError> {
265        if self.eof {
266            return Err(CursorError::Eof);
267        }
268        let len = match reg.bits() {
269            Some(bits) => bits / 8,
270            None => self.read_u16()?,
271        } as usize;
272        let pos = self.byte_pos as usize;
273        let value = Value::with(&self.bytecode[pos..pos + len]);
274        self.inc_bytes(len as u16).map(|_| value)
275    }
276}
277
278impl Write for Cursor<&mut [u8]> {
279    type Error = CursorError;
280
281    fn write_bool(&mut self, data: bool) -> Result<(), CursorError> {
282        let data = if data { 1u8 } else { 0u8 } << self.bit_pos.as_u8();
283        self.bytecode[self.byte_pos as usize] |= data;
284        self.inc_bits(u3::with(1))
285    }
286
287    fn write_u2(&mut self, data: impl Into<u2>) -> Result<(), CursorError> {
288        let data = data.into().as_u8() << self.bit_pos.as_u8();
289        self.bytecode[self.byte_pos as usize] |= data;
290        self.inc_bits(u3::with(2))
291    }
292
293    fn write_u3(&mut self, data: impl Into<u3>) -> Result<(), CursorError> {
294        let data = data.into().as_u8() << self.bit_pos.as_u8();
295        self.bytecode[self.byte_pos as usize] |= data;
296        self.inc_bits(u3::with(3))
297    }
298
299    fn write_u4(&mut self, data: impl Into<u4>) -> Result<(), CursorError> {
300        let data = data.into().as_u8() << self.bit_pos.as_u8();
301        self.bytecode[self.byte_pos as usize] |= data;
302        self.inc_bits(u3::with(4))
303    }
304
305    fn write_u5(&mut self, data: impl Into<u5>) -> Result<(), CursorError> {
306        let data = data.into().as_u8() << self.bit_pos.as_u8();
307        self.bytecode[self.byte_pos as usize] |= data;
308        self.inc_bits(u3::with(5))
309    }
310
311    fn write_u6(&mut self, data: impl Into<u6>) -> Result<(), CursorError> {
312        let data = data.into().as_u8() << self.bit_pos.as_u8();
313        self.bytecode[self.byte_pos as usize] |= data;
314        self.inc_bits(u3::with(6))
315    }
316
317    fn write_u7(&mut self, data: impl Into<u7>) -> Result<(), CursorError> {
318        let data = data.into().as_u8() << self.bit_pos.as_u8();
319        self.bytecode[self.byte_pos as usize] |= data;
320        self.inc_bits(u3::with(7))
321    }
322
323    fn write_u8(&mut self, data: impl Into<u8>) -> Result<(), CursorError> {
324        self.bytecode[self.byte_pos as usize] = data.into();
325        self.inc_bytes(1)
326    }
327
328    fn write_u16(&mut self, data: impl Into<u16>) -> Result<(), CursorError> {
329        let data = data.into().to_le_bytes();
330        self.bytecode[self.byte_pos as usize] = data[0];
331        self.bytecode[self.byte_pos as usize + 1] = data[1];
332        self.inc_bytes(2)
333    }
334
335    fn write_bytes32(&mut self, data: [u8; 32]) -> Result<(), CursorError> {
336        let from = self.byte_pos as usize;
337        let to = from + 32;
338        self.bytecode[from..to].copy_from_slice(&data);
339        self.inc_bytes(32)
340    }
341
342    fn write_slice(&mut self, bytes: impl AsRef<[u8]>) -> Result<(), CursorError> {
343        // We control that `self.byte_pos + bytes.len() < u16` at buffer
344        // allocation time, so if we panic here this means we have a bug in
345        // out allocation code and has to kill the process and report this issue
346        let len = bytes.as_ref().len();
347        if len >= u16::MAX as usize {
348            return Err(CursorError::OutOfBoundaries(len));
349        }
350        self.write_u16(len as u16)?;
351        let from = self.byte_pos as usize;
352        let to = from + len;
353        self.bytecode[from..to].copy_from_slice(bytes.as_ref());
354        self.inc_bytes(2u16 + len as u16)
355    }
356
357    fn write_value(&mut self, reg: Reg, value: &Value) -> Result<(), CursorError> {
358        let len = match reg.bits() {
359            Some(bits) => bits / 8,
360            None => {
361                self.write_u16(value.len)?;
362                value.len
363            }
364        };
365        assert!(
366            len >= value.len,
367            "value for the register has larger bit length than the register"
368        );
369        let value_len = value.len as usize;
370        let from = self.byte_pos as usize;
371        let to = from + value_len;
372        self.bytecode[from..to].copy_from_slice(&value.bytes[0..value_len]);
373        self.inc_bytes(len as u16)
374    }
375}