rune/runtime/unit/
storage.rs1use core::fmt;
2use core::iter;
3use core::mem::size_of;
4use core::slice;
5
6use crate as rune;
7use crate::alloc::prelude::*;
8use crate::alloc::{self, Vec};
9
10#[cfg(feature = "byte-code")]
11use musli::storage;
12#[cfg(feature = "musli")]
13use musli::{Decode, Encode};
14#[cfg(feature = "serde")]
15use serde::{Deserialize, Serialize};
16
17use crate::runtime::Inst;
18
19mod sealed {
20 pub trait Sealed {}
21
22 #[cfg(feature = "byte-code")]
23 impl Sealed for crate::runtime::unit::ByteCodeUnit {}
24 impl Sealed for crate::runtime::unit::ArrayUnit {}
25}
26
27pub trait UnitEncoder: self::sealed::Sealed {
29 #[doc(hidden)]
32 fn offset(&self) -> usize;
33
34 #[doc(hidden)]
36 fn encode(&mut self, inst: Inst) -> Result<(), EncodeError>;
37
38 #[doc(hidden)]
40 fn extend_offsets(&mut self, extra: usize) -> alloc::Result<usize>;
41
42 #[doc(hidden)]
44 fn mark_offset(&mut self, index: usize);
45
46 #[doc(hidden)]
48 fn label_jump(&self, base: usize, offset: usize, jump: usize) -> usize;
49}
50
51pub trait UnitStorage: self::sealed::Sealed + fmt::Debug + Default {
53 #[doc(hidden)]
55 type Iter<'this>: Iterator<Item = (usize, Inst)>
56 where
57 Self: 'this;
58
59 #[doc(hidden)]
62 fn end(&self) -> usize;
63
64 #[doc(hidden)]
66 fn bytes(&self) -> usize;
67
68 #[doc(hidden)]
70 fn iter(&self) -> Self::Iter<'_>;
71
72 #[doc(hidden)]
74 fn get(&self, ip: usize) -> Result<Option<(Inst, usize)>, BadInstruction>;
75
76 #[doc(hidden)]
78 fn translate(&self, jump: usize) -> Result<usize, BadJump>;
79}
80
81#[derive(Debug, TryClone, Default)]
83#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
84#[cfg_attr(feature = "musli", derive(Encode, Decode))]
85pub struct ArrayUnit {
86 instructions: Vec<Inst>,
87}
88
89impl UnitEncoder for ArrayUnit {
90 #[inline]
91 fn offset(&self) -> usize {
92 self.instructions.len()
93 }
94
95 #[inline]
96 fn encode(&mut self, inst: Inst) -> Result<(), EncodeError> {
97 self.instructions.try_push(inst)?;
98 Ok(())
99 }
100
101 #[inline]
102 fn extend_offsets(&mut self, _: usize) -> alloc::Result<usize> {
103 Ok(self.instructions.len())
104 }
105
106 #[inline]
107 fn mark_offset(&mut self, _: usize) {}
108
109 #[inline]
110 fn label_jump(&self, base: usize, offset: usize, _: usize) -> usize {
111 base.wrapping_add(offset)
112 }
113}
114
115impl UnitStorage for ArrayUnit {
116 type Iter<'this> = iter::Enumerate<iter::Copied<slice::Iter<'this, Inst>>>;
117
118 #[inline]
119 fn end(&self) -> usize {
120 self.instructions.len()
121 }
122
123 #[inline]
124 fn bytes(&self) -> usize {
125 self.instructions.len().wrapping_mul(size_of::<Inst>())
126 }
127
128 #[inline]
129 fn iter(&self) -> Self::Iter<'_> {
130 self.instructions.iter().copied().enumerate()
131 }
132
133 #[inline]
134 fn get(&self, ip: usize) -> Result<Option<(Inst, usize)>, BadInstruction> {
135 let Some(inst) = self.instructions.get(ip) else {
136 return Ok(None);
137 };
138
139 Ok(Some((*inst, 1)))
140 }
141
142 #[inline]
143 fn translate(&self, jump: usize) -> Result<usize, BadJump> {
144 Ok(jump)
145 }
146}
147
148#[derive(Debug)]
150#[doc(hidden)]
151pub struct EncodeError {
152 kind: EncodeErrorKind,
153}
154
155#[cfg(feature = "byte-code")]
156impl From<storage::Error> for EncodeError {
157 #[inline]
158 fn from(error: storage::Error) -> Self {
159 Self {
160 kind: EncodeErrorKind::StorageError { error },
161 }
162 }
163}
164
165impl From<alloc::Error> for EncodeError {
166 #[inline]
167 fn from(error: alloc::Error) -> Self {
168 Self {
169 kind: EncodeErrorKind::AllocError { error },
170 }
171 }
172}
173
174impl fmt::Display for EncodeError {
175 #[inline]
176 fn fmt(
177 &self,
178 #[cfg_attr(not(feature = "byte-code"), allow(unused))] f: &mut fmt::Formatter<'_>,
179 ) -> fmt::Result {
180 match &self.kind {
181 #[cfg(feature = "byte-code")]
182 EncodeErrorKind::StorageError { .. } => write!(f, "Storage error"),
183 EncodeErrorKind::AllocError { error } => error.fmt(f),
184 }
185 }
186}
187
188impl core::error::Error for EncodeError {
189 #[inline]
190 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
191 match &self.kind {
192 #[cfg(all(feature = "byte-code", feature = "std"))]
193 EncodeErrorKind::StorageError { error } => Some(error),
194 _ => None,
195 }
196 }
197}
198
199#[derive(Debug)]
200enum EncodeErrorKind {
201 #[cfg(feature = "byte-code")]
202 StorageError {
203 #[cfg_attr(not(feature = "std"), allow(dead_code))]
204 error: storage::Error,
205 },
206 AllocError {
207 error: alloc::Error,
208 },
209}
210
211#[derive(Debug)]
214#[cfg_attr(test, derive(PartialEq))]
215pub struct BadInstruction {
216 pub(crate) ip: usize,
217}
218
219impl fmt::Display for BadInstruction {
220 #[inline]
221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 write!(f, "Bad instruction at instruction {}", self.ip)
223 }
224}
225
226impl core::error::Error for BadInstruction {}
227
228#[derive(Debug)]
231#[cfg_attr(test, derive(PartialEq))]
232pub struct BadJump {
233 pub(crate) jump: usize,
234}
235
236impl fmt::Display for BadJump {
237 #[inline]
238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239 write!(f, "Bad jump index {}", self.jump)
240 }
241}
242
243impl core::error::Error for BadJump {}