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
14const CANONICAL_NAN_BITS: u64 = 0x7ff8000000000000u64;
16const CANONICAL_ZERO_BITS: u64 = 0x0u64;
17
18#[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#[derive(Debug, Copy, Clone, Collect, Default)]
40#[collect(no_drop)]
41pub enum Value<'gc> {
42 #[default]
44 Null,
45 Bool(bool),
47 Int(i64),
49 Float(f64),
51 Str(Str<'gc>),
53 Table(Table<'gc>),
55 Function(Function<'gc>),
57 UserData(AnyUserData<'gc>),
59 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#[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}