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::{
26 Address, Call, ConstValue, ConstValueBuf, DebugInfo, Inst, Rtti, StaticString,
27};
28use crate::sync::Arc;
29use crate::Hash;
30
31pub use self::storage::{ArrayUnit, EncodeError, UnitEncoder, UnitStorage};
32pub(crate) use self::storage::{BadInstruction, BadJump};
33
34#[cfg(feature = "byte-code")]
35pub use self::byte_code::ByteCodeUnit;
36
37#[cfg(not(rune_byte_code))]
39pub type DefaultStorage = ArrayUnit;
40#[cfg(rune_byte_code)]
42pub type DefaultStorage = ByteCodeUnit;
43
44#[derive(Debug, TryClone, Default)]
48#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
49#[cfg_attr(feature = "serde", serde(bound = "S: Serialize + DeserializeOwned"))]
50#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(crate = musli_core))]
51#[cfg_attr(feature = "musli", musli(Binary, bound = {S: Encode<Binary>}, decode_bound<'de, A> = {S: Decode<'de, Binary, A>}))]
52#[try_clone(bound = {S: TryClone})]
53pub struct Unit<S = DefaultStorage> {
54 #[cfg_attr(feature = "serde", serde(flatten))]
56 logic: Logic<S>,
57 debug: Option<Box<DebugInfo>>,
59}
60
61assert_impl!(Unit<DefaultStorage>: Send + Sync);
62
63#[derive(Debug, TryClone, Default)]
65#[cfg_attr(
66 feature = "serde",
67 derive(Serialize, Deserialize),
68 serde(rename = "Unit")
69)]
70#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(crate = musli_core))]
71#[try_clone(bound = {S: TryClone})]
72pub struct Logic<S = DefaultStorage> {
73 storage: S,
75 functions: hash::Map<UnitFn>,
77 static_strings: Vec<Arc<StaticString>>,
79 static_bytes: Vec<Vec<u8>>,
81 static_object_keys: Vec<Box<[String]>>,
88 drop_sets: Vec<Arc<[Address]>>,
90 rtti: hash::Map<Arc<Rtti>>,
92 constants: hash::Map<ConstValueBuf>,
94 globals: Vec<Option<ConstValueBuf>>,
98 globals_rev: hash::Map<usize>,
100}
101
102impl<S> Unit<S> {
103 #[inline]
105 pub fn from_parts(data: Logic<S>, debug: Option<DebugInfo>) -> alloc::Result<Self> {
106 Ok(Self {
107 logic: data,
108 debug: debug.map(Box::try_new).transpose()?,
109 })
110 }
111
112 #[allow(clippy::too_many_arguments)]
114 #[inline]
115 pub(crate) fn new(
116 storage: S,
117 functions: hash::Map<UnitFn>,
118 static_strings: Vec<Arc<StaticString>>,
119 static_bytes: Vec<Vec<u8>>,
120 static_object_keys: Vec<Box<[String]>>,
121 drop_sets: Vec<Arc<[Address]>>,
122 rtti: hash::Map<Arc<Rtti>>,
123 debug: Option<Box<DebugInfo>>,
124 constants: hash::Map<ConstValueBuf>,
125 globals: Vec<Option<ConstValueBuf>>,
126 globals_rev: hash::Map<usize>,
127 ) -> Self {
128 Self {
129 logic: Logic {
130 storage,
131 functions,
132 static_strings,
133 static_bytes,
134 static_object_keys,
135 drop_sets,
136 rtti,
137 constants,
138 globals,
139 globals_rev,
140 },
141 debug,
142 }
143 }
144
145 #[inline]
147 pub fn logic(&self) -> &Logic<S> {
148 &self.logic
149 }
150
151 #[inline]
153 pub fn debug_info(&self) -> Option<&DebugInfo> {
154 Some(&**self.debug.as_ref()?)
155 }
156
157 #[inline]
159 pub(crate) fn instructions(&self) -> &S {
160 &self.logic.storage
161 }
162
163 #[cfg(feature = "cli")]
165 #[inline]
166 pub(crate) fn iter_static_strings(&self) -> impl Iterator<Item = &Arc<StaticString>> + '_ {
167 self.logic.static_strings.iter()
168 }
169
170 #[cfg(feature = "cli")]
172 #[inline]
173 pub(crate) fn iter_static_bytes(&self) -> impl Iterator<Item = &[u8]> + '_ {
174 self.logic.static_bytes.iter().map(|v| &**v)
175 }
176
177 #[cfg(feature = "cli")]
179 #[inline]
180 pub(crate) fn iter_static_drop_sets(&self) -> impl Iterator<Item = &[Address]> + '_ {
181 self.logic.drop_sets.iter().map(|v| &**v)
182 }
183
184 #[cfg(feature = "cli")]
186 #[inline]
187 pub(crate) fn iter_constants(&self) -> impl Iterator<Item = (&Hash, &ConstValue)> + '_ {
188 self.logic
189 .constants
190 .iter()
191 .map(|(hash, value)| (hash, &**value))
192 }
193
194 #[cfg(feature = "cli")]
196 #[inline]
197 pub(crate) fn iter_static_object_keys(&self) -> impl Iterator<Item = (usize, &[String])> + '_ {
198 use core::iter;
199
200 let mut it = self.logic.static_object_keys.iter().enumerate();
201
202 iter::from_fn(move || {
203 let (n, s) = it.next()?;
204 Some((n, &s[..]))
205 })
206 }
207
208 #[cfg(feature = "cli")]
210 #[inline]
211 pub(crate) fn iter_functions(&self) -> impl Iterator<Item = (Hash, &UnitFn)> + '_ {
212 self.logic.functions.iter().map(|(h, f)| (*h, f))
213 }
214
215 #[inline]
217 pub(crate) fn lookup_string(&self, slot: usize) -> Option<&Arc<StaticString>> {
218 self.logic.static_strings.get(slot)
219 }
220
221 #[inline]
223 pub(crate) fn lookup_bytes(&self, slot: usize) -> Option<&[u8]> {
224 Some(self.logic.static_bytes.get(slot)?)
225 }
226
227 #[inline]
229 pub(crate) fn lookup_object_keys(&self, slot: usize) -> Option<&[String]> {
230 Some(self.logic.static_object_keys.get(slot)?)
231 }
232
233 #[inline]
234 pub(crate) fn lookup_drop_set(&self, set: usize) -> Option<&[Address]> {
235 Some(self.logic.drop_sets.get(set)?)
236 }
237
238 #[inline]
240 pub(crate) fn lookup_rtti(&self, hash: &Hash) -> Option<&Arc<Rtti>> {
241 self.logic.rtti.get(hash)
242 }
243
244 #[inline]
246 pub(crate) fn function(&self, hash: &Hash) -> Option<&UnitFn> {
247 self.logic.functions.get(hash)
248 }
249
250 #[inline]
252 pub(crate) fn constant(&self, hash: &Hash) -> Option<&ConstValue> {
253 Some(self.logic.constants.get(hash)?)
254 }
255
256 #[inline]
263 pub fn globals_len(&self) -> usize {
264 self.logic.globals.len()
265 }
266
267 #[inline]
272 pub fn global_slot(&self, hash: &Hash) -> Option<usize> {
273 self.logic.globals_rev.get(hash).copied()
274 }
275
276 #[inline]
278 pub(crate) fn global_init(&self, slot: usize) -> Option<&ConstValue> {
279 Some(self.logic.globals.get(slot)?.as_ref()?)
280 }
281
282 #[cfg(feature = "cli")]
284 #[inline]
285 pub(crate) fn iter_globals(&self) -> impl Iterator<Item = (usize, Option<&ConstValue>)> + '_ {
286 self.logic
287 .globals
288 .iter()
289 .enumerate()
290 .map(|(slot, init)| (slot, init.as_deref()))
291 }
292}
293
294impl<S> Unit<S>
295where
296 S: UnitStorage,
297{
298 #[inline]
299 pub(crate) fn translate(&self, jump: usize) -> Result<usize, BadJump> {
300 self.logic.storage.translate(jump)
301 }
302
303 #[inline]
305 pub(crate) fn instruction_at(
306 &self,
307 ip: usize,
308 ) -> Result<Option<(Inst, usize)>, BadInstruction> {
309 self.logic.storage.get(ip)
310 }
311
312 #[cfg(feature = "emit")]
314 #[inline]
315 pub(crate) fn iter_instructions(&self) -> impl Iterator<Item = (usize, Inst)> + '_ {
316 self.logic.storage.iter()
317 }
318}
319
320#[derive(Debug, Clone, Copy)]
322#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
323#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(crate = musli_core))]
324pub(crate) enum UnitFn {
325 Offset {
327 offset: usize,
329 call: Call,
331 args: usize,
333 captures: Option<usize>,
336 },
337 EmptyStruct {
339 hash: Hash,
341 },
342 TupleStruct {
344 hash: Hash,
346 args: usize,
348 },
349}
350
351impl TryClone for UnitFn {
352 #[inline]
353 fn try_clone(&self) -> alloc::Result<Self> {
354 Ok(*self)
355 }
356}
357
358impl fmt::Display for UnitFn {
359 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360 match self {
361 Self::Offset {
362 offset,
363 call,
364 args,
365 captures,
366 } => {
367 write!(
368 f,
369 "offset offset={offset}, call={call}, args={args}, captures={captures:?}"
370 )?;
371 }
372 Self::EmptyStruct { hash } => {
373 write!(f, "unit hash={hash}")?;
374 }
375 Self::TupleStruct { hash, args } => {
376 write!(f, "tuple hash={hash}, args={args}")?;
377 }
378 }
379
380 Ok(())
381 }
382}
383
384#[cfg(test)]
385static_assertions::assert_impl_all!(Unit: Send, Sync);