1use crate::error::Result;
11use crate::function::Function;
12use crate::state::Lua;
13use crate::string::LuaString;
14use crate::sys::*;
15use crate::table::Table;
16
17pub type Integer = i64;
19pub type Number = f64;
21
22#[derive(Clone, Debug)]
28pub enum Value {
29 Nil,
31 Boolean(bool),
33 Integer(Integer),
35 Number(Number),
37 String(LuaString),
39 Table(Table),
41 Function(Function),
43 LightUserData(crate::light_userdata::LightUserData),
45 UserData(crate::userdata::AnyUserData),
47 Thread(crate::thread::Thread),
49 Vector(crate::vector::Vector),
51 Buffer(crate::buffer::Buffer),
54 Error(Box<crate::error::Error>),
57}
58
59impl Value {
60 pub const NIL: Value = Value::Nil;
62
63 pub fn type_name(&self) -> &'static str {
65 match self {
66 Value::Nil => "nil",
67 Value::Boolean(_) => "boolean",
68 Value::Integer(_) | Value::Number(_) => "number",
69 Value::String(_) => "string",
70 Value::Table(_) => "table",
71 Value::Function(_) => "function",
72 Value::LightUserData(_) => "userdata",
73 Value::UserData(_) => "userdata",
74 Value::Thread(_) => "thread",
75 Value::Vector(_) => "vector",
76 Value::Buffer(_) => "buffer",
77 Value::Error(_) => "error",
78 }
79 }
80
81 pub fn is_error(&self) -> bool {
83 matches!(self, Value::Error(_))
84 }
85
86 pub fn as_error(&self) -> Option<&crate::error::Error> {
88 match self {
89 Value::Error(e) => Some(e),
90 _ => None,
91 }
92 }
93
94 pub fn is_nil(&self) -> bool {
96 matches!(self, Value::Nil)
97 }
98 pub fn is_boolean(&self) -> bool {
100 matches!(self, Value::Boolean(_))
101 }
102 pub fn is_number(&self) -> bool {
104 matches!(self, Value::Number(_) | Value::Integer(_))
105 }
106 pub fn is_integer(&self) -> bool {
108 matches!(self, Value::Integer(_))
109 }
110 pub fn is_string(&self) -> bool {
112 matches!(self, Value::String(_))
113 }
114 pub fn is_table(&self) -> bool {
116 matches!(self, Value::Table(_))
117 }
118 pub fn is_function(&self) -> bool {
120 matches!(self, Value::Function(_))
121 }
122
123 pub fn as_boolean(&self) -> Option<bool> {
125 match self {
126 Value::Boolean(b) => Some(*b),
127 _ => None,
128 }
129 }
130 pub fn as_integer(&self) -> Option<Integer> {
132 match self {
133 Value::Integer(i) => Some(*i),
134 _ => None,
135 }
136 }
137 pub fn as_number(&self) -> Option<Number> {
139 match self {
140 Value::Number(n) => Some(*n),
141 Value::Integer(i) => Some(*i as f64),
142 _ => None,
143 }
144 }
145 pub fn as_string(&self) -> Option<&LuaString> {
147 match self {
148 Value::String(s) => Some(s),
149 _ => None,
150 }
151 }
152 pub fn as_table(&self) -> Option<&Table> {
154 match self {
155 Value::Table(t) => Some(t),
156 _ => None,
157 }
158 }
159 pub fn as_function(&self) -> Option<&Function> {
161 match self {
162 Value::Function(f) => Some(f),
163 _ => None,
164 }
165 }
166
167 pub fn is_userdata(&self) -> bool {
169 matches!(self, Value::UserData(_))
170 }
171
172 pub fn as_userdata(&self) -> Option<&crate::userdata::AnyUserData> {
174 match self {
175 Value::UserData(u) => Some(u),
176 _ => None,
177 }
178 }
179
180 pub fn is_thread(&self) -> bool {
182 matches!(self, Value::Thread(_))
183 }
184
185 pub fn as_thread(&self) -> Option<&crate::thread::Thread> {
187 match self {
188 Value::Thread(t) => Some(t),
189 _ => None,
190 }
191 }
192
193 pub fn is_vector(&self) -> bool {
195 matches!(self, Value::Vector(_))
196 }
197
198 pub fn as_vector(&self) -> Option<&crate::vector::Vector> {
200 match self {
201 Value::Vector(v) => Some(v),
202 _ => None,
203 }
204 }
205
206 pub fn is_buffer(&self) -> bool {
208 matches!(self, Value::Buffer(_))
209 }
210
211 pub fn as_buffer(&self) -> Option<&crate::buffer::Buffer> {
213 match self {
214 Value::Buffer(b) => Some(b),
215 _ => None,
216 }
217 }
218
219 pub fn as_i32(&self) -> Option<i32> {
221 self.as_integer().and_then(|i| i32::try_from(i).ok())
222 }
223 pub fn as_u32(&self) -> Option<u32> {
225 self.as_integer().and_then(|i| u32::try_from(i).ok())
226 }
227 pub fn as_i64(&self) -> Option<i64> {
229 self.as_integer()
230 }
231 pub fn as_u64(&self) -> Option<u64> {
233 self.as_integer().and_then(|i| u64::try_from(i).ok())
234 }
235 pub fn as_isize(&self) -> Option<isize> {
237 self.as_integer().and_then(|i| isize::try_from(i).ok())
238 }
239 pub fn as_usize(&self) -> Option<usize> {
241 self.as_integer().and_then(|i| usize::try_from(i).ok())
242 }
243 pub fn as_f32(&self) -> Option<f32> {
245 self.as_number().map(|n| n as f32)
246 }
247 pub fn as_f64(&self) -> Option<f64> {
249 self.as_number()
250 }
251
252 pub fn to_pointer(&self) -> *const std::ffi::c_void {
256 match self {
257 Value::LightUserData(lud) => lud.0 as *const std::ffi::c_void,
258 Value::String(s) => s.to_pointer(),
259 Value::Table(t) => t.to_pointer(),
260 Value::Function(f) => f.to_pointer(),
261 Value::UserData(u) => u.to_pointer(),
262 Value::Thread(t) => t.to_pointer(),
263 Value::Buffer(b) => b.to_pointer(),
266 _ => core::ptr::null(),
267 }
268 }
269
270 pub fn equals(&self, other: &Value) -> Result<bool> {
273 match (self, other) {
276 (Value::Table(a), Value::Table(b)) => a.equals(b),
277 (Value::UserData(a), Value::UserData(b)) => a.equals(b),
278 _ => Ok(self == other),
279 }
280 }
281
282 #[allow(clippy::inherent_to_string_shadow_display)]
285 pub fn to_string(&self) -> Result<String> {
286 match self {
287 Value::Nil => Ok("nil".to_string()),
288 Value::Boolean(b) => Ok(b.to_string()),
289 Value::Integer(i) => Ok(i.to_string()),
290 Value::Number(n) => Ok(crate::value::format_number(*n)),
291 Value::Error(e) => Ok(e.to_string()),
292 Value::Vector(v) => Ok(v.to_string()),
295 Value::LightUserData(lud) => Ok(format!("userdata: {:p}", lud.0)),
298 Value::String(s) => s.to_str(),
300 other => {
301 let lua = match other {
303 Value::Table(t) => t.lua(),
304 Value::Function(f) => f.lua(),
305 Value::UserData(u) => u.lua(),
306 Value::Thread(t) => t.lua(),
307 Value::Buffer(b) => b.lua(),
308 _ => unreachable!(),
309 };
310 lua.value_to_string(other)
311 }
312 }
313 }
314}
315
316pub(crate) fn format_number(n: f64) -> String {
319 if n.fract() == 0.0 && n.is_finite() && n.abs() < 1e15 {
320 format!("{}", n as i64)
321 } else {
322 let s = format!("{n}");
325 s
326 }
327}
328
329impl PartialEq for Value {
330 fn eq(&self, other: &Self) -> bool {
331 match (self, other) {
332 (Value::Nil, Value::Nil) => true,
333 (Value::Boolean(a), Value::Boolean(b)) => a == b,
334 (Value::LightUserData(a), Value::LightUserData(b)) => a == b,
335 (Value::Integer(a), Value::Integer(b)) => a == b,
338 (Value::Number(a), Value::Number(b)) => a == b,
339 (Value::Integer(a), Value::Number(b)) | (Value::Number(b), Value::Integer(a)) => {
340 (*a as f64) == *b
341 }
342 (Value::String(a), Value::String(b)) => a == b,
343 (Value::Table(a), Value::Table(b)) => a.to_pointer() == b.to_pointer(),
345 (Value::Function(a), Value::Function(b)) => a.to_pointer() == b.to_pointer(),
346 (Value::UserData(a), Value::UserData(b)) => a.to_pointer() == b.to_pointer(),
347 (Value::Thread(a), Value::Thread(b)) => a.to_pointer() == b.to_pointer(),
348 (Value::Vector(a), Value::Vector(b)) => a == b,
351 (Value::Buffer(a), Value::Buffer(b)) => a.to_pointer() == b.to_pointer(),
352 (Value::Error(a), Value::Error(b)) => a.to_string() == b.to_string(),
353 _ => false,
354 }
355 }
356}
357
358fn is_exact_integer(n: f64) -> bool {
361 n.fract() == 0.0 && n.is_finite() && n >= i64::MIN as f64 && n <= i64::MAX as f64
362}
363
364pub(crate) fn push_value(lua: &Lua, value: &Value) -> Result<()> {
366 let state = lua.state();
367 unsafe {
368 match value {
369 Value::Nil => lua_pushnil(state),
370 Value::Boolean(b) => lua_pushboolean(state, *b as c_int),
371 Value::LightUserData(lud) => lua_pushlightuserdatatagged(state, lud.0, 0),
373 Value::Integer(i) => lua_pushnumber(state, *i as f64),
374 Value::Number(n) => lua_pushnumber(state, *n),
375 Value::String(s) => s.push_to_stack(),
376 Value::Table(t) => t.push_to_stack(),
377 Value::Function(f) => f.push_to_stack(),
378 Value::UserData(u) => u.push_to_stack(),
379 Value::Thread(t) => t.push_to_stack(),
380 Value::Buffer(b) => b.push_to_stack(),
381 Value::Vector(v) => {
384 lua_pushvector_lua_state_f32_f32_f32_f32(state, v.x(), v.y(), v.z(), 0.0)
385 }
386 Value::Error(e) => {
390 let msg = e.to_string();
391 lua_pushlstring(state, msg.as_ptr() as *const c_char, msg.len());
392 }
393 }
394 }
395 Ok(())
396}
397
398pub(crate) fn value_from_stack(lua: &Lua, idx: c_int) -> Result<Value> {
401 let state = lua.state();
402 unsafe {
403 let t = lua_type(state, idx);
404 let value = match t {
405 x if x == ttype::NIL || x == ttype::NONE => Value::Nil,
406 x if x == ttype::BOOLEAN => Value::Boolean(lua_toboolean(state, idx) != 0),
407 x if x == ttype::LIGHTUSERDATA => {
408 let p = lua_tolightuserdata(state, idx);
409 Value::LightUserData(crate::light_userdata::LightUserData(p))
410 }
411 x if x == ttype::NUMBER => {
412 let n = lua_tonumberx(state, idx, core::ptr::null_mut());
413 if is_exact_integer(n) {
414 Value::Integer(n as i64)
415 } else {
416 Value::Number(n)
417 }
418 }
419 x if x == ttype::STRING => {
420 lua_pushvalue(state, idx);
421 Value::String(LuaString::from_ref(lua.pop_ref()))
422 }
423 x if x == ttype::TABLE => {
424 lua_pushvalue(state, idx);
425 Value::Table(Table::from_ref(lua.pop_ref()))
426 }
427 x if x == ttype::FUNCTION => {
428 lua_pushvalue(state, idx);
429 Value::Function(Function::from_ref(lua.pop_ref()))
430 }
431 x if x == ttype::USERDATA => {
432 lua_pushvalue(state, idx);
433 Value::UserData(crate::userdata::AnyUserData::from_ref(lua.pop_ref()))
434 }
435 x if x == ttype::THREAD => {
436 lua_pushvalue(state, idx);
437 Value::Thread(crate::thread::Thread::from_ref(lua.pop_ref()))
438 }
439 x if x == ttype::VECTOR => {
440 let p = lua_tovector(state, idx);
443 if p.is_null() {
444 Value::Nil
445 } else {
446 let comps = core::slice::from_raw_parts(p, crate::vector::Vector::SIZE);
447 Value::Vector(crate::vector::Vector::new(comps[0], comps[1], comps[2]))
448 }
449 }
450 x if x == ttype::BUFFER => {
451 lua_pushvalue(state, idx);
452 Value::Buffer(crate::buffer::Buffer::from_ref(lua.pop_ref()))
453 }
454 _ => Value::Nil,
456 };
457 Ok(value)
458 }
459}