lucia_lang/objects/
value.rs

1use std::{
2    fmt,
3    hash::{Hash, Hasher},
4    num::NonZeroUsize,
5};
6
7use gc_arena::{Collect, Gc};
8
9use crate::{
10    objects::{AnyCallback, AnyUserData, Closure, GcError, Str, Table},
11    utils::escape_str,
12};
13
14// canonical raw float bit
15const CANONICAL_NAN_BITS: u64 = 0x7ff8000000000000u64;
16const CANONICAL_ZERO_BITS: u64 = 0x0u64;
17
18/// Enum of lucia function (Closure / Callback).
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Collect)]
20#[collect(no_drop)]
21pub enum Function<'gc> {
22    Closure(Closure<'gc>),
23    Callback(AnyCallback<'gc>),
24}
25
26impl<'gc> From<Closure<'gc>> for Function<'gc> {
27    fn from(closure: Closure<'gc>) -> Self {
28        Self::Closure(closure)
29    }
30}
31
32impl<'gc> From<AnyCallback<'gc>> for Function<'gc> {
33    fn from(callback: AnyCallback<'gc>) -> Self {
34        Self::Callback(callback)
35    }
36}
37
38/// Enum of all lucia values.
39#[derive(Debug, Copy, Clone, Collect, Default)]
40#[collect(no_drop)]
41pub enum Value<'gc> {
42    /// `null` - A null value.
43    #[default]
44    Null,
45    /// `bool` - A `true` / `false` value.
46    Bool(bool),
47    /// `int` - A 64-bit integer.
48    Int(i64),
49    /// `float` - A 64-bit floating point number.
50    Float(f64),
51    /// `str` - A UTF-8 string.
52    Str(Str<'gc>),
53    /// `table` - A table.
54    Table(Table<'gc>),
55    /// `function` - A function.
56    Function(Function<'gc>),
57    /// `userdata` - An UserData.
58    UserData(AnyUserData<'gc>),
59    /// `error` - An error.
60    Error(GcError<'gc>),
61}
62
63impl<'gc> Value<'gc> {
64    pub fn metatable(&self) -> Option<Table<'gc>> {
65        match self {
66            Self::Table(t) => t.metatable(),
67            Self::UserData(u) => u.metatable(),
68            _ => None,
69        }
70    }
71
72    pub fn id(&self) -> Option<NonZeroUsize> {
73        match self {
74            Self::Null => None,
75            Self::Bool(_) => None,
76            Self::Int(_) => None,
77            Self::Float(_) => None,
78            Self::Str(v) => NonZeroUsize::new(Gc::as_ptr(v.0) as usize),
79            Self::Table(v) => NonZeroUsize::new(Gc::as_ptr(v.0) as usize),
80            Self::Function(Function::Closure(v)) => NonZeroUsize::new(Gc::as_ptr(v.0) as usize),
81            Self::Function(Function::Callback(v)) => NonZeroUsize::new(v.as_ptr() as usize),
82            Self::UserData(v) => NonZeroUsize::new(v.as_ptr() as usize),
83            Self::Error(v) => NonZeroUsize::new(Gc::as_ptr(v.0) as usize),
84        }
85    }
86
87    pub fn is(&self, other: &Value<'gc>) -> bool {
88        match (self, other) {
89            (Self::Null, Self::Null) => true,
90            (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
91            (Self::Int(l0), Self::Int(r0)) => l0 == r0,
92            (Self::Float(l0), Self::Float(r0)) => {
93                if l0.is_nan() {
94                    r0.is_nan()
95                } else {
96                    l0 == r0
97                }
98            }
99            (Self::Str(l0), Self::Str(r0)) => Gc::ptr_eq(l0.0, r0.0),
100            (Self::Table(l0), Self::Table(r0)) => Gc::ptr_eq(l0.0, r0.0),
101            (Self::Function(Function::Closure(l0)), Self::Function(Function::Closure(r0))) => {
102                Gc::ptr_eq(l0.0, r0.0)
103            }
104            (Self::Function(Function::Callback(l0)), Self::Function(Function::Callback(r0))) => {
105                l0.as_ptr() == r0.as_ptr()
106            }
107            (Self::UserData(l0), Self::UserData(r0)) => l0.as_ptr() == r0.as_ptr(),
108            (Self::Error(l0), Self::Error(r0)) => Gc::ptr_eq(l0.0, r0.0),
109            _ => false,
110        }
111    }
112
113    pub const fn value_type(self) -> ValueType {
114        match self {
115            Self::Null => ValueType::Null,
116            Self::Bool(_) => ValueType::Bool,
117            Self::Int(_) => ValueType::Int,
118            Self::Float(_) => ValueType::Float,
119            Self::Str(_) => ValueType::Str,
120            Self::Table(_) => ValueType::Table,
121            Self::Function(_) => ValueType::Function,
122            Self::UserData(_) => ValueType::UserData,
123            Self::Error(_) => ValueType::Error,
124        }
125    }
126
127    pub fn is_null(self) -> bool {
128        matches!(self, Self::Null)
129    }
130
131    pub fn repr(&self) -> String {
132        if let Self::Str(s) = self {
133            format!("\"{}\"", escape_str(s, false))
134        } else if let Self::Table(t) = self {
135            t.repr_table(self)
136        } else {
137            self.to_string()
138        }
139    }
140}
141
142impl<'gc> fmt::Display for Value<'gc> {
143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
144        match self {
145            Self::Null => write!(f, "null"),
146            Self::Bool(v) => write!(f, "{}", v),
147            Self::Int(v) => write!(f, "{}", v),
148            Self::Float(v) => write!(f, "{}", v),
149            Self::Str(v) => write!(f, "{}", v),
150            Self::Table(v) => write!(f, "<table {:p}>", v.0),
151            Self::Function(Function::Closure(v)) => write!(f, "<function {:p}>", v.0),
152            Self::Function(Function::Callback(v)) => write!(f, "<function {:p}>", v.as_ptr()),
153            Self::UserData(v) => write!(f, "<userdata {:p}>", v.as_ptr()),
154            Self::Error(e) => write!(f, "<error {}>", **e),
155        }
156    }
157}
158
159impl<'gc> PartialEq for Value<'gc> {
160    fn eq(&self, other: &Self) -> bool {
161        match (self, other) {
162            (Self::Null, Self::Null) => true,
163            (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
164            (Self::Int(l0), Self::Int(r0)) => l0 == r0,
165            (Self::Float(l0), Self::Float(r0)) => {
166                if l0.is_nan() {
167                    r0.is_nan()
168                } else {
169                    l0 == r0
170                }
171            }
172            (Self::Str(l0), Self::Str(r0)) => l0 == r0,
173            (Self::Table(l0), Self::Table(r0)) => l0 == r0,
174            (Self::Function(l0), Self::Function(r0)) => l0 == r0,
175            (Self::UserData(l0), Self::UserData(r0)) => l0 == r0,
176            (Self::Error(l0), Self::Error(r0)) => l0 == r0,
177            _ => false,
178        }
179    }
180}
181
182impl<'gc> Eq for Value<'gc> {}
183
184impl<'gc> Hash for Value<'gc> {
185    fn hash<H: Hasher>(&self, state: &mut H) {
186        match self {
187            Self::Null => 0.hash(state),
188            Self::Bool(v) => v.hash(state),
189            Self::Int(v) => v.hash(state),
190            Self::Float(v) => {
191                if v.is_nan() {
192                    CANONICAL_NAN_BITS.hash(state)
193                } else if *v == 0.0f64 {
194                    CANONICAL_ZERO_BITS.hash(state)
195                } else {
196                    (*v).to_bits().hash(state)
197                }
198            }
199            Self::Str(v) => v.hash(state),
200            Self::Table(v) => v.hash(state),
201            Self::Function(v) => v.hash(state),
202            Self::UserData(v) => v.hash(state),
203            Self::Error(v) => v.hash(state),
204        }
205    }
206}
207
208/// The type of Value.
209#[derive(Debug, Clone, Copy, Collect, PartialEq, Eq, Hash)]
210#[collect[require_static]]
211pub enum ValueType {
212    Null,
213    Bool,
214    Int,
215    Float,
216    Str,
217    Table,
218    Function,
219    UserData,
220    Error,
221}
222
223impl ValueType {
224    pub const fn name(self) -> &'static str {
225        match self {
226            ValueType::Null => "null",
227            ValueType::Bool => "bool",
228            ValueType::Int => "int",
229            ValueType::Float => "float",
230            ValueType::Str => "str",
231            ValueType::Table => "table",
232            ValueType::Function => "function",
233            ValueType::UserData => "userdata",
234            ValueType::Error => "error",
235        }
236    }
237}
238
239impl fmt::Display for ValueType {
240    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241        f.write_str(self.name())
242    }
243}