rune/runtime/unit/
byte_code.rs
1use core::mem::size_of;
2
3use serde::{Deserialize, Serialize};
4
5use crate as rune;
6use crate::alloc::prelude::*;
7use crate::alloc::{self, Vec};
8use crate::runtime::unit::{BadInstruction, BadJump, EncodeError, UnitEncoder, UnitStorage};
9use crate::runtime::Inst;
10
11#[derive(Debug, TryClone, Default, Serialize, Deserialize)]
15pub struct ByteCodeUnit {
16 #[try_clone(with = Clone::clone)]
18 bytes: rust_alloc::vec::Vec<u8>,
19 offsets: Vec<usize>,
21}
22
23pub struct ByteCodeUnitIter<'a> {
25 address: &'a [u8],
26 len: usize,
27}
28
29impl Iterator for ByteCodeUnitIter<'_> {
30 type Item = (usize, Inst);
31
32 #[inline]
33 fn next(&mut self) -> Option<Self::Item> {
34 if self.address.is_empty() {
35 return None;
36 }
37
38 let ip = self.len.checked_sub(self.address.len())?;
39 let inst = musli::storage::decode(self.address).ok()?;
40 Some((ip, inst))
41 }
42}
43
44impl UnitEncoder for ByteCodeUnit {
45 #[inline]
46 fn offset(&self) -> usize {
47 self.bytes.len()
48 }
49
50 #[inline]
51 fn encode(&mut self, inst: Inst) -> Result<(), EncodeError> {
52 musli::storage::encode(&mut self.bytes, &inst)?;
53 Ok(())
54 }
55
56 #[inline]
57 fn extend_offsets(&mut self, extra: usize) -> alloc::Result<usize> {
58 let base = self.offsets.len();
59 self.offsets.try_extend((0..extra).map(|_| 0))?;
60 Ok(base)
61 }
62
63 #[inline]
64 fn mark_offset(&mut self, index: usize) {
65 if let Some(o) = self.offsets.get_mut(index) {
66 *o = self.bytes.len();
67 }
68 }
69
70 #[inline]
71 fn label_jump(&self, base: usize, _: usize, jump: usize) -> usize {
72 base.wrapping_add(jump)
73 }
74}
75
76impl UnitStorage for ByteCodeUnit {
77 type Iter<'this> = ByteCodeUnitIter<'this>;
78
79 #[inline]
80 fn end(&self) -> usize {
81 self.bytes.len()
82 }
83
84 #[inline]
85 fn bytes(&self) -> usize {
86 self.bytes
87 .len()
88 .wrapping_add(self.offsets.len().wrapping_mul(size_of::<usize>()))
89 }
90
91 #[inline]
92 fn iter(&self) -> Self::Iter<'_> {
93 ByteCodeUnitIter {
94 address: &self.bytes[..],
95 len: self.bytes.len(),
96 }
97 }
98
99 fn get(&self, ip: usize) -> Result<Option<(Inst, usize)>, BadInstruction> {
100 let Some(bytes) = self.bytes.get(ip..) else {
101 return Ok(None);
102 };
103
104 let start = bytes.as_ptr();
105 let inst: Inst = musli::storage::decode(bytes).map_err(|_| BadInstruction { ip })?;
106 let len = (bytes.as_ptr() as usize).wrapping_sub(start as usize);
107 Ok(Some((inst, len)))
108 }
109
110 #[inline]
111 fn translate(&self, jump: usize) -> Result<usize, BadJump> {
112 let Some(&offset) = self.offsets.get(jump) else {
113 return Err(BadJump { jump });
114 };
115
116 Ok(offset)
117 }
118}