1#[cfg(feature = "byte-code")]
7mod byte_code;
8mod storage;
9
10use core::fmt;
11
12#[cfg(feature = "musli")]
13use musli_core::mode::Binary;
14#[cfg(feature = "musli")]
15use musli_core::{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(Decode, Encode), musli(crate = musli_core))]
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(Decode, Encode), musli(crate = musli_core))]
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 globals: Vec<Option<ConstValue>>,
96 globals_rev: hash::Map<usize>,
98}
99
100impl<S> Unit<S> {
101 #[inline]
103 pub fn from_parts(data: Logic<S>, debug: Option<DebugInfo>) -> alloc::Result<Self> {
104 Ok(Self {
105 logic: data,
106 debug: debug.map(Box::try_new).transpose()?,
107 })
108 }
109
110 #[allow(clippy::too_many_arguments)]
112 #[inline]
113 pub(crate) fn new(
114 storage: S,
115 functions: hash::Map<UnitFn>,
116 static_strings: Vec<Arc<StaticString>>,
117 static_bytes: Vec<Vec<u8>>,
118 static_object_keys: Vec<Box<[String]>>,
119 drop_sets: Vec<Arc<[Address]>>,
120 rtti: hash::Map<Arc<Rtti>>,
121 debug: Option<Box<DebugInfo>>,
122 constants: hash::Map<ConstValue>,
123 globals: Vec<Option<ConstValue>>,
124 globals_rev: hash::Map<usize>,
125 ) -> Self {
126 Self {
127 logic: Logic {
128 storage,
129 functions,
130 static_strings,
131 static_bytes,
132 static_object_keys,
133 drop_sets,
134 rtti,
135 constants,
136 globals,
137 globals_rev,
138 },
139 debug,
140 }
141 }
142
143 #[inline]
145 pub fn logic(&self) -> &Logic<S> {
146 &self.logic
147 }
148
149 #[inline]
151 pub fn debug_info(&self) -> Option<&DebugInfo> {
152 Some(&**self.debug.as_ref()?)
153 }
154
155 #[inline]
157 pub(crate) fn instructions(&self) -> &S {
158 &self.logic.storage
159 }
160
161 #[cfg(feature = "cli")]
163 #[inline]
164 pub(crate) fn iter_static_strings(&self) -> impl Iterator<Item = &Arc<StaticString>> + '_ {
165 self.logic.static_strings.iter()
166 }
167
168 #[cfg(feature = "cli")]
170 #[inline]
171 pub(crate) fn iter_static_bytes(&self) -> impl Iterator<Item = &[u8]> + '_ {
172 self.logic.static_bytes.iter().map(|v| &**v)
173 }
174
175 #[cfg(feature = "cli")]
177 #[inline]
178 pub(crate) fn iter_static_drop_sets(&self) -> impl Iterator<Item = &[Address]> + '_ {
179 self.logic.drop_sets.iter().map(|v| &**v)
180 }
181
182 #[cfg(feature = "cli")]
184 #[inline]
185 pub(crate) fn iter_constants(&self) -> impl Iterator<Item = (&Hash, &ConstValue)> + '_ {
186 self.logic.constants.iter()
187 }
188
189 #[cfg(feature = "cli")]
191 #[inline]
192 pub(crate) fn iter_static_object_keys(&self) -> impl Iterator<Item = (usize, &[String])> + '_ {
193 use core::iter;
194
195 let mut it = self.logic.static_object_keys.iter().enumerate();
196
197 iter::from_fn(move || {
198 let (n, s) = it.next()?;
199 Some((n, &s[..]))
200 })
201 }
202
203 #[cfg(feature = "cli")]
205 #[inline]
206 pub(crate) fn iter_functions(&self) -> impl Iterator<Item = (Hash, &UnitFn)> + '_ {
207 self.logic.functions.iter().map(|(h, f)| (*h, f))
208 }
209
210 #[inline]
212 pub(crate) fn lookup_string(&self, slot: usize) -> Option<&Arc<StaticString>> {
213 self.logic.static_strings.get(slot)
214 }
215
216 #[inline]
218 pub(crate) fn lookup_bytes(&self, slot: usize) -> Option<&[u8]> {
219 Some(self.logic.static_bytes.get(slot)?)
220 }
221
222 #[inline]
224 pub(crate) fn lookup_object_keys(&self, slot: usize) -> Option<&[String]> {
225 Some(self.logic.static_object_keys.get(slot)?)
226 }
227
228 #[inline]
229 pub(crate) fn lookup_drop_set(&self, set: usize) -> Option<&[Address]> {
230 Some(self.logic.drop_sets.get(set)?)
231 }
232
233 #[inline]
235 pub(crate) fn lookup_rtti(&self, hash: &Hash) -> Option<&Arc<Rtti>> {
236 self.logic.rtti.get(hash)
237 }
238
239 #[inline]
241 pub(crate) fn function(&self, hash: &Hash) -> Option<&UnitFn> {
242 self.logic.functions.get(hash)
243 }
244
245 #[inline]
247 pub(crate) fn constant(&self, hash: &Hash) -> Option<&ConstValue> {
248 self.logic.constants.get(hash)
249 }
250
251 #[inline]
258 pub fn globals_len(&self) -> usize {
259 self.logic.globals.len()
260 }
261
262 #[inline]
267 pub fn global_slot(&self, hash: &Hash) -> Option<usize> {
268 self.logic.globals_rev.get(hash).copied()
269 }
270
271 #[inline]
273 pub(crate) fn global_init(&self, slot: usize) -> Option<&ConstValue> {
274 self.logic.globals.get(slot)?.as_ref()
275 }
276
277 #[cfg(feature = "cli")]
279 #[inline]
280 pub(crate) fn iter_globals(&self) -> impl Iterator<Item = (usize, Option<&ConstValue>)> + '_ {
281 self.logic
282 .globals
283 .iter()
284 .enumerate()
285 .map(|(slot, init)| (slot, init.as_ref()))
286 }
287}
288
289impl<S> Unit<S>
290where
291 S: UnitStorage,
292{
293 #[inline]
294 pub(crate) fn translate(&self, jump: usize) -> Result<usize, BadJump> {
295 self.logic.storage.translate(jump)
296 }
297
298 #[inline]
300 pub(crate) fn instruction_at(
301 &self,
302 ip: usize,
303 ) -> Result<Option<(Inst, usize)>, BadInstruction> {
304 self.logic.storage.get(ip)
305 }
306
307 #[cfg(feature = "emit")]
309 #[inline]
310 pub(crate) fn iter_instructions(&self) -> impl Iterator<Item = (usize, Inst)> + '_ {
311 self.logic.storage.iter()
312 }
313}
314
315#[derive(Debug, Clone, Copy)]
317#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
318#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(crate = musli_core))]
319pub(crate) enum UnitFn {
320 Offset {
322 offset: usize,
324 call: Call,
326 args: usize,
328 captures: Option<usize>,
331 },
332 EmptyStruct {
334 hash: Hash,
336 },
337 TupleStruct {
339 hash: Hash,
341 args: usize,
343 },
344}
345
346impl TryClone for UnitFn {
347 #[inline]
348 fn try_clone(&self) -> alloc::Result<Self> {
349 Ok(*self)
350 }
351}
352
353impl fmt::Display for UnitFn {
354 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
355 match self {
356 Self::Offset {
357 offset,
358 call,
359 args,
360 captures,
361 } => {
362 write!(
363 f,
364 "offset offset={offset}, call={call}, args={args}, captures={captures:?}"
365 )?;
366 }
367 Self::EmptyStruct { hash } => {
368 write!(f, "unit hash={hash}")?;
369 }
370 Self::TupleStruct { hash, args } => {
371 write!(f, "tuple hash={hash}, args={args}")?;
372 }
373 }
374
375 Ok(())
376 }
377}
378
379#[cfg(test)]
380static_assertions::assert_impl_all!(Unit: Send, Sync);