1use crate::collections::HashMap;
7use crate::{
8 Call, ConstValue, DebugInfo, Hash, Inst, Rtti, StaticString, VariantRtti, VmError, VmErrorKind,
9};
10use serde::{Deserialize, Serialize};
11use std::fmt;
12use std::sync::Arc;
13
14#[derive(Debug, Default, Serialize, Deserialize)]
16pub struct Unit {
17 instructions: Vec<Inst>,
19 functions: HashMap<Hash, UnitFn>,
21 static_strings: Vec<Arc<StaticString>>,
23 static_bytes: Vec<Vec<u8>>,
25 static_object_keys: Vec<Box<[String]>>,
32 rtti: HashMap<Hash, Arc<Rtti>>,
34 variant_rtti: HashMap<Hash, Arc<VariantRtti>>,
36 debug: Option<Box<DebugInfo>>,
38 constants: HashMap<Hash, ConstValue>,
40}
41
42impl Unit {
43 #[allow(clippy::too_many_arguments)]
45 pub fn new(
46 instructions: Vec<Inst>,
47 functions: HashMap<Hash, UnitFn>,
48 static_strings: Vec<Arc<StaticString>>,
49 static_bytes: Vec<Vec<u8>>,
50 static_object_keys: Vec<Box<[String]>>,
51 rtti: HashMap<Hash, Arc<Rtti>>,
52 variant_rtti: HashMap<Hash, Arc<VariantRtti>>,
53 debug: Option<Box<DebugInfo>>,
54 constants: HashMap<Hash, ConstValue>,
55 ) -> Self {
56 Self {
57 instructions,
58 functions,
59 static_strings,
60 static_bytes,
61 static_object_keys,
62 rtti,
63 variant_rtti,
64 debug,
65 constants,
66 }
67 }
68
69 pub fn debug_info(&self) -> Option<&DebugInfo> {
71 let debug = self.debug.as_ref()?;
72 Some(&**debug)
73 }
74
75 pub fn instruction_at(&self, ip: usize) -> Option<&Inst> {
77 self.instructions.get(ip)
78 }
79
80 pub fn iter_static_strings(&self) -> impl Iterator<Item = &Arc<StaticString>> + '_ {
82 self.static_strings.iter()
83 }
84
85 pub fn iter_static_object_keys(&self) -> impl Iterator<Item = (usize, &[String])> + '_ {
87 let mut it = self.static_object_keys.iter().enumerate();
88
89 std::iter::from_fn(move || {
90 let (n, s) = it.next()?;
91 Some((n, &s[..]))
92 })
93 }
94
95 pub fn iter_instructions(&self) -> impl Iterator<Item = Inst> + '_ {
97 self.instructions.iter().copied()
98 }
99
100 pub fn iter_functions(&self) -> impl Iterator<Item = (Hash, &UnitFn)> + '_ {
102 self.functions.iter().map(|(h, f)| (*h, f))
103 }
104
105 pub fn lookup_string(&self, slot: usize) -> Result<&Arc<StaticString>, VmError> {
107 Ok(self
108 .static_strings
109 .get(slot)
110 .ok_or_else(|| VmErrorKind::MissingStaticString { slot })?)
111 }
112
113 pub fn lookup_bytes(&self, slot: usize) -> Result<&[u8], VmError> {
115 Ok(self
116 .static_bytes
117 .get(slot)
118 .ok_or_else(|| VmErrorKind::MissingStaticString { slot })?
119 .as_ref())
120 }
121
122 pub fn lookup_object_keys(&self, slot: usize) -> Option<&[String]> {
124 self.static_object_keys.get(slot).map(|keys| &keys[..])
125 }
126
127 pub fn lookup_rtti(&self, hash: Hash) -> Option<&Arc<Rtti>> {
129 self.rtti.get(&hash)
130 }
131
132 pub fn lookup_variant_rtti(&self, hash: Hash) -> Option<&Arc<VariantRtti>> {
134 self.variant_rtti.get(&hash)
135 }
136
137 pub fn lookup(&self, hash: Hash) -> Option<UnitFn> {
139 self.functions.get(&hash).copied()
140 }
141
142 pub fn constant(&self, hash: Hash) -> Option<&ConstValue> {
144 self.constants.get(&hash)
145 }
146}
147
148#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
150pub enum UnitFn {
151 Offset {
153 offset: usize,
155 call: Call,
157 args: usize,
159 },
160 UnitStruct {
162 hash: Hash,
164 },
165 TupleStruct {
167 hash: Hash,
169 args: usize,
171 },
172 UnitVariant {
174 hash: Hash,
176 },
177 TupleVariant {
179 hash: Hash,
181 args: usize,
183 },
184}
185
186impl fmt::Display for UnitFn {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 match self {
189 Self::Offset { offset, call, args } => {
190 write!(f, "offset {}, {}, {}", offset, call, args)?;
191 }
192 Self::UnitStruct { hash } => {
193 write!(f, "unit {}", hash)?;
194 }
195 Self::TupleStruct { hash, args } => {
196 write!(f, "tuple {}, {}", hash, args)?;
197 }
198 Self::UnitVariant { hash } => {
199 write!(f, "empty-variant {}", hash)?;
200 }
201 Self::TupleVariant { hash, args } => {
202 write!(f, "tuple-variant {}, {}", hash, args)?;
203 }
204 }
205
206 Ok(())
207 }
208}
209
210#[cfg(test)]
211static_assertions::assert_impl_all!(Unit: Send, Sync);