1#[cfg(feature = "byte-code")]
7mod byte_code;
8mod storage;
9
10use core::fmt;
11
12#[cfg(feature = "musli")]
13use musli::mode::Binary;
14#[cfg(feature = "musli")]
15use musli::{Decode, Encode};
16#[cfg(feature = "serde")]
17use serde::de::DeserializeOwned;
18#[cfg(feature = "serde")]
19use serde::{Deserialize, Serialize};
20
21use crate as rune;
22use crate::alloc::prelude::*;
23use crate::alloc::{self, Box, String, Vec};
24use crate::hash;
25use crate::runtime::{Address, Call, ConstValue, DebugInfo, Inst, Rtti, StaticString};
26use crate::sync::Arc;
27use crate::Hash;
28
29pub use self::storage::{ArrayUnit, EncodeError, UnitEncoder, UnitStorage};
30pub(crate) use self::storage::{BadInstruction, BadJump};
31
32#[cfg(feature = "byte-code")]
33pub use self::byte_code::ByteCodeUnit;
34
35#[cfg(not(rune_byte_code))]
37pub type DefaultStorage = ArrayUnit;
38#[cfg(rune_byte_code)]
40pub type DefaultStorage = ByteCodeUnit;
41
42#[derive(Debug, TryClone, Default)]
46#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
47#[cfg_attr(feature = "serde", serde(bound = "S: Serialize + DeserializeOwned"))]
48#[cfg_attr(feature = "musli", derive(Encode, Decode))]
49#[cfg_attr(feature = "musli", musli(Binary, bound = {S: Encode<Binary>}, decode_bound<'de, A> = {S: Decode<'de, Binary, A>}))]
50#[try_clone(bound = {S: TryClone})]
51pub struct Unit<S = DefaultStorage> {
52 #[cfg_attr(feature = "serde", serde(flatten))]
54 logic: Logic<S>,
55 debug: Option<Box<DebugInfo>>,
57}
58
59assert_impl!(Unit<DefaultStorage>: Send + Sync);
60
61#[derive(Debug, TryClone, Default)]
63#[cfg_attr(
64 feature = "serde",
65 derive(Serialize, Deserialize),
66 serde(rename = "Unit")
67)]
68#[cfg_attr(feature = "musli", derive(Encode, Decode))]
69#[try_clone(bound = {S: TryClone})]
70pub struct Logic<S = DefaultStorage> {
71 storage: S,
73 functions: hash::Map<UnitFn>,
75 static_strings: Vec<Arc<StaticString>>,
77 static_bytes: Vec<Vec<u8>>,
79 static_object_keys: Vec<Box<[String]>>,
86 drop_sets: Vec<Arc<[Address]>>,
88 rtti: hash::Map<Arc<Rtti>>,
90 constants: hash::Map<ConstValue>,
92}
93
94impl<S> Unit<S> {
95 #[inline]
97 pub fn from_parts(data: Logic<S>, debug: Option<DebugInfo>) -> alloc::Result<Self> {
98 Ok(Self {
99 logic: data,
100 debug: debug.map(Box::try_new).transpose()?,
101 })
102 }
103
104 #[allow(clippy::too_many_arguments)]
106 #[inline]
107 pub(crate) fn new(
108 storage: S,
109 functions: hash::Map<UnitFn>,
110 static_strings: Vec<Arc<StaticString>>,
111 static_bytes: Vec<Vec<u8>>,
112 static_object_keys: Vec<Box<[String]>>,
113 drop_sets: Vec<Arc<[Address]>>,
114 rtti: hash::Map<Arc<Rtti>>,
115 debug: Option<Box<DebugInfo>>,
116 constants: hash::Map<ConstValue>,
117 ) -> Self {
118 Self {
119 logic: Logic {
120 storage,
121 functions,
122 static_strings,
123 static_bytes,
124 static_object_keys,
125 drop_sets,
126 rtti,
127 constants,
128 },
129 debug,
130 }
131 }
132
133 #[inline]
135 pub fn logic(&self) -> &Logic<S> {
136 &self.logic
137 }
138
139 #[inline]
141 pub fn debug_info(&self) -> Option<&DebugInfo> {
142 Some(&**self.debug.as_ref()?)
143 }
144
145 #[inline]
147 pub(crate) fn instructions(&self) -> &S {
148 &self.logic.storage
149 }
150
151 #[cfg(feature = "cli")]
153 #[inline]
154 pub(crate) fn iter_static_strings(&self) -> impl Iterator<Item = &Arc<StaticString>> + '_ {
155 self.logic.static_strings.iter()
156 }
157
158 #[cfg(feature = "cli")]
160 #[inline]
161 pub(crate) fn iter_static_bytes(&self) -> impl Iterator<Item = &[u8]> + '_ {
162 self.logic.static_bytes.iter().map(|v| &**v)
163 }
164
165 #[cfg(feature = "cli")]
167 #[inline]
168 pub(crate) fn iter_static_drop_sets(&self) -> impl Iterator<Item = &[Address]> + '_ {
169 self.logic.drop_sets.iter().map(|v| &**v)
170 }
171
172 #[cfg(feature = "cli")]
174 #[inline]
175 pub(crate) fn iter_constants(&self) -> impl Iterator<Item = (&Hash, &ConstValue)> + '_ {
176 self.logic.constants.iter()
177 }
178
179 #[cfg(feature = "cli")]
181 #[inline]
182 pub(crate) fn iter_static_object_keys(&self) -> impl Iterator<Item = (usize, &[String])> + '_ {
183 use core::iter;
184
185 let mut it = self.logic.static_object_keys.iter().enumerate();
186
187 iter::from_fn(move || {
188 let (n, s) = it.next()?;
189 Some((n, &s[..]))
190 })
191 }
192
193 #[cfg(feature = "cli")]
195 #[inline]
196 pub(crate) fn iter_functions(&self) -> impl Iterator<Item = (Hash, &UnitFn)> + '_ {
197 self.logic.functions.iter().map(|(h, f)| (*h, f))
198 }
199
200 #[inline]
202 pub(crate) fn lookup_string(&self, slot: usize) -> Option<&Arc<StaticString>> {
203 self.logic.static_strings.get(slot)
204 }
205
206 #[inline]
208 pub(crate) fn lookup_bytes(&self, slot: usize) -> Option<&[u8]> {
209 Some(self.logic.static_bytes.get(slot)?)
210 }
211
212 #[inline]
214 pub(crate) fn lookup_object_keys(&self, slot: usize) -> Option<&[String]> {
215 Some(self.logic.static_object_keys.get(slot)?)
216 }
217
218 #[inline]
219 pub(crate) fn lookup_drop_set(&self, set: usize) -> Option<&[Address]> {
220 Some(self.logic.drop_sets.get(set)?)
221 }
222
223 #[inline]
225 pub(crate) fn lookup_rtti(&self, hash: &Hash) -> Option<&Arc<Rtti>> {
226 self.logic.rtti.get(hash)
227 }
228
229 #[inline]
231 pub(crate) fn function(&self, hash: &Hash) -> Option<&UnitFn> {
232 self.logic.functions.get(hash)
233 }
234
235 #[inline]
237 pub(crate) fn constant(&self, hash: &Hash) -> Option<&ConstValue> {
238 self.logic.constants.get(hash)
239 }
240}
241
242impl<S> Unit<S>
243where
244 S: UnitStorage,
245{
246 #[inline]
247 pub(crate) fn translate(&self, jump: usize) -> Result<usize, BadJump> {
248 self.logic.storage.translate(jump)
249 }
250
251 #[inline]
253 pub(crate) fn instruction_at(
254 &self,
255 ip: usize,
256 ) -> Result<Option<(Inst, usize)>, BadInstruction> {
257 self.logic.storage.get(ip)
258 }
259
260 #[cfg(feature = "emit")]
262 #[inline]
263 pub(crate) fn iter_instructions(&self) -> impl Iterator<Item = (usize, Inst)> + '_ {
264 self.logic.storage.iter()
265 }
266}
267
268#[derive(Debug, Clone, Copy)]
270#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
271#[cfg_attr(feature = "musli", derive(Encode, Decode))]
272#[non_exhaustive]
273pub(crate) enum UnitFn {
274 Offset {
276 offset: usize,
278 call: Call,
280 args: usize,
282 captures: Option<usize>,
285 },
286 EmptyStruct {
288 hash: Hash,
290 },
291 TupleStruct {
293 hash: Hash,
295 args: usize,
297 },
298}
299
300impl TryClone for UnitFn {
301 #[inline]
302 fn try_clone(&self) -> alloc::Result<Self> {
303 Ok(*self)
304 }
305}
306
307impl fmt::Display for UnitFn {
308 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
309 match self {
310 Self::Offset {
311 offset,
312 call,
313 args,
314 captures,
315 } => {
316 write!(
317 f,
318 "offset offset={offset}, call={call}, args={args}, captures={captures:?}"
319 )?;
320 }
321 Self::EmptyStruct { hash } => {
322 write!(f, "unit hash={hash}")?;
323 }
324 Self::TupleStruct { hash, args } => {
325 write!(f, "tuple hash={hash}, args={args}")?;
326 }
327 }
328
329 Ok(())
330 }
331}
332
333#[cfg(test)]
334static_assertions::assert_impl_all!(Unit: Send, Sync);