1use core::ptr;
2
3use luau_common::{BStr, ByteSlice, flags};
4
5use super::{
6 LUA_ENVIRON_INDEX, LUA_GLOBALS_INDEX, LUA_REGISTRY_INDEX, LUA_TNONE, LUAI_MAX_C_STACK, Thread,
7 is_pseudo,
8};
9use crate::buffer::BufferRuntime;
10use crate::call::{ProtectedCall, ThreadStack};
11use crate::debug::DebugRuntime;
12use crate::gc::{GcBarrier, GcRuntime};
13use crate::handle::RawHandle;
14use crate::handle::sealed::Sealed;
15use crate::state::ThreadState;
16use crate::string::{LuaString, StringFormatting, StringRuntime, TString};
17use crate::types::{
18 LUA_T_COUNT, LUA_TBOOLEAN, LUA_TBUFFER, LUA_TCLASS, LUA_TFUNCTION, LUA_TLIGHTUSERDATA,
19 LUA_TNIL, LUA_TNUMBER, LUA_TOBJECT, LUA_TSTRING, LUA_TTABLE, LUA_TTHREAD, LUA_TUSERDATA,
20 LUA_TVECTOR,
21};
22use crate::value::{RAW_TVALUE_NIL, TValue, TValueCursor, nil_object};
23use crate::vm::{VmConversions, VmOperations};
24use crate::{Class, Table, VmErrorResult, VmResult};
25
26#[allow(
35 clippy::missing_safety_doc,
36 reason = "all methods share the capability-level safety contract"
37)]
38pub trait RawStackAccess: Sealed {
39 unsafe fn to_object(&self, index: i32) -> Option<TValue>;
41
42 unsafe fn push_value_internal(&self, value: TValue) -> VmErrorResult;
44
45 unsafe fn push_table(&self, table: Table) -> VmErrorResult;
46
47 unsafe fn push_class(&self, class: Class) -> VmErrorResult;
49}
50
51impl RawStackAccess for Thread {
53 unsafe fn to_object(&self, index: i32) -> Option<TValue> {
55 let object = unsafe { self.index_to_addr(index) };
56 if object == nil_object() {
57 None
58 } else {
59 Some(object)
60 }
61 }
62
63 unsafe fn push_value_internal(&self, value: TValue) -> VmErrorResult {
65 unsafe {
66 self.ensure_stack(self, 1)?;
67 let top = self.stack_top();
68 top.value_unchecked().set_obj(value);
69 debug_assert!(top.offset_from(self.current_call_info().top()) < 0);
70 self.set_stack_top(top.add(1));
71 }
72 Ok(())
73 }
74
75 unsafe fn push_table(&self, table: Table) -> VmErrorResult {
76 unsafe {
77 self.ensure_stack(self, 1)?;
78 let top = self.stack_top();
79 top.value_unchecked().set_table_value(table);
80 debug_assert!(top.offset_from(self.current_call_info().top()) < 0);
81 self.set_stack_top(top.add(1));
82 }
83 Ok(())
84 }
85
86 unsafe fn push_class(&self, class: Class) -> VmErrorResult {
88 unsafe {
89 self.ensure_stack(self, 1)?;
90 let top = self.stack_top();
91 top.value_unchecked().set_class_value(class);
92 debug_assert!(top.offset_from(self.current_call_info().top()) < 0);
93 self.set_stack_top(top.add(1));
94 }
95 Ok(())
96 }
97}
98
99impl Thread {
100 unsafe fn pseudo_to_addr(&self, index: i32) -> TValue {
102 debug_assert!(is_pseudo(index));
103
104 unsafe {
105 let global = self.global();
106
107 match index {
108 LUA_REGISTRY_INDEX => global.registry(),
109 LUA_ENVIRON_INDEX => {
110 let pseudo_temp = global.pseudo_temp();
111 pseudo_temp.set_table_value(self.current_env());
112 pseudo_temp
113 }
114 LUA_GLOBALS_INDEX => {
115 let pseudo_temp = global.pseudo_temp();
116 pseudo_temp.set_table_value(self.globals());
117 pseudo_temp
118 }
119 _ => {
120 let closure = self.current_function();
121 let upvalue_index = (LUA_GLOBALS_INDEX - index) as usize;
122
123 if upvalue_index
124 <= closure.as_ptr().as_ref().unwrap_unchecked().n_upvalues as usize
125 {
126 closure.native_upvalue(upvalue_index - 1)
127 } else {
128 nil_object()
129 }
130 }
131 }
132 }
133 }
134
135 pub(crate) unsafe fn stack_index_cursor(&self, index: i32) -> Option<TValueCursor> {
136 debug_assert!(index != 0);
137
138 unsafe {
139 if index > 0 {
140 let object = self.stack_base().add((index - 1) as usize);
141 debug_assert!(
142 index
143 <= self
144 .current_call_info()
145 .top()
146 .offset_from(self.stack_base()) as i32
147 );
148 Some(object)
149 } else if index > LUA_REGISTRY_INDEX {
150 debug_assert!(-index <= self.stack_top().offset_from(self.stack_base()) as i32);
151 Some(self.stack_top().offset(index as isize))
152 } else {
153 None
154 }
155 }
156 }
157
158 pub(crate) unsafe fn stack_index_to_cursor(&self, index: i32) -> TValueCursor {
159 debug_assert!(!is_pseudo(index));
160 unsafe { self.stack_index_cursor(index).unwrap_unchecked() }
161 }
162
163 pub(crate) unsafe fn index_to_addr(&self, index: i32) -> TValue {
165 unsafe {
166 if let Some(object) = self.stack_index_cursor(index) {
167 if index > 0 && object.offset_from(self.stack_top()) >= 0 {
168 nil_object()
169 } else {
170 object.value_unchecked()
171 }
172 } else {
173 self.pseudo_to_addr(index)
174 }
175 }
176 }
177
178 pub(crate) unsafe fn ensure_stack(&self, error_thread: &Thread, size: i32) -> VmErrorResult {
180 unsafe {
181 let available = self.current_call_info().top().offset_from(self.stack_top()) as i32;
182 if flags::LuauAutoStack.get()
183 && size > 0
184 && size > available
185 && self.check_stack(size) == 0
186 {
187 return crate::run_error!(error_thread, "stack overflow");
188 }
189 }
190 Ok(())
191 }
192
193 pub unsafe fn abs_index(&self, index: i32) -> i32 {
195 unsafe {
196 debug_assert!(
197 (index > 0 && index <= self.get_top())
198 || (index < 0 && -index <= self.get_top())
199 || is_pseudo(index)
200 );
201 if index > 0 || is_pseudo(index) {
202 index
203 } else {
204 self.get_top() + index + 1
205 }
206 }
207 }
208
209 pub unsafe fn get_top(&self) -> i32 {
211 unsafe { self.stack_top().offset_from(self.stack_base()) as i32 }
212 }
213
214 pub unsafe fn check_stack(&self, size: i32) -> i32 {
216 debug_assert!(size >= 0);
217 unsafe {
218 let top_offset = self.stack_top().offset_from(self.stack_base()) as i32;
219 if size > LUAI_MAX_C_STACK || top_offset + size > LUAI_MAX_C_STACK {
220 return 0;
221 }
222
223 if size > 0 {
224 if self.stack_limit_reached(size) {
225 #[repr(C)]
226 struct GrowStackContext {
227 size: i32,
228 }
229
230 unsafe fn grow_stack_callback(
231 thread: &Thread,
232 context: &mut GrowStackContext,
233 ) -> VmResult {
234 unsafe { thread.grow_stack(context.size) }?;
235 Ok(())
236 }
237
238 let mut context = GrowStackContext { size };
239 if self
240 .raw_run_protected(grow_stack_callback, &mut context)
241 .is_err()
242 {
243 return 0;
244 }
245 }
246
247 let pointer = self.stack_top().add(size as usize);
248 self.expand_stack_limit(pointer);
249 }
250
251 1
252 }
253 }
254
255 pub unsafe fn raw_check_stack(&self, size: i32) -> VmErrorResult {
257 debug_assert!(size >= 0);
258 unsafe {
259 self.check_stack_internal(size)?;
260 let pointer = self.stack_top().add(size as usize);
261 self.expand_stack_limit(pointer);
262 }
263 Ok(())
264 }
265
266 pub unsafe fn set_top(&self, index: i32) -> VmErrorResult {
268 debug_assert!(index >= 0);
269 unsafe {
270 let base = self.stack_base();
271 let mut top = self.stack_top();
272 self.ensure_stack(self, index - top.offset_from(base) as i32)?;
273 debug_assert!(index <= self.stack_last().offset_from(base) as i32);
274 let target = base.add(index as usize);
275 while top < target {
276 top.value_unchecked().set_nil();
277 top = top.add(1);
278 }
279 self.set_stack_top(target);
280 }
281 Ok(())
282 }
283
284 pub unsafe fn restore_top(&self, top: i32) {
286 unsafe {
287 let current_top = self.get_top();
288 debug_assert!((0..=current_top).contains(&top));
289 self.set_stack_top(self.stack_base().add(top as usize));
290 }
291 }
292
293 pub unsafe fn pop(&self, count: i32) {
295 debug_assert!(count >= 0);
296 unsafe {
297 let current_top = self.get_top();
298 debug_assert!(count <= current_top);
299 self.restore_top(current_top - count);
300 }
301 }
302
303 pub unsafe fn push_value(&self, index: i32) -> VmErrorResult {
305 unsafe {
306 self.thread_barrier();
307 self.ensure_stack(self, 1)?;
308
309 let top = self.stack_top();
310 let object = self.index_to_addr(index);
311 top.value_unchecked().set_obj(object);
312 debug_assert!(top.offset_from(self.current_call_info().top()) < 0);
313 self.set_stack_top(top.add(1));
314 }
315 Ok(())
316 }
317
318 pub unsafe fn remove(&self, index: i32) {
320 unsafe {
321 let object_cursor = self.stack_index_to_cursor(index);
322 let next = object_cursor.add(1);
323 ptr::copy(
324 next.as_ptr(),
325 object_cursor.as_ptr(),
326 self.stack_top().offset_from(next) as usize,
327 );
328 self.set_stack_top(self.stack_top().sub(1));
329 }
330 }
331
332 pub unsafe fn insert(&self, index: i32) {
334 unsafe {
335 self.thread_barrier();
336
337 let object_cursor = self.stack_index_to_cursor(index);
338
339 let top = self.stack_top().as_ptr();
340 let mut slot = top;
341 while slot > object_cursor.as_ptr() {
342 ptr::copy(slot.sub(1), slot, 1);
343 slot = slot.sub(1);
344 }
345
346 ptr::copy(top, object_cursor.as_ptr(), 1);
347 }
348 }
349
350 pub unsafe fn replace(&self, index: i32) {
352 unsafe {
353 let top = self.stack_top();
354 debug_assert!(top.offset_from(self.stack_base()) > 0);
355
356 self.thread_barrier();
357
358 let object = self.index_to_addr(index);
359 debug_assert!(object != nil_object());
360
361 let value = top.sub(1);
362 if index == LUA_ENVIRON_INDEX {
363 debug_assert!(self.current_call_info() != self.base_call_info());
364 debug_assert!(value.value_unchecked().is_table());
365
366 let function = self.current_function();
367 function.set_env(value.value_unchecked().table_value());
368 self.barrier_value(function.into(), value.value_unchecked());
369 } else if index == LUA_GLOBALS_INDEX {
370 debug_assert!(value.value_unchecked().is_table());
371 self.set_globals(value.value_unchecked().table_value());
372 } else {
373 object.set_obj(value.value_unchecked());
374
375 if index < LUA_GLOBALS_INDEX {
376 let function = self.current_function();
377 self.barrier_value(function.into(), value.value_unchecked());
378 }
379 }
380
381 self.set_stack_top(top.sub(1));
382 }
383 }
384
385 pub unsafe fn x_move(&self, to: &Thread, count: i32) -> VmErrorResult {
387 unsafe {
388 debug_assert!(count >= 0);
389
390 if *self == *to {
391 return Ok(());
392 }
393
394 debug_assert!(count <= self.stack_top().offset_from(self.stack_base()) as i32);
395 debug_assert!(self.global() == to.global());
396
397 to.thread_barrier();
398 to.ensure_stack(self, count)?;
399
400 let to_top = to.stack_top();
401 let from_top = self.stack_top().sub(count as usize);
402 for index in 0..count as usize {
403 to_top
404 .add(index)
405 .value_unchecked()
406 .set_obj(from_top.add(index).value_unchecked());
407 }
408
409 self.set_stack_top(from_top);
410 to.set_stack_top(to_top.add(count as usize));
411 }
412 Ok(())
413 }
414
415 pub unsafe fn x_push(&self, to: &Thread, index: i32) -> VmErrorResult {
417 unsafe {
418 debug_assert!(self.global() == to.global());
419
420 to.thread_barrier();
421 to.ensure_stack(self, 1)?;
422
423 let top = to.stack_top();
424 let object = self.index_to_addr(index);
425 top.value_unchecked().set_obj(object);
426 debug_assert!(top < to.current_call_info().top());
427 to.set_stack_top(top.add(1));
428 }
429 Ok(())
430 }
431}
432
433impl Thread {
435 pub unsafe fn push_nil(&self) -> VmErrorResult {
437 unsafe {
438 self.ensure_stack(self, 1)?;
439 let top = self.stack_top();
440 debug_assert!(top < self.current_call_info().top());
441 top.value_unchecked().set_nil();
442 self.set_stack_top(top.add(1));
443 }
444 Ok(())
445 }
446
447 pub unsafe fn push_number(&self, value: f64) -> VmErrorResult {
449 unsafe {
450 self.ensure_stack(self, 1)?;
451 let top = self.stack_top();
452 debug_assert!(top < self.current_call_info().top());
453 top.value_unchecked().set_number(value);
454 self.set_stack_top(top.add(1));
455 }
456 Ok(())
457 }
458
459 pub unsafe fn push_integer(&self, value: i32) -> VmErrorResult {
461 unsafe {
462 self.ensure_stack(self, 1)?;
463 let top = self.stack_top();
464 debug_assert!(top < self.current_call_info().top());
465 top.value_unchecked().set_number(value as f64);
466 self.set_stack_top(top.add(1));
467 }
468 Ok(())
469 }
470
471 pub unsafe fn push_integer64(&self, value: i64) -> VmErrorResult {
473 unsafe {
474 self.ensure_stack(self, 1)?;
475 let top = self.stack_top();
476 debug_assert!(top < self.current_call_info().top());
477 top.value_unchecked().set_integer(value);
478 self.set_stack_top(top.add(1));
479 }
480 Ok(())
481 }
482
483 pub unsafe fn push_unsigned(&self, value: u32) -> VmErrorResult {
485 unsafe {
486 self.ensure_stack(self, 1)?;
487 let top = self.stack_top();
488 debug_assert!(top < self.current_call_info().top());
489 top.value_unchecked().set_number(value as f64);
490 self.set_stack_top(top.add(1));
491 }
492 Ok(())
493 }
494
495 pub unsafe fn push_vector(
497 &self,
498 components: [f32; crate::types::LUA_VECTOR_SIZE],
499 ) -> VmErrorResult {
500 unsafe {
501 self.ensure_stack(self, 1)?;
502 let top = self.stack_top();
503 debug_assert!(top < self.current_call_info().top());
504 top.value_unchecked().set_vector(components);
505 self.set_stack_top(top.add(1));
506 }
507 Ok(())
508 }
509
510 pub unsafe fn push_boolean(&self, value: i32) -> VmErrorResult {
512 unsafe {
513 self.ensure_stack(self, 1)?;
514 let top = self.stack_top();
515 debug_assert!(top < self.current_call_info().top());
516 top.value_unchecked().set_boolean(i32::from(value != 0));
517 self.set_stack_top(top.add(1));
518 }
519 Ok(())
520 }
521
522 pub unsafe fn push_light_userdata_tagged(&self, pointer: *mut (), tag: i32) -> VmErrorResult {
524 unsafe {
525 self.ensure_stack(self, 1)?;
526 let top = self.stack_top();
527 debug_assert!(top < self.current_call_info().top());
528 top.value_unchecked().set_light_userdata(pointer, tag);
529 self.set_stack_top(top.add(1));
530 }
531 Ok(())
532 }
533
534 pub unsafe fn push_light_userdata(&self, pointer: *mut ()) -> VmErrorResult {
536 unsafe { self.push_light_userdata_tagged(pointer, 0) }
537 }
538
539 pub unsafe fn push_string(&self, bytes: impl AsRef<[u8]>) -> VmErrorResult {
541 let bytes = bytes.as_ref();
542 unsafe {
543 self.check_gc()?;
544 self.thread_barrier();
545 self.ensure_stack(self, 1)?;
546
547 let interned = self.intern_string(bytes.as_bstr())?;
548 let top = self.stack_top();
549 top.value_unchecked().set_string_value(interned);
550 debug_assert!(top < self.current_call_info().top());
551 self.set_stack_top(top.add(1));
552 }
553 Ok(())
554 }
555
556 pub unsafe fn push_optional_string(&self, bytes: Option<impl AsRef<[u8]>>) -> VmErrorResult {
558 if let Some(bytes) = bytes {
559 unsafe { self.push_string(bytes) }
560 } else {
561 unsafe { self.push_nil() }
562 }
563 }
564
565 pub unsafe fn push_vfstring<'a>(
567 &self,
568 format: &str,
569 args: impl AsMut<[luau_printf::Arg<'a>]>,
570 ) -> VmErrorResult<LuaString> {
571 unsafe {
572 self.check_gc()?;
573 self.thread_barrier();
574 self.push_vfstring_internal(format, args)
575 }
576 }
577
578 pub unsafe fn push_fstring<'a>(
580 &self,
581 format: &str,
582 args: impl AsMut<[luau_printf::Arg<'a>]>,
583 ) -> VmErrorResult<LuaString> {
584 unsafe {
585 self.check_gc()?;
586 self.thread_barrier();
587 self.push_fstring_internal(format, args)
588 }
589 }
590}
591
592impl Thread {
594 unsafe fn borrow_interned_string(&self, string: TString) -> &BStr {
600 unsafe {
601 let raw = string.as_ptr().as_ref().unwrap_unchecked();
602 core::slice::from_raw_parts(string.data_ptr(), raw.len as usize).as_bstr()
603 }
604 }
605
606 pub unsafe fn is_number(&self, index: i32) -> i32 {
608 unsafe {
609 let object = self.index_to_addr(index);
610 let mut converted = RAW_TVALUE_NIL;
611 let converted = TValue::from_mut(&mut converted);
612 self.to_number_internal(object, converted).is_some() as i32
613 }
614 }
615
616 pub unsafe fn is_string(&self, index: i32) -> i32 {
618 let tag = unsafe { self.type_of(index) };
619 (tag == LUA_TSTRING || tag == LUA_TNUMBER) as i32
620 }
621
622 pub unsafe fn is_light_userdata(&self, index: i32) -> i32 {
624 (unsafe { self.type_of(index) } == LUA_TLIGHTUSERDATA) as i32
625 }
626
627 pub unsafe fn is_function(&self, index: i32) -> i32 {
629 (unsafe { self.type_of(index) } == LUA_TFUNCTION) as i32
630 }
631
632 pub unsafe fn is_table(&self, index: i32) -> i32 {
634 (unsafe { self.type_of(index) } == LUA_TTABLE) as i32
635 }
636
637 pub unsafe fn is_nil(&self, index: i32) -> i32 {
639 (unsafe { self.type_of(index) } == LUA_TNIL) as i32
640 }
641
642 pub unsafe fn is_boolean(&self, index: i32) -> i32 {
644 (unsafe { self.type_of(index) } == LUA_TBOOLEAN) as i32
645 }
646
647 pub unsafe fn is_vector(&self, index: i32) -> i32 {
649 (unsafe { self.type_of(index) } == LUA_TVECTOR) as i32
650 }
651
652 pub unsafe fn is_thread(&self, index: i32) -> i32 {
654 (unsafe { self.type_of(index) } == LUA_TTHREAD) as i32
655 }
656
657 pub unsafe fn is_buffer(&self, index: i32) -> i32 {
659 (unsafe { self.type_of(index) } == LUA_TBUFFER) as i32
660 }
661
662 pub unsafe fn is_none(&self, index: i32) -> i32 {
664 (unsafe { self.type_of(index) } == LUA_TNONE) as i32
665 }
666
667 pub unsafe fn is_none_or_nil(&self, index: i32) -> i32 {
669 (unsafe { self.type_of(index) } <= LUA_TNIL) as i32
670 }
671
672 pub unsafe fn is_class(&self, index: i32) -> i32 {
674 (unsafe { self.type_of(index) } == LUA_TCLASS) as i32
675 }
676
677 pub unsafe fn is_object(&self, index: i32) -> i32 {
679 (unsafe { self.type_of(index) } == LUA_TOBJECT) as i32
680 }
681
682 pub unsafe fn is_integer64(&self, index: i32) -> i32 {
684 let object = unsafe { self.index_to_addr(index) };
685 (object != nil_object() && object.is_integer()) as i32
686 }
687
688 pub unsafe fn is_native_function(&self, index: i32) -> i32 {
690 let object = unsafe { self.index_to_addr(index) };
691 (object != nil_object()
692 && object.is_function()
693 && unsafe { object.closure_value().is_native() }) as i32
694 }
695
696 pub unsafe fn is_lua_function(&self, index: i32) -> i32 {
698 let object = unsafe { self.index_to_addr(index) };
699 (object != nil_object()
700 && object.is_function()
701 && unsafe { object.closure_value().is_lua() }) as i32
702 }
703
704 pub unsafe fn is_userdata(&self, index: i32) -> i32 {
706 let object = unsafe { self.index_to_addr(index) };
707 (object != nil_object() && (object.is_userdata() || object.is_light_userdata())) as i32
708 }
709
710 pub unsafe fn type_of(&self, index: i32) -> i32 {
712 let object = unsafe { self.index_to_addr(index) };
713 if object == nil_object() {
714 LUA_TNONE
715 } else {
716 object.tt()
717 }
718 }
719
720 pub unsafe fn type_name(&self, tag: i32) -> LuaString {
722 debug_assert!((LUA_TNONE..LUA_T_COUNT as i32).contains(&tag));
723
724 if tag == LUA_TNONE {
725 LuaString::from_static(b"no value".as_bstr())
726 } else {
727 LuaString::from_interned(unsafe { self.global().type_name(tag as usize) })
728 }
729 }
730
731 pub unsafe fn equal(&self, left: i32, right: i32) -> VmResult<i32> {
733 unsafe {
734 let left_object = self.index_to_addr(left);
735 let right_object = self.index_to_addr(right);
736
737 if left_object == nil_object()
738 || right_object == nil_object()
739 || left_object.tt() != right_object.tt()
740 {
741 Ok(0)
742 } else {
743 self.equal_value(left_object, right_object)
744 }
745 }
746 }
747
748 pub unsafe fn raw_equal(&self, left: i32, right: i32) -> i32 {
750 let left_object = unsafe { self.index_to_addr(left) };
751 let right_object = unsafe { self.index_to_addr(right) };
752
753 if left_object == nil_object() || right_object == nil_object() {
754 0
755 } else {
756 left_object.raw_equal(right_object) as i32
757 }
758 }
759
760 pub unsafe fn less_than(&self, left: i32, right: i32) -> VmResult<i32> {
762 unsafe {
763 let left_object = self.index_to_addr(left);
764 let right_object = self.index_to_addr(right);
765
766 if left_object == nil_object() || right_object == nil_object() {
767 Ok(0)
768 } else {
769 self.less_than_internal(left_object, right_object)
770 }
771 }
772 }
773
774 pub unsafe fn to_number(&self, index: i32) -> Option<f64> {
776 unsafe {
777 let object = self.index_to_addr(index);
778 let mut converted = RAW_TVALUE_NIL;
779 let converted = TValue::from_mut(&mut converted);
780 self.to_number_internal(object, converted)
781 .map(|value| value.number_value())
782 }
783 }
784
785 pub unsafe fn to_integer(&self, index: i32) -> Option<i32> {
787 unsafe {
788 let object = self.index_to_addr(index);
789 let mut converted = RAW_TVALUE_NIL;
790 let converted = TValue::from_mut(&mut converted);
791 self.to_number_internal(object, converted)
792 .map(|value| value.number_value())
793 .map(crate::number::num_to_int)
794 }
795 }
796
797 pub unsafe fn to_unsigned(&self, index: i32) -> Option<u32> {
799 unsafe {
800 let object = self.index_to_addr(index);
801 let mut converted = RAW_TVALUE_NIL;
802 let converted = TValue::from_mut(&mut converted);
803 self.to_number_internal(object, converted)
804 .map(|value| value.number_value())
805 .map(crate::number::num_to_unsigned)
806 }
807 }
808
809 pub unsafe fn to_vector(&self, index: i32) -> Option<[f32; crate::types::LUA_VECTOR_SIZE]> {
811 let object = unsafe { self.index_to_addr(index) };
812 if object == nil_object() || !object.is_vector() {
813 None
814 } else {
815 Some(object.vector_value())
816 }
817 }
818
819 pub unsafe fn to_boolean(&self, index: i32) -> i32 {
821 let object = unsafe { self.index_to_addr(index) };
822 (!object.is_false()) as i32
823 }
824
825 pub unsafe fn to_integer64(&self, index: i32) -> Option<i64> {
827 unsafe {
828 let object = self.index_to_addr(index);
829
830 if object != nil_object() && object.is_integer() {
831 Some(object.integer_value())
832 } else {
833 None
834 }
835 }
836 }
837
838 pub unsafe fn to_string(&self, index: i32) -> VmErrorResult<Option<&BStr>> {
840 unsafe {
841 let mut object = self.index_to_addr(index);
842 if !object.is_string() {
843 self.thread_barrier();
844 if self.to_string_internal(object)? == 0 {
845 return Ok(None);
846 }
847
848 self.check_gc()?;
849 object = self.index_to_addr(index);
850 }
851
852 Ok(Some(self.borrow_interned_string(object.string_value())))
853 }
854 }
855
856 pub unsafe fn to_string_atom(&self, index: i32) -> Option<(&BStr, i32)> {
858 unsafe {
859 let object = self.index_to_addr(index);
860 if object == nil_object() || !object.is_string() {
861 return None;
862 }
863
864 let string = object.string_value();
865 self.update_atom(string);
866
867 Some((
868 self.borrow_interned_string(string),
869 string.as_ptr().as_ref().unwrap_unchecked().atom as i32,
870 ))
871 }
872 }
873
874 pub unsafe fn namecall_atom(&self) -> Option<(&BStr, i32)> {
876 unsafe {
877 let string = self.name_call()?;
878
879 self.update_atom(string);
880
881 Some((
882 self.borrow_interned_string(string),
883 string.as_ptr().as_ref().unwrap_unchecked().atom as i32,
884 ))
885 }
886 }
887
888 pub unsafe fn len(&self, index: i32) -> VmResult<f64> {
890 unsafe {
891 self.ensure_stack(self, 1)?;
892 let value = self.index_to_addr(index);
893 let result = self.stack_top();
894 self.do_len(result, value)?;
895 debug_assert!(result < self.current_call_info().top());
896 self.set_stack_top(result.add(1));
897 Ok(result.value_unchecked().number_value())
898 }
899 }
900
901 pub unsafe fn obj_len(&self, index: i32) -> i32 {
903 unsafe {
904 let object = self.index_to_addr(index);
905 if object == nil_object() {
906 return 0;
907 }
908
909 match object.tt() {
910 x if x == LUA_TSTRING => {
911 object
912 .string_value()
913 .as_ptr()
914 .as_ref()
915 .unwrap_unchecked()
916 .len as i32
917 }
918 x if x == LUA_TUSERDATA => {
919 object
920 .userdata_value()
921 .as_ptr()
922 .as_ref()
923 .unwrap_unchecked()
924 .len
925 }
926 x if x == LUA_TBUFFER => {
927 object
928 .buffer_value()
929 .as_ptr()
930 .as_ref()
931 .unwrap_unchecked()
932 .len as i32
933 }
934 x if x == LUA_TTABLE => object.table_value().getn(),
935 _ => 0,
936 }
937 }
938 }
939
940 pub unsafe fn to_pointer(&self, index: i32) -> *const () {
942 let object = unsafe { self.index_to_addr(index) };
943 if object == nil_object() {
944 return ptr::null();
945 }
946
947 match object.tt() {
948 LUA_TUSERDATA => object.userdata_value().data_ptr().cast(),
949 LUA_TLIGHTUSERDATA => object.pointer_value(),
950 _ if object.is_collectable() => object.gc_value().as_ptr().cast(),
951 _ => ptr::null(),
952 }
953 }
954}
955
956impl Thread {
958 pub unsafe fn new_buffer(&self, size: usize) -> VmErrorResult<*mut u8> {
960 unsafe {
961 self.check_gc()?;
962 self.thread_barrier();
963 self.ensure_stack(self, 1)?;
964
965 let buffer = self.new_buffer_internal(size)?;
966 let data = buffer.data_mut_ptr();
967 let top = self.stack_top();
968 top.value_unchecked().set_buffer_value(buffer);
969 debug_assert!(top < self.current_call_info().top());
970 self.set_stack_top(top.add(1));
971
972 Ok(data)
973 }
974 }
975
976 pub unsafe fn to_buffer(&self, index: i32) -> Option<(*mut u8, usize)> {
978 let object = unsafe { self.index_to_addr(index) };
979 if object == nil_object() || !object.is_buffer() {
980 return None;
981 }
982
983 let buffer = object.buffer_value();
984 Some((unsafe { buffer.data_mut_ptr() }, unsafe {
985 buffer.as_ptr().as_ref().unwrap_unchecked().len as usize
986 }))
987 }
988}