spore_vm/val/
unsafe_val.rs1use compact_str::CompactString;
2
3use crate::Vm;
4
5use super::{
6 bytecode::ByteCode, custom::CustomVal, formatter::ValFormatter, ListVal, NativeFunction,
7 StructVal, Symbol, ValId,
8};
9
10#[derive(Copy, Clone, Debug, Default, PartialEq)]
16pub enum UnsafeVal {
17 #[default]
19 Void,
20 Bool(bool),
22 Int(i64),
24 Float(f64),
26 String(ValId<CompactString>),
31 Symbol(Symbol),
33 MutableBox(ValId<UnsafeVal>),
38 List(ValId<ListVal>),
43 Struct(ValId<StructVal>),
45 ByteCodeFunction(ValId<ByteCode>),
50 NativeFunction(NativeFunction),
52 Custom(ValId<CustomVal>),
57}
58
59impl UnsafeVal {
60 pub const FUNCTION_TYPE_NAME: &'static str = "function";
62 pub const BOOL_TYPE_NAME: &'static str = "bool";
64 pub const INT_TYPE_NAME: &'static str = "int";
66 pub const FLOAT_TYPE_NAME: &'static str = "float";
68 pub const VOID_TYPE_NAME: &'static str = "void";
70 pub const SYMBOL_TYPE_NAME: &'static str = "symbol";
72 pub const STRING_TYPE_NAME: &'static str = "string";
74 pub const MUTABLE_BOX_TYPE_NAME: &'static str = "mutable-box";
76 pub const LIST_TYPE_NAME: &'static str = "list";
78 pub const STRUCT_TYPE_NAME: &'static str = "struct";
80 pub const CUSTOM_TYPE_NAME: &'static str = "custom";
82
83 pub fn type_name(self) -> &'static str {
85 match self {
86 UnsafeVal::Void => UnsafeVal::VOID_TYPE_NAME,
87 UnsafeVal::Bool(_) => UnsafeVal::BOOL_TYPE_NAME,
88 UnsafeVal::Int(_) => UnsafeVal::INT_TYPE_NAME,
89 UnsafeVal::Float(_) => UnsafeVal::FLOAT_TYPE_NAME,
90 UnsafeVal::String(_) => UnsafeVal::STRING_TYPE_NAME,
91 UnsafeVal::Symbol(_) => UnsafeVal::SYMBOL_TYPE_NAME,
92 UnsafeVal::MutableBox(_) => UnsafeVal::MUTABLE_BOX_TYPE_NAME,
93 UnsafeVal::List(_) => UnsafeVal::LIST_TYPE_NAME,
94 UnsafeVal::Struct(_) => UnsafeVal::STRUCT_TYPE_NAME,
95 UnsafeVal::ByteCodeFunction(_) => UnsafeVal::FUNCTION_TYPE_NAME,
96 UnsafeVal::NativeFunction(_) => UnsafeVal::FUNCTION_TYPE_NAME,
97 UnsafeVal::Custom(_) => UnsafeVal::CUSTOM_TYPE_NAME,
98 }
99 }
100
101 pub fn is_truthy(self) -> bool {
103 !matches!(self, UnsafeVal::Void | UnsafeVal::Bool(false))
104 }
105
106 pub fn formatted<'a>(&self, vm: &'a Vm) -> impl 'a + std::fmt::Display {
108 ValFormatter::new(vm, *self)
109 }
110
111 pub fn format_quoted<'a>(&self, vm: &'a Vm) -> impl 'a + std::fmt::Display {
114 ValFormatter::new_quoted(vm, *self)
115 }
116}
117
118macro_rules! to_internal_val_impl {
119 ($rust_type:ty => $variant:ident) => {
120 impl From<$rust_type> for UnsafeVal {
121 fn from(v: $rust_type) -> UnsafeVal {
122 UnsafeVal::$variant(v)
123 }
124 }
125 };
126}
127
128to_internal_val_impl!(bool => Bool);
129to_internal_val_impl!(i64 => Int);
130to_internal_val_impl!(f64 => Float);
131to_internal_val_impl!(NativeFunction => NativeFunction);
132to_internal_val_impl!(ValId<CompactString> => String);
133to_internal_val_impl!(ValId<UnsafeVal> => MutableBox);
134to_internal_val_impl!(ValId<ListVal> => List);
135to_internal_val_impl!(ValId<StructVal> => Struct);
136to_internal_val_impl!(ValId<ByteCode> => ByteCodeFunction);
137to_internal_val_impl!(ValId<CustomVal> => Custom);
138
139impl From<()> for UnsafeVal {
140 fn from(_: ()) -> UnsafeVal {
141 UnsafeVal::Void
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 #[test]
150 fn internal_val_is_small() {
151 assert_eq!(
152 std::mem::size_of::<UnsafeVal>(),
153 2 * std::mem::size_of::<usize>()
154 );
155 }
156
157 #[test]
158 fn hacks_for_code_coverage() {
159 let vals = [
160 UnsafeVal::Void,
161 UnsafeVal::Bool(false),
162 UnsafeVal::Int(0),
163 UnsafeVal::Float(0.0),
164 UnsafeVal::String(Default::default()),
165 UnsafeVal::MutableBox(Default::default()),
166 UnsafeVal::List(Default::default()),
167 UnsafeVal::ByteCodeFunction(Default::default()),
168 UnsafeVal::NativeFunction(crate::builtins::numbers::add),
169 UnsafeVal::Custom(ValId {
170 vm_id: 0,
171 obj_id: 0,
172 idx: 0,
173 _marker: std::marker::PhantomData,
174 }),
175 ];
176 for v in vals {
177 assert_ne!(v.type_name(), "");
178 }
179 }
180}