sphinx/runtime/
variant.rs

1use core::fmt;
2use core::hash::{Hash, Hasher};
3use static_assertions::const_assert_eq;
4use crate::language::{IntType, FloatType};
5use crate::runtime::types::{Tuple, UserData, UserIterator, Marker};
6use crate::runtime::function::{Function, NativeFunction};
7use crate::runtime::strings::{StringValue, StringSymbol, InlineStr};
8use crate::runtime::gc::{Gc, GcTrace};
9use crate::runtime::errors::{ExecResult, RuntimeError};
10
11
12// try to use less memory on 32-bit architectures
13#[cfg(target_pointer_width = "32")]
14const_assert_eq!(core::mem::size_of::<Variant>(), 8);
15
16#[cfg(target_pointer_width = "64")]
17const_assert_eq!(core::mem::size_of::<Variant>(), 16);
18
19// Fundamental data value type
20#[derive(Clone, Copy)]
21pub enum Variant {
22    Nil,
23    BoolTrue,
24    BoolFalse,
25    
26    Marker(Marker),
27    
28    Integer(IntType),
29    Float(FloatType),
30    
31    // separate different string types here to keep size down
32    InternStr(StringSymbol),
33    InlineStr(InlineStr),
34    GCStr(Gc<str>),
35    
36    Tuple(Tuple),
37    Function(Gc<Function>),
38    NativeFunction(Gc<NativeFunction>),
39    
40    Iterator(Gc<dyn UserIterator>),
41    
42    Error(Gc<RuntimeError>),
43    
44    UserData(Gc<dyn UserData>),
45}
46
47unsafe impl GcTrace for Variant {
48    #[inline]
49    fn trace(&self) {
50        match self {
51            Self::Tuple(tuple) => tuple.trace(),
52            Self::Function(fun) => fun.mark_trace(),
53            Self::NativeFunction(fun) => fun.mark_trace(),
54            Self::Iterator(iter) => iter.mark_trace(),
55            Self::UserData(data) => data.mark_trace(),
56            _ => { },
57        };
58    }
59}
60
61impl Variant {
62    pub fn marker(id: StringSymbol) -> Self {
63        Self::Marker(Marker::new(id))
64    }
65    
66    pub fn is_nil(&self) -> bool {
67        matches!(self, Variant::Nil)
68    }
69    
70    pub fn as_strval(&self) -> Option<StringValue> {
71        match self {
72            Self::InternStr(symbol) => Some(StringValue::from(*symbol)),
73            Self::InlineStr(inline) => Some(StringValue::from(*inline)),
74            Self::GCStr(gc_str) => Some(StringValue::from(*gc_str)),
75            _ => None,
76        }
77    }
78    
79    pub fn display_echo(&self) -> impl fmt::Display + '_ {
80        struct Display<'a>(&'a Variant);
81        impl fmt::Display for Display<'_> {
82            fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
83                match self.0.fmt_repr() {
84                    Ok(strval) => write!(fmt, "{}", strval),
85                    Err(error) => write!(fmt, "{}", error),
86                }
87            }
88        }
89        
90        Display(self)
91    }
92    
93    pub fn fmt_str(&self) -> ExecResult<StringValue> {
94        if let Some(strval) = self.as_strval() {
95            Ok(strval)
96        } else {
97            self.fmt_repr()
98        }
99    }
100}
101
102
103impl From<bool> for Variant {
104    fn from(value: bool) -> Self {
105        match value {
106            true => Self::BoolTrue,
107            false => Self::BoolFalse,
108        }
109    }
110}
111
112impl From<IntType> for Variant {
113    fn from(value: IntType) -> Self { Self::Integer(value) }
114}
115
116impl From<FloatType> for Variant {
117    fn from(value: FloatType) -> Self { Self::Float(value) }
118}
119
120impl From<StringValue> for Variant {
121    fn from(value: StringValue) -> Self {
122        match value {
123            StringValue::Intern(symbol) => Self::InternStr(symbol),
124            StringValue::Inline(inline) => Self::InlineStr(inline),
125            StringValue::Gc(gc_str) => Self::GCStr(gc_str),
126        }
127    }
128}
129
130impl From<StringSymbol> for Variant {
131    fn from(symbol: StringSymbol) -> Self {
132        Self::InternStr(symbol)
133    }
134}
135
136impl From<Box<[Variant]>> for Variant {
137    fn from(items: Box<[Variant]>) -> Self {
138        Self::Tuple(items.into())
139    }
140}
141
142impl From<Function> for Variant {
143    fn from(func: Function) -> Self {
144        Self::Function(Gc::new(func))
145    }
146}
147
148impl From<NativeFunction> for Variant {
149    fn from(func: NativeFunction) -> Self {
150        Self::NativeFunction(Gc::new(func))
151    }
152}
153
154
155// Not all Variants are hashable
156impl Variant {
157    pub fn can_hash(&self) -> bool {
158        struct DummyHasher();
159        impl Hasher for DummyHasher {
160            fn finish(&self) -> u64 { 0 }
161            fn write(&mut self, _: &[u8]) { }
162        }
163        self.try_hash(&mut DummyHasher()).is_ok()
164    }
165    
166    fn try_hash<H: Hasher>(&self, state: &mut H) -> ExecResult<()> {
167        let discr = core::mem::discriminant(self);
168        
169        match self {
170            Self::Nil | Self::BoolTrue | Self::BoolFalse 
171                => discr.hash(state),
172            
173            Self::Integer(value) => (discr, value).hash(state),
174            
175            Self::Function(fun) => (discr, fun).hash(state),
176            Self::NativeFunction(fun) => (discr, fun).hash(state),
177            Self::Tuple(items) => {
178                discr.hash(state); // also prevent prefix collisions
179                for item in items.as_ref().iter() {
180                    item.try_hash(state)?;
181                }
182            },
183            
184            Self::InternStr(..) | Self::InlineStr(..) | Self::GCStr(..) =>
185                self.as_strval().unwrap().hash(state),
186            
187            _ => return Err(RuntimeError::unhashable_value(self)),
188        }
189        Ok(())
190    }
191    
192}
193
194
195/// Wrapper for variant that dynamically ensures hashability
196#[derive(Clone)]
197pub struct VariantKey<'a>(&'a Variant);
198
199impl<'a> TryFrom<&'a Variant> for VariantKey<'a> {
200    type Error = Box<RuntimeError>;
201    fn try_from(value: &'a Variant) -> ExecResult<Self> {
202        if !value.can_hash() {
203            return Err(RuntimeError::unhashable_value(value));
204        }
205        Ok(Self(value))
206    }
207}
208
209impl Hash for VariantKey<'_> {
210    fn hash<H: Hasher>(&self, state: &mut H) {
211        self.0.try_hash(state).unwrap()
212    }
213}
214
215impl<'s> PartialEq for VariantKey<'_> {
216    fn eq(&self, other: &VariantKey) -> bool {
217        self.0.cmp_eq(other.0).unwrap_or(false)
218    }
219}
220impl Eq for VariantKey<'_> { }
221
222impl fmt::Display for Variant {
223    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
224        match self.fmt_repr() {
225            Ok(strval) => write!(fmt, "{}", strval),
226            Err(error) => write!(fmt, "{}", error),
227        }
228    }
229}
230
231macro_rules! debug_tuple {
232    ( $fmt:expr, $name:expr, $( $debug:expr ),* ) => {
233        $fmt.debug_tuple($name)
234            $( .field($debug) )*
235            .finish()
236    }
237}
238
239impl fmt::Debug for Variant {
240    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
241        match self {
242            Self::Nil => fmt.write_str("Nil"),
243            Self::BoolTrue => fmt.write_str("True"),
244            Self::BoolFalse => fmt.write_str("False"),
245            Self::Marker(marker) => debug_tuple!(fmt, "Marker", marker),
246            Self::Integer(value) => debug_tuple!(fmt, "Integer", value),
247            Self::Float(value) => debug_tuple!(fmt, "Float", value),
248            Self::InternStr(value) => debug_tuple!(fmt, "InternStr", value),
249            Self::InlineStr(value) => debug_tuple!(fmt, "InlineStr", &value.to_string()),
250            Self::GCStr(gc_str) => debug_tuple!(fmt, "GCStr", &gc_str.to_string()),
251            Self::Tuple(tuple) => debug_tuple!(fmt, "Tuple", tuple),
252            Self::Function(fun)
253                => debug_tuple!(fmt, "Function", &fun.signature().fmt_signature().to_string()),
254            Self::NativeFunction(fun) 
255                => debug_tuple!(fmt, "NativeFunction", &fun.signature().fmt_signature().to_string()),
256            Self::Iterator(iter) => debug_tuple!(fmt, "Iterator", iter),
257            Self::Error(error) => write!(fmt, "{:?}", &**error),
258            Self::UserData(data) => debug_tuple!(fmt, "UserData", data),
259        }
260    }
261}