1pub mod chunk_serializer;
4pub mod lua_convert;
5mod lua_string;
6mod lua_table;
7mod lua_value;
8pub mod userdata_builder;
9pub mod userdata_trait;
10
11use self::lua_value::Value;
12use std::any::Any;
13use std::fmt;
14
15pub use lua_string::*;
16pub use userdata_builder::UserDataBuilder;
17pub use userdata_trait::{UserDataTrait, lua_value_to_udvalue, udvalue_to_lua_value};
18
19pub use lua_table::LuaTable;
21pub use lua_value::{BIT_ISCOLLECTABLE, LUA_VNUMFLT, LUA_VNUMINT};
22pub use lua_value::{LuaValue, LuaValueKind};
23
24use crate::gc::{ProtoPtr, TablePtr, UpvaluePtr};
25use crate::lua_vm::CFunction;
26use crate::{Instruction, RefUserData};
27
28#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
29pub struct LuaValuePtr {
30 pub ptr: *mut LuaValue,
31}
32
33pub struct LuaUpvalue {
42 v: *mut LuaValue,
45 closed_value: LuaValue,
47 stack_index: usize,
49}
50
51impl LuaUpvalue {
52 #[inline(always)]
55 pub fn new_open(stack_index: usize, stack_ptr: LuaValuePtr) -> Self {
56 LuaUpvalue {
57 v: stack_ptr.ptr,
58 closed_value: LuaValue::nil(),
59 stack_index,
60 }
61 }
62
63 #[inline(always)]
67 pub fn new_closed(value: LuaValue) -> Self {
68 LuaUpvalue {
69 v: std::ptr::null_mut(),
70 closed_value: value,
71 stack_index: 0,
72 }
73 }
74
75 #[inline(always)]
79 pub fn fix_closed_ptr(&mut self) {
80 if self.v.is_null() {
81 self.v = &mut self.closed_value as *mut LuaValue;
82 }
83 }
84
85 #[inline(always)]
88 pub fn is_open(&self) -> bool {
89 !std::ptr::eq(self.v, &self.closed_value)
90 }
91
92 #[inline(always)]
94 pub fn get_stack_index(&self) -> usize {
95 self.stack_index
96 }
97
98 #[inline(always)]
101 pub fn close(&mut self, stack_value: LuaValue) {
102 self.closed_value = stack_value;
103 self.v = &mut self.closed_value as *mut LuaValue;
104 }
105
106 #[inline(always)]
108 pub fn update_stack_ptr(&mut self, ptr: *mut LuaValue) {
109 self.v = ptr;
110 }
111
112 #[inline(always)]
114 pub fn get_v_ptr(&self) -> *mut LuaValue {
115 self.v
116 }
117
118 #[inline(always)]
120 pub fn get_value(&self) -> LuaValue {
121 debug_assert!(!self.v.is_null(), "upvalue get_value: null pointer");
122 debug_assert!(
123 (self.v as usize) > 0x10000,
124 "upvalue get_value: suspiciously low pointer {:p} (stack_index={})",
125 self.v,
126 self.stack_index
127 );
128 let val = unsafe { *self.v };
129 debug_assert!(
130 Self::is_valid_tt(val.tt()),
131 "upvalue get_value: INVALID type tag 0x{:02X} read from {:p} (stack_index={}, is_open={}). Likely dangling pointer!",
132 val.tt(),
133 self.v,
134 self.stack_index,
135 self.is_open()
136 );
137 val
138 }
139
140 #[inline(always)]
142 pub fn get_value_ref(&self) -> &LuaValue {
143 debug_assert!(!self.v.is_null(), "upvalue get_value_ref: null pointer");
144 unsafe { &*self.v }
145 }
146
147 #[inline(always)]
149 pub fn set_value(&mut self, val: LuaValue) {
150 debug_assert!(!self.v.is_null(), "upvalue set_value: null pointer");
151 debug_assert!(
152 (self.v as usize) > 0x10000,
153 "upvalue set_value: suspiciously low pointer {:p} (stack_index={})",
154 self.v,
155 self.stack_index
156 );
157 unsafe { *self.v = val }
158 }
159
160 #[inline(always)]
162 pub fn set_value_parts(&mut self, value: Value, tt: u8) {
163 debug_assert!(!self.v.is_null(), "upvalue set_value_parts: null pointer");
164 debug_assert!(
165 (self.v as usize) > 0x10000,
166 "upvalue set_value_parts: suspiciously low pointer {:p} (stack_index={})",
167 self.v,
168 self.stack_index
169 );
170 unsafe {
171 (*self.v).value = value;
172 (*self.v).tt = tt;
173 }
174 }
175
176 fn is_valid_tt(tt: u8) -> bool {
178 use crate::lua_value::lua_value::*;
179 matches!(
180 tt,
181 LUA_VNIL
182 | LUA_VEMPTY
183 | LUA_VABSTKEY
184 | LUA_VFALSE
185 | LUA_VTRUE
186 | LUA_VNUMINT
187 | LUA_VNUMFLT
188 | LUA_VSHRSTR
189 | LUA_VLNGSTR
190 | LUA_VTABLE
191 | LUA_VFUNCTION
192 | LUA_CCLOSURE
193 | LUA_VLCF
194 | LUA_VLIGHTUSERDATA
195 | LUA_VUSERDATA
196 | LUA_VTHREAD
197 )
198 }
199
200 pub fn get_closed_value(&self) -> Option<&LuaValue> {
201 if !self.is_open() {
202 Some(&self.closed_value)
203 } else {
204 None
205 }
206 }
207}
208
209pub struct LuaUserdata {
214 data: Box<dyn UserDataTrait>,
215 metatable: TablePtr,
216}
217
218impl LuaUserdata {
219 pub fn new<T: UserDataTrait>(data: T) -> Self {
221 LuaUserdata {
222 data: Box::new(data),
223 metatable: TablePtr::null(),
224 }
225 }
226
227 pub fn from_boxed(data: Box<dyn UserDataTrait>) -> Self {
232 LuaUserdata {
233 data,
234 metatable: TablePtr::null(),
235 }
236 }
237
238 #[inline]
247 pub unsafe fn from_ref<T: UserDataTrait>(reference: &mut T) -> Self {
248 LuaUserdata {
249 data: Box::new(unsafe { RefUserData::new(reference) }),
250 metatable: TablePtr::null(),
251 }
252 }
253
254 #[inline]
260 pub unsafe fn from_raw_ptr<T: UserDataTrait>(ptr: *mut T) -> Self {
261 LuaUserdata {
262 data: Box::new(unsafe { RefUserData::from_raw(ptr) }),
263 metatable: TablePtr::null(),
264 }
265 }
266
267 pub fn with_metatable<T: UserDataTrait>(data: T, metatable: TablePtr) -> Self {
269 LuaUserdata {
270 data: Box::new(data),
271 metatable,
272 }
273 }
274
275 #[inline]
279 pub fn get_trait(&self) -> &dyn UserDataTrait {
280 self.data.as_ref()
281 }
282
283 #[inline]
285 pub fn get_trait_mut(&mut self) -> &mut dyn UserDataTrait {
286 self.data.as_mut()
287 }
288
289 #[inline]
291 pub fn type_name(&self) -> &'static str {
292 self.data.type_name()
293 }
294
295 #[inline]
299 pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
300 self.data.as_any().downcast_ref::<T>()
301 }
302
303 #[inline]
305 pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
306 self.data.as_any_mut().downcast_mut::<T>()
307 }
308
309 pub fn get_data(&self) -> &dyn Any {
311 self.data.as_any()
312 }
313
314 pub fn get_data_mut(&mut self) -> &mut dyn Any {
316 self.data.as_any_mut()
317 }
318
319 pub fn get_metatable(&self) -> Option<LuaValue> {
322 if self.metatable.is_null() {
323 None
324 } else {
325 Some(LuaValue::table(self.metatable))
326 }
327 }
328
329 pub(crate) fn set_metatable(&mut self, metatable: LuaValue) {
330 if let Some(table_ptr) = metatable.as_table_ptr() {
331 self.metatable = table_ptr;
332 } else if metatable.is_nil() {
333 self.metatable = TablePtr::null();
334 } else {
335 debug_assert!(
336 false,
337 "Attempted to set userdata metatable to non-table, non-nil value"
338 );
339 }
340 }
341}
342
343impl fmt::Debug for LuaUserdata {
344 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
345 write!(
346 f,
347 "Userdata({}@{:p})",
348 self.data.type_name(),
349 self.data.as_any() as *const dyn Any
350 )
351 }
352}
353
354#[derive(Debug, Clone)]
356pub struct UpvalueDesc {
357 pub name: String, pub is_local: bool, pub index: u32, }
361
362#[derive(Debug, Clone)]
364pub struct LocVar {
365 pub name: String, pub startpc: u32, pub endpc: u32, }
369
370#[derive(Debug, Clone)]
372pub struct LuaProto {
373 pub code: Vec<Instruction>,
374 pub constants: Vec<LuaValue>,
375 pub locals: Vec<LocVar>,
376 pub upvalue_count: usize,
377 pub param_count: usize,
378 pub is_vararg: bool, pub needs_vararg_table: bool, pub use_hidden_vararg: bool, pub max_stack_size: usize,
382 pub child_protos: Vec<ProtoPtr>, pub upvalue_descs: Vec<UpvalueDesc>, pub source_name: Option<String>, pub line_info: Vec<u32>, pub linedefined: usize, pub lastlinedefined: usize, pub proto_data_size: u32, }
390
391impl Default for LuaProto {
392 fn default() -> Self {
393 Self::new()
394 }
395}
396
397impl LuaProto {
398 pub fn new() -> Self {
399 LuaProto {
400 code: Vec::new(),
401 constants: Vec::new(),
402 locals: Vec::new(),
403 upvalue_count: 0,
404 param_count: 0,
405 is_vararg: false,
406 needs_vararg_table: false,
407 use_hidden_vararg: false,
408 max_stack_size: 0,
409 child_protos: Vec::new(),
410 upvalue_descs: Vec::new(),
411 source_name: None,
412 line_info: Vec::new(),
413 linedefined: 0,
414 lastlinedefined: 0,
415 proto_data_size: 0,
416 }
417 }
418
419 pub fn compute_proto_data_size(&mut self) {
421 use std::mem::size_of;
422 let instr_size = self.code.len() * size_of::<crate::lua_vm::Instruction>();
423 let const_size = self.constants.len() * size_of::<LuaValue>();
424 let child_size = self.child_protos.len() * size_of::<ProtoPtr>();
425 let line_size = self.line_info.len() * size_of::<u32>();
426 self.proto_data_size = (instr_size + const_size + child_size + line_size) as u32;
427 }
428
429 #[cfg(feature = "shared-proto")]
430 pub fn share_constant_strings(&mut self) -> usize {
431 let mut shared_count = 0;
432
433 for constant in &mut self.constants {
434 shared_count += usize::from(crate::gc::share_lua_value(constant));
435 }
436
437 shared_count
438 }
439
440 #[cfg(feature = "shared-proto")]
441 pub fn share_proto_strings(&mut self) -> usize {
442 let mut shared_count = self.share_constant_strings();
443
444 for child in &mut self.child_protos {
445 shared_count += child.as_mut_ref().data.share_proto_strings();
446 }
447
448 shared_count
449 }
450}
451
452pub enum UpvalueStore {
456 Empty,
457 One(UpvaluePtr),
458 Many(Box<[UpvaluePtr]>),
459}
460
461impl UpvalueStore {
462 #[inline(always)]
463 pub fn from_single(ptr: UpvaluePtr) -> Self {
464 UpvalueStore::One(ptr)
465 }
466
467 #[inline(always)]
468 pub fn from_vec(v: Vec<UpvaluePtr>) -> Self {
469 match v.len() {
470 0 => UpvalueStore::Empty,
471 1 => UpvalueStore::One(v[0]),
472 _ => UpvalueStore::Many(v.into_boxed_slice()),
473 }
474 }
475
476 #[inline(always)]
477 pub fn as_slice(&self) -> &[UpvaluePtr] {
478 match self {
479 UpvalueStore::Empty => &[],
480 UpvalueStore::One(p) => std::slice::from_ref(p),
481 UpvalueStore::Many(b) => b,
482 }
483 }
484
485 #[inline(always)]
486 pub fn as_mut_slice(&mut self) -> &mut [UpvaluePtr] {
487 match self {
488 UpvalueStore::Empty => &mut [],
489 UpvalueStore::One(p) => std::slice::from_mut(p),
490 UpvalueStore::Many(b) => b,
491 }
492 }
493
494 #[inline(always)]
495 pub fn len(&self) -> usize {
496 match self {
497 UpvalueStore::Empty => 0,
498 UpvalueStore::One(_) => 1,
499 UpvalueStore::Many(b) => b.len(),
500 }
501 }
502}
503
504pub struct LuaFunction {
505 chunk: ProtoPtr,
506 upvalue_store: UpvalueStore,
507}
508
509impl LuaFunction {
510 pub fn new(chunk: ProtoPtr, upvalue_store: UpvalueStore) -> Self {
511 LuaFunction {
512 chunk,
513 upvalue_store,
514 }
515 }
516
517 #[inline(always)]
519 pub fn chunk(&self) -> &LuaProto {
520 &self.chunk.as_ref().data
521 }
522
523 #[inline(always)]
524 pub fn proto(&self) -> ProtoPtr {
525 self.chunk
526 }
527
528 #[inline(always)]
530 pub fn upvalues(&self) -> &[UpvaluePtr] {
531 self.upvalue_store.as_slice()
532 }
533
534 #[inline(always)]
536 pub fn upvalues_mut(&mut self) -> &mut [UpvaluePtr] {
537 self.upvalue_store.as_mut_slice()
538 }
539}
540
541pub struct CClosureFunction {
542 func: CFunction,
543 upvalues: Vec<LuaValue>,
544}
545
546impl CClosureFunction {
547 pub fn new(func: CFunction, upvalues: Vec<LuaValue>) -> Self {
548 CClosureFunction { func, upvalues }
549 }
550
551 #[inline(always)]
553 pub fn func(&self) -> CFunction {
554 self.func
555 }
556
557 #[inline(always)]
559 pub fn upvalues(&self) -> &Vec<LuaValue> {
560 &self.upvalues
561 }
562
563 #[inline(always)]
565 pub fn upvalues_mut(&mut self) -> &mut Vec<LuaValue> {
566 &mut self.upvalues
567 }
568}
569
570pub type RustCallback = Box<dyn Fn(&mut crate::lua_vm::LuaState) -> crate::LuaResult<usize>>;
572
573pub struct RClosureFunction {
577 func: RustCallback,
578 upvalues: Vec<LuaValue>,
579}
580
581impl RClosureFunction {
582 pub fn new(func: RustCallback, upvalues: Vec<LuaValue>) -> Self {
583 RClosureFunction { func, upvalues }
584 }
585
586 #[inline(always)]
588 pub fn call(&self, state: &mut crate::lua_vm::LuaState) -> crate::LuaResult<usize> {
589 (self.func)(state)
590 }
591
592 #[inline(always)]
594 pub fn upvalues(&self) -> &Vec<LuaValue> {
595 &self.upvalues
596 }
597
598 #[inline(always)]
600 pub fn upvalues_mut(&mut self) -> &mut Vec<LuaValue> {
601 &mut self.upvalues
602 }
603}
604
605#[cfg(test)]
606mod value_tests {
607 use super::*;
608
609 #[test]
610 fn test_integer_float_distinction() {
611 let int_val = LuaValue::integer(42);
612 let float_val = LuaValue::number(42.0);
613
614 assert!(int_val.is_integer());
615 assert!(!int_val.is_float());
616 assert!(!float_val.is_integer()); assert!(float_val.is_float());
618
619 assert!(int_val.is_number());
621 assert!(float_val.is_number());
622 }
623
624 #[test]
625 fn test_integer_float_conversion() {
626 let int_val = LuaValue::integer(42);
627 let float_val = LuaValue::number(42.5);
628
629 assert_eq!(int_val.as_float(), Some(42.0));
631
632 assert_eq!(float_val.as_integer(), None);
634
635 let exact_float = LuaValue::number(42.0);
637 assert_eq!(exact_float.as_integer(), Some(42));
638 }
639
640 #[test]
641 fn test_as_number_unified() {
642 let int_val = LuaValue::integer(42);
643 let float_val = LuaValue::number(3.15);
644
645 assert_eq!(int_val.as_number(), Some(42.0));
647 assert_eq!(float_val.as_number(), Some(3.15));
648 }
649}