1use super::Result;
2use super::State;
3use super::object::{Closure, GcHeap, ObjectPtr, StringPtr};
4
5use std::borrow::Cow;
6use std::fmt;
7use std::hash::{Hash, Hasher};
8
9pub type RustFunc = fn(&mut State) -> Result<u8>;
15
16#[derive(Clone, Copy, Default)]
17pub(crate) enum Val {
18 #[default]
19 Nil,
20 Bool(bool),
21 Num(f64),
22 Str(StringPtr),
23 RustFn(RustFunc),
24 Obj(ObjectPtr),
25}
26use Val::*;
27
28impl Val {
29 pub(super) fn as_lua_function(&self, heap: &GcHeap) -> Option<Closure> {
32 if let Obj(o) = self {
33 heap.as_lua_function(*o)
34 } else {
35 None
36 }
37 }
38
39 pub(super) fn as_num(&self) -> Option<f64> {
40 match self {
41 Num(f) => Some(*f),
42 _ => None,
43 }
44 }
45
46 pub(super) fn as_string<'a>(&self, heap: &'a GcHeap) -> Option<&'a [u8]> {
49 if let Str(s) = self {
50 Some(heap.get_string(*s))
51 } else {
52 None
53 }
54 }
55
56 pub(super) fn as_string_ptr(&self) -> Option<StringPtr> {
58 if let Str(s) = self { Some(*s) } else { None }
59 }
60
61 pub(super) fn as_object_ptr(&self) -> Option<ObjectPtr> {
64 if let Obj(o) = self { Some(*o) } else { None }
65 }
66
67 pub(super) fn truthy(&self) -> bool {
68 !matches!(self, Nil | Bool(false))
69 }
70
71 pub(super) fn typ(&self, heap: &GcHeap) -> LuaType {
74 match self {
75 Nil => LuaType::Nil,
76 Bool(_) => LuaType::Boolean,
77 Num(_) => LuaType::Number,
78 RustFn(_) => LuaType::Function,
79 Str(_) => LuaType::String,
80 Obj(o) => o.typ(heap),
81 }
82 }
83
84 pub(super) fn typ_simple(&self) -> LuaType {
88 match self {
89 Nil => LuaType::Nil,
90 Bool(_) => LuaType::Boolean,
91 Num(_) => LuaType::Number,
92 RustFn(_) => LuaType::Function,
93 Str(_) => LuaType::String,
94 Obj(_) => LuaType::Table, }
96 }
97
98 pub(super) fn to_string_with_heap(self, heap: &GcHeap) -> String {
101 match self {
102 Nil => "nil".to_string(),
103 Bool(b) => b.to_string(),
104 Num(n) => n.to_string(),
105 RustFn(func) => format!("<function: {func:p}>"),
106 Obj(o) => format!("{o}"),
107 Str(s) => String::from_utf8_lossy(heap.get_string(s)).into_owned(),
108 }
109 }
110
111 pub(super) fn to_bytes_with_heap(self, heap: &GcHeap) -> Cow<'_, [u8]> {
112 match self {
113 Nil => Cow::Borrowed(b"nil"),
114 Bool(false) => Cow::Borrowed(b"false"),
115 Bool(true) => Cow::Borrowed(b"true"),
116 Num(n) => Cow::Owned(n.to_string().into_bytes()),
117 RustFn(func) => Cow::Owned(format!("<function: {func:p}>").into_bytes()),
118 Obj(o) => Cow::Owned(format!("{o}").into_bytes()),
119 Str(s) => Cow::Borrowed(heap.get_string(s)),
120 }
121 }
122}
123
124impl fmt::Debug for Val {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 match self {
127 Nil => write!(f, "nil"),
128 Bool(b) => b.fmt(f),
129 Num(n) => n.fmt(f),
130 RustFn(func) => write!(f, "<function: {func:p}>"),
131 Obj(o) => o.fmt(f),
132 Str(s) => s.fmt(f),
133 }
134 }
135}
136
137impl fmt::Display for Val {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 match self {
140 Nil => write!(f, "nil"),
141 Bool(b) => b.fmt(f),
142 Num(n) => n.fmt(f),
143 Obj(o) => o.fmt(f),
144 Str(s) => s.fmt(f),
145 RustFn(func) => write!(f, "<function: {func:p}>"),
146 }
147 }
148}
149
150impl Eq for Val {}
152
153impl Hash for Val {
154 fn hash<H: Hasher>(&self, hasher: &mut H) {
155 match self {
156 Nil => (),
157 Bool(b) => b.hash(hasher),
158 Obj(o) => o.hash(hasher),
159 Num(n) => {
160 assert!(!n.is_nan(), "Cannot use NaN as table key");
163 let mut bits = n.to_bits();
164 if bits == 1 << 63 {
165 bits = 0;
166 }
167 bits.hash(hasher);
168 }
169 RustFn(func) => {
170 let f: *const RustFunc = func;
171 f.hash(hasher);
172 }
173 Str(s) => s.hash(hasher),
174 }
175 }
176}
177
178impl PartialEq for Val {
179 fn eq(&self, other: &Val) -> bool {
180 match (self, other) {
181 (Nil, Nil) => true,
182 (Bool(a), Bool(b)) => a == b,
183 (Num(a), Num(b)) => a == b,
184 (RustFn(a), RustFn(b)) => {
185 let x: *const RustFunc = a;
186 let y: *const RustFunc = b;
187 x == y
188 }
189 (Obj(a), Obj(b)) => a == b,
190 (Str(a), Str(b)) => a == b,
192 _ => false,
193 }
194 }
195}
196
197#[derive(Debug, Eq, PartialEq)]
201pub enum LuaType {
202 Nil,
204 Boolean,
206 Number,
208 String,
210 Table,
212 Function,
214}
215
216impl LuaType {
217 pub fn as_str(&self) -> &'static str {
219 use LuaType::*;
220 match self {
221 Nil => "nil",
222 Boolean => "boolean",
223 Number => "number",
224 String => "string",
225 Table => "table",
226 Function => "function",
227 }
228 }
229}
230
231impl fmt::Display for LuaType {
232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 self.as_str().fmt(f)
234 }
235}