1mod bytecode;
4pub(crate) mod custom;
5mod formatter;
6mod id;
7mod native_function;
8mod protected_val;
9mod struct_val;
10mod symbol;
11mod unsafe_val;
12
13use std::marker::PhantomData;
14
15pub use bytecode::{ByteCode, Instruction};
16pub use custom::{CustomType, CustomVal, CustomValError, CustomValMut, CustomValRef};
17pub use formatter::ValFormatter;
18pub use id::ValId;
19pub use native_function::{NativeFunction, NativeFunctionContext, ValBuilder};
20pub use protected_val::ProtectedVal;
21pub use struct_val::StructVal;
22pub use symbol::Symbol;
23pub use unsafe_val::UnsafeVal;
24
25use crate::Vm;
26
27pub type ListVal = Vec<UnsafeVal>;
29
30#[repr(transparent)]
32#[derive(Copy, Clone, Debug, Default)]
33pub struct Val<'a> {
34 inner: UnsafeVal,
35 _lifetime: PhantomData<&'a ()>,
36}
37
38impl Val<'static> {
39 pub fn new_void() -> Val<'static> {
41 unsafe { Self::from_unsafe_val(().into()) }
43 }
44
45 pub fn new_bool(x: bool) -> Val<'static> {
47 unsafe { Self::from_unsafe_val(x.into()) }
49 }
50
51 pub fn new_int(x: i64) -> Val<'static> {
53 unsafe { Self::from_unsafe_val(x.into()) }
55 }
56
57 pub fn new_float(x: f64) -> Val<'static> {
59 unsafe { Self::from_unsafe_val(x.into()) }
61 }
62}
63
64impl<'a> Val<'a> {
65 pub fn is_void(self) -> bool {
67 matches!(self.inner, UnsafeVal::Void)
68 }
69
70 pub fn is_truthy(self) -> bool {
73 self.inner.is_truthy()
74 }
75
76 pub fn try_bool(self) -> Result<bool, Self> {
78 match self.inner {
79 UnsafeVal::Bool(x) => Ok(x),
80 _ => Err(self),
81 }
82 }
83
84 pub fn try_int(self) -> Result<i64, Self> {
86 match self.inner {
87 UnsafeVal::Int(x) => Ok(x),
88 _ => Err(self),
89 }
90 }
91
92 pub fn try_float(self) -> Result<f64, Self> {
94 match self.inner {
95 UnsafeVal::Float(x) => Ok(x),
96 _ => Err(self),
97 }
98 }
99
100 pub fn try_symbol(self) -> Result<Symbol, Self> {
102 match self.inner {
103 UnsafeVal::Symbol(sym) => Ok(sym),
104 _ => Err(self),
105 }
106 }
107
108 pub fn try_str(self, vm: &Vm) -> Result<&str, Self> {
110 match self.inner {
111 UnsafeVal::String(id) => Ok(vm.objects.get_str(id)),
112 _ => Err(self),
113 }
114 }
115
116 pub fn try_list(self, vm: &Vm) -> Result<&[Val], Val<'a>> {
118 match self.inner {
119 UnsafeVal::List(id) => {
120 let list = vm.objects.get_list(id);
121 Ok(unsafe { Val::from_unsafe_val_slice(list.as_slice()) })
123 }
124 _ => Err(self),
125 }
126 }
127
128 pub fn is_struct(self) -> bool {
130 matches!(self.inner, UnsafeVal::Struct(_))
131 }
132
133 pub fn try_struct(self, vm: &Vm) -> Result<&StructVal, Val<'a>> {
135 match self.inner {
136 UnsafeVal::Struct(id) => {
137 let strct = vm.objects.get_struct(id);
138 Ok(strct)
140 }
141 _ => Err(self),
142 }
143 }
144
145 pub fn try_struct_get(self, vm: &'a Vm, name: &str) -> Result<Option<Val<'a>>, Val<'a>> {
147 match self.inner {
148 UnsafeVal::Struct(id) => {
149 let strct = vm.objects.get_struct(id);
150 let sym = vm.get_symbol(name).ok_or(self)?;
151 let maybe_v = strct.get(sym).map(|v| unsafe { Val::from_unsafe_val(v) });
152 Ok(maybe_v)
153 }
154 _ => Err(self),
155 }
156 }
157
158 pub unsafe fn try_unsafe_struct_mut(self, vm: &mut Vm) -> Result<&mut StructVal, Val<'a>> {
163 match self.inner {
164 UnsafeVal::Struct(id) => {
165 let strct = vm.objects.get_struct_mut(id);
166 Ok(strct)
167 }
168 _ => Err(self),
169 }
170 }
171
172 pub fn try_mutable_box_ref(self, vm: &Vm) -> Result<Val, Val<'a>> {
175 match self.inner {
176 UnsafeVal::MutableBox(id) => {
177 let mutable_box = vm.objects.get_mutable_box(id);
178 Ok(unsafe { Val::from_unsafe_val(*mutable_box) })
180 }
181 _ => Err(self),
182 }
183 }
184
185 pub fn type_name(self) -> &'static str {
187 self.inner.type_name()
188 }
189
190 pub fn formatted(self, vm: &Vm) -> impl '_ + std::fmt::Display {
192 self.inner.formatted(vm)
193 }
194
195 pub fn format_quoted(self, vm: &Vm) -> impl '_ + std::fmt::Display {
199 self.inner.format_quoted(vm)
200 }
201
202 pub fn is_custom(&self) -> bool {
204 matches!(self.inner, UnsafeVal::Custom(_))
205 }
206
207 pub fn try_custom<T: CustomType>(&self, vm: &'a Vm) -> Result<CustomValRef<T>, CustomValError> {
210 match self.inner {
211 UnsafeVal::Custom(id) => vm.objects.get_custom(id).get(),
212 _ => Err(CustomValError::WrongType {
213 expected: std::any::type_name::<T>(),
214 actual: self.type_name(),
215 }),
216 }
217 }
218
219 pub fn try_custom_mut<T: CustomType>(
222 &self,
223 vm: &'a Vm,
224 ) -> Result<CustomValMut<T>, CustomValError> {
225 match self.inner {
226 UnsafeVal::Custom(id) => vm.objects.get_custom(id).get_mut(),
227 _ => Err(CustomValError::WrongType {
228 expected: std::any::type_name::<T>(),
229 actual: self.type_name(),
230 }),
231 }
232 }
233}
234
235impl<'a> Val<'a> {
236 pub unsafe fn from_unsafe_val(v: UnsafeVal) -> Val<'a> {
242 Val {
243 inner: v,
244 _lifetime: PhantomData,
245 }
246 }
247
248 pub unsafe fn as_unsafe_val(self) -> UnsafeVal {
253 self.inner
254 }
255
256 pub unsafe fn as_static(self) -> Val<'static> {
261 Val {
262 inner: self.inner,
263 _lifetime: PhantomData,
264 }
265 }
266
267 pub unsafe fn from_unsafe_val_slice(v: &'a [UnsafeVal]) -> &'a [Val<'a>] {
273 debug_assert_eq!(
275 std::mem::size_of::<UnsafeVal>(),
276 std::mem::size_of::<Val<'a>>()
277 );
278 std::mem::transmute(v)
279 }
280
281 pub unsafe fn as_unsafe_val_slice<'b>(slice: &'b [Val<'a>]) -> &'b [UnsafeVal] {
286 debug_assert_eq!(
288 std::mem::size_of::<UnsafeVal>(),
289 std::mem::size_of::<Val<'a>>()
290 );
291 std::mem::transmute(slice)
292 }
293}
294
295macro_rules! to_val_impl {
296 ($rust_type:ty) => {
297 impl From<$rust_type> for Val<'static> {
299 fn from(v: $rust_type) -> Val<'static> {
300 unsafe { Self::from_unsafe_val(v.into()) }
301 }
302 }
303 };
304}
305
306to_val_impl!(());
307to_val_impl!(bool);
308to_val_impl!(i64);
309to_val_impl!(f64);
310
311#[cfg(test)]
312mod tests {
313 use super::*;
314
315 #[test]
316 fn static_values_can_be_created_outside_of_vm() {
317 assert_eq!(
318 Val::new_void().formatted(&Vm::default()).to_string(),
319 "<void>"
320 );
321 assert_eq!(
322 Val::new_bool(true).formatted(&Vm::default()).to_string(),
323 "true"
324 );
325 assert_eq!(Val::new_int(1).formatted(&Vm::default()).to_string(), "1");
326 assert_eq!(
327 Val::new_float(2.5).formatted(&Vm::default()).to_string(),
328 "2.5"
329 );
330 }
331}