1use core::ptr::NonNull;
2
3use crate::Table;
4use crate::buffer::Buffer;
5use crate::function::{Closure, Proto, UpVal};
6use crate::handle::RawHandle;
7use crate::state::ThreadState;
8use crate::string::TString;
9use crate::thread::Thread;
10use crate::types::{
11 LUA_EXTRA_SIZE, LUA_TBOOLEAN, LUA_TBUFFER, LUA_TCLASS, LUA_TFUNCTION, LUA_TINTEGER,
12 LUA_TLIGHTUSERDATA, LUA_TNIL, LUA_TNUMBER, LUA_TOBJECT, LUA_TPROTO, LUA_TSTRING, LUA_TTABLE,
13 LUA_TTHREAD, LUA_TUPVALUE, LUA_TUSERDATA, LUA_TVECTOR, LUA_VECTOR_SIZE,
14};
15use crate::userdata::Userdata;
16use crate::{Class, Object};
17
18use crate::gc::{GcObject, RawGcObject};
19
20#[derive(Clone, Copy)]
21#[repr(C)]
22pub union RawValue {
23 pub gc: *mut RawGcObject,
24 pub pointer: *mut (),
25 pub number: f64,
26 pub boolean: i32,
27 pub integer: i64,
28 pub vector: [f32; 2],
29}
30
31#[derive(Clone, Copy)]
32#[repr(C)]
33pub struct RawTValue {
34 pub value: RawValue,
35 pub extra: [i32; LUA_EXTRA_SIZE],
36 pub tt: i32,
37}
38
39impl RawTValue {
40 pub const fn nil() -> Self {
41 Self {
42 value: RawValue {
43 pointer: core::ptr::null_mut(),
44 },
45 extra: [0; LUA_EXTRA_SIZE],
46 tt: LUA_TNIL,
47 }
48 }
49
50 pub const fn number(value: f64) -> Self {
51 Self {
52 value: RawValue { number: value },
53 extra: [0; LUA_EXTRA_SIZE],
54 tt: LUA_TNUMBER,
55 }
56 }
57
58 pub fn string(value: TString) -> Self {
59 Self {
60 value: RawValue {
61 gc: GcObject::from(value).as_ptr(),
62 },
63 extra: [0; LUA_EXTRA_SIZE],
64 tt: LUA_TSTRING,
65 }
66 }
67
68 pub const fn light_userdata(pointer: *mut (), tag: i32) -> Self {
69 let mut extra = [0; LUA_EXTRA_SIZE];
70 extra[0] = tag;
71 Self {
72 value: RawValue { pointer },
73 extra,
74 tt: LUA_TLIGHTUSERDATA,
75 }
76 }
77}
78
79pub const RAW_TVALUE_NIL: RawTValue = RawTValue::nil();
80
81#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
82#[repr(transparent)]
83pub struct TValueCursor(*mut RawTValue);
89
90#[allow(
91 clippy::missing_safety_doc,
92 reason = "TValueCursor navigation is governed by its documented non-owning cursor contract"
93)]
94impl TValueCursor {
95 pub const fn as_ptr(&self) -> *mut RawTValue {
99 self.0
100 }
101
102 pub const fn from_ptr(raw: *mut RawTValue) -> Self {
103 Self(raw)
104 }
105
106 pub const fn is_null(&self) -> bool {
107 self.0.is_null()
108 }
109
110 pub unsafe fn is_nil_unchecked(&self) -> bool {
111 debug_assert!(!self.is_null());
112 unsafe { (*self.as_ptr()).tt == LUA_TNIL }
113 }
114
115 pub unsafe fn value_unchecked(&self) -> TValue {
116 debug_assert!(!self.is_null());
117 unsafe { TValue::from_raw(NonNull::new_unchecked(self.0)) }
118 }
119
120 pub fn value(&self) -> Option<TValue> {
121 NonNull::new(self.0).map(|raw| unsafe { TValue::from_raw(raw) })
122 }
123
124 pub unsafe fn add(self, count: usize) -> Self {
125 unsafe { Self::from_ptr(self.0.add(count)) }
126 }
127
128 pub unsafe fn sub(self, count: usize) -> Self {
129 unsafe { Self::from_ptr(self.0.sub(count)) }
130 }
131
132 pub unsafe fn offset(self, count: isize) -> Self {
133 unsafe { Self::from_ptr(self.0.offset(count)) }
134 }
135
136 pub unsafe fn offset_from(self, other: Self) -> isize {
137 unsafe { self.0.offset_from(other.0) }
138 }
139
140 pub fn addr_offset_from(self, other: Self) -> isize {
141 let byte_offset = self.0 as isize - other.0 as isize;
142 debug_assert_eq!(byte_offset % core::mem::size_of::<RawTValue>() as isize, 0);
143 byte_offset / core::mem::size_of::<RawTValue>() as isize
144 }
145}
146
147impl AsRef<TValueCursor> for TValueCursor {
148 fn as_ref(&self) -> &TValueCursor {
149 self
150 }
151}
152
153#[derive(Clone, Copy, PartialEq, Eq)]
154#[repr(transparent)]
155pub struct TValue {
163 raw: NonNull<RawTValue>,
164}
165
166#[repr(transparent)]
167pub struct NilObject(RawTValue);
168
169unsafe impl Sync for NilObject {}
170
171pub static LUA_O_NIL_OBJECT: NilObject = NilObject(RAW_TVALUE_NIL);
172#[allow(
173 clippy::missing_safety_doc,
174 reason = "TValue's shared raw-view contract is documented on TValue"
175)]
176impl TValue {
177 pub const unsafe fn from_raw(raw: NonNull<RawTValue>) -> Self {
178 Self { raw }
179 }
180
181 pub unsafe fn from_ref(raw: &RawTValue) -> Self {
182 Self {
183 raw: NonNull::from(raw),
184 }
185 }
186
187 pub unsafe fn from_mut(raw: &mut RawTValue) -> Self {
188 Self {
189 raw: NonNull::from(raw),
190 }
191 }
192
193 pub fn is_nil(&self) -> bool {
195 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt == LUA_TNIL }
196 }
197
198 pub fn is_number(&self) -> bool {
200 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt == LUA_TNUMBER }
201 }
202
203 pub fn is_integer(&self) -> bool {
205 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt == LUA_TINTEGER }
206 }
207
208 pub fn is_string(&self) -> bool {
210 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt == LUA_TSTRING }
211 }
212
213 pub fn is_table(&self) -> bool {
215 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt == LUA_TTABLE }
216 }
217
218 pub fn is_function(&self) -> bool {
220 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt == LUA_TFUNCTION }
221 }
222
223 pub fn is_native_function(&self) -> bool {
225 if !self.is_function() {
226 return false;
227 }
228
229 let closure = self.closure_value();
230 unsafe { closure.is_native() }
231 }
232
233 pub fn is_lua_function(&self) -> bool {
235 if !self.is_function() {
236 return false;
237 }
238
239 let closure = self.closure_value();
240 unsafe { closure.is_lua() }
241 }
242
243 pub fn is_boolean(&self) -> bool {
245 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt == LUA_TBOOLEAN }
246 }
247
248 pub fn is_userdata(&self) -> bool {
250 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt == LUA_TUSERDATA }
251 }
252
253 pub fn is_thread(&self) -> bool {
255 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt == LUA_TTHREAD }
256 }
257
258 pub fn is_buffer(&self) -> bool {
260 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt == LUA_TBUFFER }
261 }
262
263 pub fn is_light_userdata(&self) -> bool {
265 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt == LUA_TLIGHTUSERDATA }
266 }
267
268 pub fn is_vector(&self) -> bool {
270 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt == LUA_TVECTOR }
271 }
272
273 pub fn is_class(&self) -> bool {
275 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt == LUA_TCLASS }
276 }
277
278 pub fn is_object(&self) -> bool {
280 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt == LUA_TOBJECT }
281 }
282
283 pub fn is_upvalue(&self) -> bool {
285 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt == LUA_TUPVALUE }
286 }
287
288 pub fn is_proto(&self) -> bool {
289 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt == LUA_TPROTO }
290 }
291
292 pub fn is_collectable(&self) -> bool {
294 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt >= LUA_TSTRING }
295 }
296
297 pub fn tt(&self) -> i32 {
299 unsafe { self.as_ptr().as_ref().unwrap_unchecked().tt }
300 }
301
302 pub fn is_false(&self) -> bool {
304 let value = unsafe { self.as_ptr().as_ref().unwrap_unchecked() };
305 value.tt == LUA_TNIL || (value.tt == LUA_TBOOLEAN && unsafe { value.value.boolean } == 0)
306 }
307
308 pub fn gc_value(&self) -> GcObject {
310 debug_assert!(self.is_collectable());
311 unsafe {
312 GcObject::from_raw(NonNull::new_unchecked(
313 self.as_ptr().as_ref().unwrap_unchecked().value.gc,
314 ))
315 }
316 }
317
318 pub fn string_value(&self) -> TString {
320 debug_assert!(self.is_string());
321 unsafe {
322 TString::from_raw(NonNull::new_unchecked(
323 self.as_ptr().as_ref().unwrap_unchecked().value.gc.cast(),
324 ))
325 }
326 }
327
328 pub fn table_value(&self) -> Table {
330 debug_assert!(self.is_table());
331 unsafe {
332 Table::from_raw(NonNull::new_unchecked(
333 self.as_ptr().as_ref().unwrap_unchecked().value.gc.cast(),
334 ))
335 }
336 }
337
338 pub fn userdata_value(&self) -> Userdata {
340 debug_assert!(self.is_userdata());
341 unsafe {
342 Userdata::from_raw(NonNull::new_unchecked(
343 self.as_ptr().as_ref().unwrap_unchecked().value.gc.cast(),
344 ))
345 }
346 }
347
348 pub fn closure_value(&self) -> Closure {
350 debug_assert!(self.is_function());
351 unsafe {
352 Closure::from_raw(NonNull::new_unchecked(
353 self.as_ptr().as_ref().unwrap_unchecked().value.gc.cast(),
354 ))
355 }
356 }
357
358 pub fn pointer_value(&self) -> *mut () {
360 debug_assert!(self.is_light_userdata());
361 unsafe { self.as_ptr().as_ref().unwrap_unchecked().value.pointer }
362 }
363
364 pub fn number_value(&self) -> f64 {
366 debug_assert!(self.is_number());
367 unsafe { self.as_ptr().as_ref().unwrap_unchecked().value.number }
368 }
369
370 pub fn integer_value(&self) -> i64 {
372 debug_assert!(self.is_integer());
373 unsafe { self.as_ptr().as_ref().unwrap_unchecked().value.integer }
374 }
375
376 pub fn boolean_value(&self) -> i32 {
378 debug_assert!(self.is_boolean());
379 unsafe { self.as_ptr().as_ref().unwrap_unchecked().value.boolean }
380 }
381
382 pub fn thread_value(&self) -> Thread {
384 debug_assert!(self.is_thread());
385 unsafe {
386 Thread::from_raw(NonNull::new_unchecked(
387 self.as_ptr().as_ref().unwrap_unchecked().value.gc.cast(),
388 ))
389 }
390 }
391
392 pub fn buffer_value(&self) -> Buffer {
394 debug_assert!(self.is_buffer());
395 unsafe {
396 Buffer::from_raw(NonNull::new_unchecked(
397 self.as_ptr().as_ref().unwrap_unchecked().value.gc.cast(),
398 ))
399 }
400 }
401
402 pub fn upvalue_value(&self) -> UpVal {
404 debug_assert!(self.is_upvalue());
405 unsafe {
406 UpVal::from_raw(NonNull::new_unchecked(
407 self.as_ptr().as_ref().unwrap_unchecked().value.gc.cast(),
408 ))
409 }
410 }
411
412 pub fn class_value(&self) -> Class {
414 debug_assert!(self.is_class());
415 unsafe {
416 Class::from_raw(NonNull::new_unchecked(
417 self.as_ptr().as_ref().unwrap_unchecked().value.gc.cast(),
418 ))
419 }
420 }
421
422 pub fn object_value(&self) -> Object {
424 debug_assert!(self.is_object());
425 unsafe {
426 Object::from_raw(NonNull::new_unchecked(
427 self.as_ptr().as_ref().unwrap_unchecked().value.gc.cast(),
428 ))
429 }
430 }
431
432 pub fn proto_value(&self) -> Proto {
434 debug_assert!(self.is_proto());
435 unsafe { self.gc_value().to_proto() }
436 }
437
438 pub fn light_userdata_tag(&self) -> i32 {
440 debug_assert!(self.is_light_userdata());
441 unsafe { self.as_ptr().as_ref().unwrap_unchecked().extra[0] }
442 }
443
444 pub fn vector_value(&self) -> [f32; LUA_VECTOR_SIZE] {
446 debug_assert!(self.is_vector());
447 let vector = self.as_ptr().cast::<f32>();
448 #[cfg(not(feature = "vector4"))]
449 unsafe {
450 [*vector, *vector.add(1), *vector.add(2)]
451 }
452 #[cfg(feature = "vector4")]
453 unsafe {
454 [*vector, *vector.add(1), *vector.add(2), *vector.add(3)]
455 }
456 }
457
458 pub fn set_nil(&self) {
460 unsafe {
461 self.as_ptr().as_mut().unwrap_unchecked().tt = LUA_TNIL;
462 }
463 }
464
465 pub fn set_number(&self, value: f64) {
467 unsafe {
468 let raw = self.as_ptr().as_mut().unwrap_unchecked();
469 raw.value = RawValue { number: value };
470 raw.tt = LUA_TNUMBER;
471 }
472 }
473
474 pub fn set_integer(&self, value: i64) {
476 unsafe {
477 let raw = self.as_ptr().as_mut().unwrap_unchecked();
478 raw.value = RawValue { integer: value };
479 raw.tt = LUA_TINTEGER;
480 }
481 }
482
483 pub fn set_boolean(&self, value: i32) {
485 unsafe {
486 let raw = self.as_ptr().as_mut().unwrap_unchecked();
487 raw.value = RawValue { boolean: value };
488 raw.tt = LUA_TBOOLEAN;
489 }
490 }
491
492 pub fn set_light_userdata(&self, pointer: *mut (), tag: i32) {
494 unsafe {
495 let raw = self.as_ptr().as_mut().unwrap_unchecked();
496 raw.value = RawValue { pointer };
497 raw.extra[0] = tag;
498 raw.tt = LUA_TLIGHTUSERDATA;
499 }
500 }
501
502 pub fn set_string_value(&self, value: TString) {
504 unsafe {
505 let raw = self.as_ptr().as_mut().unwrap_unchecked();
506 raw.value = RawValue {
507 gc: GcObject::from(value).as_ptr(),
508 };
509 raw.tt = LUA_TSTRING;
510 }
511 }
512
513 pub fn set_vector(&self, value: [f32; LUA_VECTOR_SIZE]) {
515 let vector = self.as_ptr().cast::<f32>();
516 unsafe {
517 *vector = value[0];
518 *vector.add(1) = value[1];
519 *vector.add(2) = value[2];
520 }
521 #[cfg(feature = "vector4")]
522 unsafe {
523 *vector.add(3) = value[3];
524 }
525 unsafe {
526 (*self.as_ptr()).tt = LUA_TVECTOR;
527 }
528 }
529
530 pub fn set_userdata_value(&self, value: Userdata) {
532 unsafe {
533 let raw = self.as_ptr().as_mut().unwrap_unchecked();
534 raw.value = RawValue {
535 gc: GcObject::from(value).as_ptr(),
536 };
537 raw.tt = LUA_TUSERDATA;
538 }
539 }
540
541 pub fn set_thread_value(&self, value: &Thread) {
543 unsafe {
544 let raw = self.as_ptr().as_mut().unwrap_unchecked();
545 raw.value = RawValue {
546 gc: GcObject::from(value).as_ptr(),
547 };
548 raw.tt = LUA_TTHREAD;
549 }
550 }
551
552 pub fn set_buffer_value(&self, value: Buffer) {
554 unsafe {
555 let raw = self.as_ptr().as_mut().unwrap_unchecked();
556 raw.value = RawValue {
557 gc: GcObject::from(value).as_ptr(),
558 };
559 raw.tt = LUA_TBUFFER;
560 }
561 }
562
563 pub fn set_closure_value(&self, value: Closure) {
565 unsafe {
566 let raw = self.as_ptr().as_mut().unwrap_unchecked();
567 raw.value = RawValue {
568 gc: GcObject::from(value).as_ptr(),
569 };
570 raw.tt = LUA_TFUNCTION;
571 }
572 }
573
574 pub fn set_table_value(&self, value: Table) {
576 unsafe {
577 let raw = self.as_ptr().as_mut().unwrap_unchecked();
578 raw.value = RawValue {
579 gc: GcObject::from(value).as_ptr(),
580 };
581 raw.tt = LUA_TTABLE;
582 }
583 }
584
585 pub fn set_proto_value(&self, value: Proto) {
587 unsafe {
588 let raw = self.as_ptr().as_mut().unwrap_unchecked();
589 raw.value = RawValue {
590 gc: GcObject::from(value).as_ptr(),
591 };
592 raw.tt = LUA_TPROTO;
593 }
594 }
595
596 pub fn set_upvalue_value(&self, value: UpVal) {
598 unsafe {
599 let raw = self.as_ptr().as_mut().unwrap_unchecked();
600 raw.value = RawValue {
601 gc: GcObject::from(value).as_ptr(),
602 };
603 raw.tt = LUA_TUPVALUE;
604 }
605 }
606
607 pub fn set_class_value(&self, value: Class) {
609 unsafe {
610 let raw = self.as_ptr().as_mut().unwrap_unchecked();
611 raw.value = RawValue {
612 gc: GcObject::from(value).as_ptr(),
613 };
614 raw.tt = LUA_TCLASS;
615 }
616 }
617
618 pub fn set_object_value(&self, value: Object) {
620 unsafe {
621 let raw = self.as_ptr().as_mut().unwrap_unchecked();
622 raw.value = RawValue {
623 gc: GcObject::from(value).as_ptr(),
624 };
625 raw.tt = LUA_TOBJECT;
626 }
627 }
628
629 pub fn set_obj(&self, other: impl Into<TValue>) {
631 let other = other.into();
632 unsafe {
633 core::ptr::copy(other.as_ptr(), self.as_ptr(), 1);
634 }
635 }
636
637 pub fn raw_equal(&self, other: impl Into<TValue>) -> bool {
639 let other = other.into();
640 if self.tt() != other.tt() {
641 return false;
642 }
643
644 match self.tt() {
645 x if x == LUA_TNIL => true,
646 x if x == LUA_TNUMBER => self.number_value() == other.number_value(),
647 x if x == LUA_TINTEGER => self.integer_value() == other.integer_value(),
648 x if x == LUA_TVECTOR => self.vector_value() == other.vector_value(),
649 x if x == LUA_TBOOLEAN => self.boolean_value() == other.boolean_value(),
650 x if x == LUA_TLIGHTUSERDATA => {
651 self.pointer_value() == other.pointer_value()
652 && self.light_userdata_tag() == other.light_userdata_tag()
653 }
654 _ => {
655 debug_assert!(self.is_collectable());
656 self.gc_value() == other.gc_value()
657 }
658 }
659 }
660}
661
662pub fn nil_object() -> TValue {
664 unsafe { TValue::from_ref(&LUA_O_NIL_OBJECT.0) }
665}
666impl crate::handle::sealed::Sealed for TValue {}
667impl RawHandle for TValue {
668 type Raw = RawTValue;
669
670 fn as_ptr(&self) -> *mut Self::Raw {
671 self.raw.as_ptr()
672 }
673}
674
675impl AsRef<TValue> for TValue {
676 fn as_ref(&self) -> &TValue {
677 self
678 }
679}