1use std::cell::{Cell, RefCell};
24
25use crate::closure::LuaClosure;
26use crate::error::LuaError;
27use crate::gc::GcRef;
28use crate::string::LuaString;
29use crate::value::LuaValue;
30
31const MAXABITS: u32 = (std::mem::size_of::<i32>() as u32) * 8 - 1;
35
36pub const MAXASIZE: u32 = 1u32 << MAXABITS;
38
39pub const MAXHBITS: u32 = MAXABITS - 1;
41
42const MAXHSIZE: u32 = 1u32 << MAXHBITS;
44
45const DUMMY_TABLE_INIT_HASH_NODES: u32 = 4;
51
52const BIT_RAS: u8 = 1 << 7;
54
55pub const ARRAY_GROW_CAP: u32 = 1u32 << 20;
63
64pub const TOTAL_GROW_CAP: usize = 1usize << 24;
77
78const WEAK_KEYS: u8 = 1 << 0;
79const WEAK_VALUES: u8 = 1 << 1;
80
81#[derive(Clone, Copy, Debug, Default)]
86pub struct TableFlags(pub u8);
87
88impl TableFlags {
89 #[inline]
91 pub fn is_real_asize(self) -> bool {
92 (self.0 & BIT_RAS) == 0
93 }
94
95 #[inline]
97 pub fn set_real_asize(&mut self) {
98 self.0 &= !BIT_RAS;
99 }
100
101 #[inline]
103 pub fn set_no_real_asize(&mut self) {
104 self.0 |= BIT_RAS;
105 }
106
107 #[inline]
109 pub fn invalidate_tm_cache(&mut self) {
110 const MASK_FLAGS: u8 = 0x7F;
111 self.0 &= !MASK_FLAGS;
112 }
113}
114
115pub struct TableNode {
121 pub value: LuaValue,
123 pub key: LuaValue,
125 pub next: i32,
127}
128
129impl TableNode {
130 fn empty() -> Self {
131 TableNode {
132 value: LuaValue::Nil,
133 key: LuaValue::Nil,
134 next: 0,
135 }
136 }
137
138 fn key_is_nil(&self) -> bool {
139 matches!(self.key, LuaValue::Nil)
140 }
141 fn key_is_int(&self) -> bool {
142 matches!(self.key, LuaValue::Int(_))
143 }
144 fn key_int(&self) -> i64 {
145 if let LuaValue::Int(i) = self.key {
146 i
147 } else {
148 panic!("TableNode::key_int: key is not int")
149 }
150 }
151 fn key_is_short_str(&self) -> bool {
152 if let LuaValue::Str(s) = &self.key {
153 s.is_short()
154 } else {
155 false
156 }
157 }
158 fn key_string(&self) -> &GcRef<LuaString> {
159 if let LuaValue::Str(s) = &self.key {
160 s
161 } else {
162 panic!("TableNode::key_string: key is not a string")
163 }
164 }
165 fn key_value(&self) -> LuaValue {
166 self.key.clone()
167 }
168 fn set_key(&mut self, k: &LuaValue) {
169 self.key = k.clone();
170 }
171}
172
173#[inline]
174fn lua_string_content_eq(a: &GcRef<LuaString>, b: &GcRef<LuaString>) -> bool {
175 GcRef::ptr_eq(a, b) || (a.hash() == b.hash() && a.as_bytes() == b.as_bytes())
176}
177
178#[derive(Debug, Clone, Copy)]
185pub enum TableSlotRef {
186 Array(usize),
188 Hash(usize),
190 Absent,
192}
193
194fn ceil_log2(x: u32) -> i32 {
198 static LOG_2: [u8; 256] = [
199 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
200 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
201 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
202 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
203 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
204 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
205 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
206 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
207 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
208 ];
209 let mut l: i32 = 0;
210 let mut x = x.wrapping_sub(1);
211 while x >= 256 {
212 l += 8;
213 x >>= 8;
214 }
215 l + LOG_2[x as usize] as i32
216}
217
218fn hash_float(n: f64) -> i32 {
226 if n.is_nan() || n.is_infinite() {
227 return 0;
228 }
229 let (mantissa, exp) = frexp(n);
230 let scaled = mantissa * -(i32::MIN as f64);
231 let ni = scaled as i64;
232 if ni as f64 != scaled {
233 return 0;
234 }
235 let u = (exp as u32).wrapping_add(ni as u32);
236 if u <= i32::MAX as u32 {
237 u as i32
238 } else {
239 !(u as i32)
240 }
241}
242
243fn frexp(x: f64) -> (f64, i32) {
245 if x == 0.0 || x.is_nan() || x.is_infinite() {
246 return (x, 0);
247 }
248 let bits = x.to_bits();
249 let exp_bits = ((bits >> 52) & 0x7FFu64) as i32;
250 if exp_bits == 0 {
251 let scaled = x * (2.0f64.powi(64));
252 let (m, e) = frexp(scaled);
253 return (m, e - 64);
254 }
255 let exp = exp_bits - 1022;
256 let mantissa_bits = (bits & !(0x7FFu64 << 52)) | (0x3FEu64 << 52);
257 (f64::from_bits(mantissa_bits), exp)
258}
259
260pub struct TableInner {
267 pub flags: TableFlags,
268 pub lsizenode: u8,
269 pub alimit: u32,
270 pub array: Vec<LuaValue>,
271 pub node: Vec<TableNode>,
272 pub lastfree: Option<usize>,
273}
274
275impl TableInner {
276 fn new() -> Self {
277 TableInner {
278 flags: TableFlags(0x7F),
279 lsizenode: 0,
280 alimit: 0,
281 array: Vec::new(),
282 node: Vec::new(),
283 lastfree: None,
284 }
285 }
286
287 #[inline]
289 fn is_dummy(&self) -> bool {
290 self.lastfree.is_none()
291 }
292
293 #[inline]
295 fn sizenode(&self) -> u32 {
296 1u32 << self.lsizenode
297 }
298
299 #[inline]
301 fn alloc_sizenode(&self) -> u32 {
302 if self.is_dummy() {
303 0
304 } else {
305 self.sizenode()
306 }
307 }
308
309 #[inline]
311 fn is_real_asize(&self) -> bool {
312 self.flags.is_real_asize()
313 }
314
315 #[inline]
317 fn is_pow2(x: u32) -> bool {
318 x == 0 || x.is_power_of_two()
319 }
320
321 fn real_asize(&self) -> u32 {
323 if self.limit_equals_asize() {
324 return self.alimit;
325 }
326 let mut size = self.alimit;
327 size |= size >> 1;
328 size |= size >> 2;
329 size |= size >> 4;
330 size |= size >> 8;
331 size |= size >> 16;
332 size = size.wrapping_add(1);
333 debug_assert!(Self::is_pow2(size) && size / 2 < self.alimit && self.alimit < size);
334 size
335 }
336
337 #[inline]
338 fn limit_equals_asize(&self) -> bool {
339 self.is_real_asize() || Self::is_pow2(self.alimit)
340 }
341
342 fn is_pow2_real_asize(&self) -> bool {
343 !self.is_real_asize() || Self::is_pow2(self.alimit)
344 }
345
346 fn set_limit_to_size(&mut self) -> u32 {
347 self.alimit = self.real_asize();
348 self.flags.set_real_asize();
349 self.alimit
350 }
351
352 fn hash_idx_for_int(&self, i: i64) -> usize {
355 let ui = i as u64;
356 let sn = self.sizenode() as usize;
357 let modulo = (sn - 1) | 1;
358 if ui <= i32::MAX as u64 {
359 (ui as usize) % modulo
360 } else {
361 (ui as usize) % modulo
362 }
363 }
364
365 #[inline]
366 fn hashpow2_idx(&self, h: u32) -> usize {
367 (h & (self.sizenode() - 1)) as usize
368 }
369
370 #[inline]
371 fn hashmod_idx(&self, h: usize) -> usize {
372 let sn = self.sizenode() as usize;
373 let modulo = (sn - 1) | 1;
374 h % modulo
375 }
376
377 fn main_position(&self, key: &LuaValue) -> usize {
378 match key {
379 LuaValue::Int(i) => self.hash_idx_for_int(*i),
380 LuaValue::Float(f) => {
381 let h = hash_float(*f);
382 self.hashmod_idx(h as usize)
383 }
384 LuaValue::Str(s) if s.is_short() => self.hashpow2_idx(s.hash()),
385 LuaValue::Str(s) => self.hashpow2_idx(s.hash()),
386 LuaValue::Bool(false) => self.hashpow2_idx(0),
387 LuaValue::Bool(true) => self.hashpow2_idx(1),
388 LuaValue::LightUserData(p) => {
389 let h = (*p as usize as u32) as usize;
390 self.hashmod_idx(h)
391 }
392 LuaValue::Function(LuaClosure::LightC(f)) => {
393 let h = (*f as u32) as usize;
394 self.hashmod_idx(h)
395 }
396 LuaValue::Table(t) => {
397 let h = (GcRef::identity(t) as u32) as usize;
398 self.hashmod_idx(h)
399 }
400 LuaValue::Function(LuaClosure::Lua(cl)) => {
401 let h = (GcRef::identity(cl) as u32) as usize;
402 self.hashmod_idx(h)
403 }
404 LuaValue::Function(LuaClosure::C(cl)) => {
405 let h = (GcRef::identity(cl) as u32) as usize;
406 self.hashmod_idx(h)
407 }
408 LuaValue::UserData(u) => {
409 let h = (GcRef::identity(u) as u32) as usize;
410 self.hashmod_idx(h)
411 }
412 LuaValue::Thread(th) => {
413 let h = (GcRef::identity(th) as u32) as usize;
414 self.hashmod_idx(h)
415 }
416 LuaValue::Nil => 0,
417 }
418 }
419
420 fn main_position_from_node(&self, nd: usize) -> usize {
421 let key = self.node[nd].key_value();
422 self.main_position(&key)
423 }
424
425 fn equal_key(k1: &LuaValue, n2: &TableNode) -> bool {
428 let types_match = std::mem::discriminant(k1) == std::mem::discriminant(&n2.key);
429 if !types_match {
430 return false;
431 }
432 match &n2.key {
433 LuaValue::Nil => true,
434 LuaValue::Bool(b) => matches!(k1, LuaValue::Bool(b2) if b == b2),
435 LuaValue::Int(ni) => matches!(k1, LuaValue::Int(ki) if ki == ni),
436 LuaValue::Float(nf) => matches!(k1, LuaValue::Float(kf) if kf == nf),
437 LuaValue::LightUserData(np) => matches!(k1, LuaValue::LightUserData(kp) if kp == np),
438 LuaValue::Function(LuaClosure::LightC(nf)) => {
439 matches!(k1, LuaValue::Function(LuaClosure::LightC(kf)) if kf == nf)
440 }
441 LuaValue::Str(ns) if ns.is_long() => {
442 if let LuaValue::Str(ks) = k1 {
443 lua_string_content_eq(ks, ns)
444 } else {
445 false
446 }
447 }
448 _ => Self::gc_ptr_eq(k1, &n2.key),
449 }
450 }
451
452 fn gc_ptr_eq(a: &LuaValue, b: &LuaValue) -> bool {
453 match (a, b) {
454 (LuaValue::Str(sa), LuaValue::Str(sb)) => GcRef::ptr_eq(sa, sb),
455 (LuaValue::Table(ta), LuaValue::Table(tb)) => GcRef::ptr_eq(ta, tb),
456 (LuaValue::Function(LuaClosure::Lua(fa)), LuaValue::Function(LuaClosure::Lua(fb))) => {
457 GcRef::ptr_eq(fa, fb)
458 }
459 (LuaValue::Function(LuaClosure::C(fa)), LuaValue::Function(LuaClosure::C(fb))) => {
460 GcRef::ptr_eq(fa, fb)
461 }
462 (LuaValue::UserData(ua), LuaValue::UserData(ub)) => GcRef::ptr_eq(ua, ub),
463 (LuaValue::Thread(ta), LuaValue::Thread(tb)) => GcRef::ptr_eq(ta, tb),
464 _ => false,
465 }
466 }
467
468 fn get_generic_slot(&self, key: &LuaValue) -> TableSlotRef {
471 if self.is_dummy() {
472 return TableSlotRef::Absent;
473 }
474 let mut n = self.main_position(key);
475 loop {
476 if Self::equal_key(key, &self.node[n]) {
477 return TableSlotRef::Hash(n);
478 }
479 let nx = self.node[n].next;
480 if nx == 0 {
481 return TableSlotRef::Absent;
482 }
483 n = (n as isize + nx as isize) as usize;
484 }
485 }
486
487 fn array_index(k: i64) -> u32 {
490 let uk = k as u64;
491 if uk.wrapping_sub(1) < MAXASIZE as u64 {
492 k as u32
493 } else {
494 0
495 }
496 }
497
498 fn find_index(&self, key: &LuaValue, asize: u32) -> Result<u32, LuaError> {
502 if matches!(key, LuaValue::Nil) {
503 return Ok(0);
504 }
505 let i = if let LuaValue::Int(k) = key {
506 Self::array_index(*k)
507 } else {
508 0
509 };
510 if i.wrapping_sub(1) < asize {
511 return Ok(i);
512 }
513 let slot = self.get_generic_slot(key);
514 match slot {
515 TableSlotRef::Absent => Err(LuaError::runtime(format_args!("invalid key to 'next'"))),
516 TableSlotRef::Hash(node_idx) => Ok((node_idx as u32 + 1) + asize),
517 TableSlotRef::Array(_) => unreachable!("getgeneric returned Array slot"),
518 }
519 }
520
521 fn next_pair(&self, key: &LuaValue) -> Result<Option<(LuaValue, LuaValue)>, LuaError> {
524 let asize = self.real_asize();
525 let i = self.find_index(key, asize)?;
526 let mut i = i as usize;
527 while i < asize as usize {
528 if !matches!(self.array[i], LuaValue::Nil) {
529 return Ok(Some((LuaValue::Int((i + 1) as i64), self.array[i].clone())));
530 }
531 i += 1;
532 }
533 let mut hi = i.saturating_sub(asize as usize);
534 while hi < self.node.len() {
535 if !matches!(self.node[hi].value, LuaValue::Nil) {
536 return Ok(Some((
537 self.node[hi].key_value(),
538 self.node[hi].value.clone(),
539 )));
540 }
541 hi += 1;
542 }
543 Ok(None)
544 }
545
546 fn compute_sizes(nums: &[u32], pna: &mut u32) -> u32 {
549 let mut twotoi: u32 = 1;
550 let mut a: u32 = 0;
551 let mut na: u32 = 0;
552 let mut optimal: u32 = 0;
553 for i in 0..nums.len() {
554 if twotoi == 0 || *pna <= twotoi / 2 {
555 break;
556 }
557 a += nums[i];
558 if a > twotoi / 2 {
559 optimal = twotoi;
560 na = a;
561 }
562 twotoi = twotoi.wrapping_mul(2);
563 }
564 debug_assert!(optimal == 0 || optimal / 2 < na && na <= optimal);
565 *pna = na;
566 optimal
567 }
568
569 fn count_int(key: i64, nums: &mut [u32]) -> bool {
570 let k = Self::array_index(key);
571 if k != 0 {
572 nums[ceil_log2(k) as usize] += 1;
573 true
574 } else {
575 false
576 }
577 }
578
579 fn num_use_array(&self, nums: &mut [u32]) -> u32 {
580 debug_assert!(
581 self.is_real_asize(),
582 "numusearray: alimit must be real size"
583 );
584 let asize = self.alimit as usize;
585 let mut ause: u32 = 0;
586 let mut i: usize = 1;
587 let mut ttlg: usize = 1;
588 for lg in 0..=(MAXABITS as usize) {
589 let mut lc: u32 = 0;
590 let lim = if ttlg > asize { asize } else { ttlg };
591 if i > lim {
592 break;
593 }
594 while i <= lim {
595 if !matches!(self.array[i - 1], LuaValue::Nil) {
596 lc += 1;
597 }
598 i += 1;
599 }
600 nums[lg] += lc;
601 ause += lc;
602 ttlg = ttlg.saturating_mul(2);
603 }
604 ause
605 }
606
607 fn num_use_hash(&self, nums: &mut [u32], pna: &mut u32) -> i32 {
608 let mut totaluse: i32 = 0;
609 let mut ause: u32 = 0;
610 let mut i = self.node.len();
611 while i > 0 {
612 i -= 1;
613 let n = &self.node[i];
614 if !matches!(n.value, LuaValue::Nil) {
615 if n.key_is_int() {
616 if Self::count_int(n.key_int(), nums) {
617 ause += 1;
618 }
619 }
620 totaluse += 1;
621 }
622 }
623 *pna += ause;
624 totaluse
625 }
626
627 fn set_node_vector(&mut self, size: u32) -> Result<(), LuaError> {
628 if size == 0 {
629 self.node = Vec::new();
630 self.lsizenode = 0;
631 self.lastfree = None;
632 } else {
633 let lsize = ceil_log2(size);
634 if lsize as u32 > MAXHBITS || (1u32 << lsize) > MAXHSIZE {
635 return Err(LuaError::runtime(format_args!("table overflow")));
636 }
637 let actual_size = 1u32 << lsize;
638 let mut nodes = Vec::with_capacity(actual_size as usize);
639 for _ in 0..actual_size {
640 nodes.push(TableNode::empty());
641 }
642 self.node = nodes;
643 self.lsizenode = lsize as u8;
644 self.lastfree = Some(actual_size as usize);
645 }
646 Ok(())
647 }
648
649 fn reinsert(&mut self, old_nodes: Vec<(LuaValue, LuaValue)>) -> Result<(), LuaError> {
650 for (k, v) in old_nodes {
651 self.set(&k, v)?;
652 }
653 Ok(())
654 }
655
656 fn resize(&mut self, new_asize: u32, nhsize: u32) -> Result<(), LuaError> {
658 let old_asize = self.set_limit_to_size();
659
660 let (mut new_hash_node, mut new_hash_lsize, mut new_hash_lastfree) = {
661 let mut tmp = TableInner::new();
662 tmp.set_node_vector(nhsize)?;
663 (tmp.node, tmp.lsizenode, tmp.lastfree)
664 };
665
666 if new_asize < old_asize {
667 let migrate_end = (old_asize as usize).min(self.array.len());
668 let detached: Vec<(i64, LuaValue)> = ((new_asize as usize)..migrate_end)
669 .filter(|&i| !matches!(self.array[i], LuaValue::Nil))
670 .map(|i| ((i + 1) as i64, self.array[i].clone()))
671 .collect();
672 self.array.truncate(new_asize as usize);
673 self.alimit = new_asize;
674
675 std::mem::swap(&mut self.node, &mut new_hash_node);
676 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
677 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
678
679 for (key, v) in detached {
680 self.set_int(key, v)?;
681 }
682
683 self.alimit = old_asize;
684 std::mem::swap(&mut self.node, &mut new_hash_node);
685 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
686 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
687 }
688
689 self.array.resize_with(new_asize as usize, || LuaValue::Nil);
690
691 std::mem::swap(&mut self.node, &mut new_hash_node);
692 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
693 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
694 self.alimit = new_asize;
695
696 let old_hash_entries: Vec<(LuaValue, LuaValue)> = new_hash_node
697 .iter()
698 .filter(|n| !matches!(n.value, LuaValue::Nil))
699 .map(|n| (n.key_value(), n.value.clone()))
700 .collect();
701 drop(new_hash_node);
702 self.reinsert(old_hash_entries)?;
703
704 Ok(())
705 }
706
707 fn rehash(&mut self, extra_key: &LuaValue) -> Result<(), LuaError> {
708 let mut nums = [0u32; MAXABITS as usize + 1];
709 self.set_limit_to_size();
710
711 let na = self.num_use_array(&mut nums);
712 let mut na = na;
713 let mut totaluse = na as i32;
714
715 totaluse += self.num_use_hash(&mut nums, &mut na);
716
717 if let LuaValue::Int(ek) = extra_key {
718 if Self::count_int(*ek, &mut nums) {
719 na += 1;
720 }
721 }
722 totaluse += 1;
723
724 let asize = Self::compute_sizes(&nums, &mut na);
725
726 let nh = (totaluse - na as i32).max(0) as u32;
727 self.resize(asize, nh)
728 }
729
730 fn get_free_pos(&mut self) -> Option<usize> {
731 if self.is_dummy() {
732 return None;
733 }
734 loop {
735 let lf = self.lastfree?;
736 if lf == 0 {
737 self.lastfree = None;
738 return None;
739 }
740 let idx = lf - 1;
741 self.lastfree = Some(idx);
742 if self.node[idx].key_is_nil() {
743 return Some(idx);
744 }
745 }
746 }
747
748 fn find_chain_predecessor(&self, idx: usize) -> Option<usize> {
749 self.node
750 .iter()
751 .enumerate()
752 .find(|(prev, node)| {
753 node.next != 0 && (*prev as isize + node.next as isize) == idx as isize
754 })
755 .map(|(prev, _)| prev)
756 }
757
758 fn clear_node(&mut self, idx: usize) {
759 self.node[idx].key = LuaValue::Nil;
760 self.node[idx].value = LuaValue::Nil;
761 self.node[idx].next = 0;
762 }
763
764 fn remove_hash_node(&mut self, idx: usize) {
765 if let Some(prev) = self.find_chain_predecessor(idx) {
766 let next = self.node[idx].next;
767 self.node[prev].next = if next == 0 {
768 0
769 } else {
770 let target = idx as isize + next as isize;
771 (target - prev as isize) as i32
772 };
773 self.clear_node(idx);
774 return;
775 }
776
777 let next = self.node[idx].next;
778 if next == 0 {
779 self.clear_node(idx);
780 return;
781 }
782
783 let next_idx = (idx as isize + next as isize) as usize;
784 let moved_next = self.node[next_idx].next;
785 let moved_key = self.node[next_idx].key_value();
786 let moved_value = self.node[next_idx].value.clone();
787 self.node[idx].key = moved_key;
788 self.node[idx].value = moved_value;
789 self.node[idx].next = if moved_next == 0 {
790 0
791 } else {
792 let target = next_idx as isize + moved_next as isize;
793 (target - idx as isize) as i32
794 };
795 self.clear_node(next_idx);
796 }
797
798 fn clear_dead_hash_node(&mut self, idx: usize) {
799 self.remove_hash_node(idx);
800 }
801
802 fn new_key(&mut self, key: &LuaValue, value: LuaValue) -> Result<(), LuaError> {
803 if matches!(key, LuaValue::Nil) {
804 return Err(LuaError::runtime(format_args!("table index is nil")));
805 }
806 let normalised_key;
807 let key = if let LuaValue::Float(f) = key {
808 let f = *f;
809 if f.is_nan() {
810 return Err(LuaError::runtime(format_args!("table index is NaN")));
811 }
812 let k = f as i64;
813 if k as f64 == f {
814 normalised_key = LuaValue::Int(k);
815 &normalised_key
816 } else {
817 key
818 }
819 } else {
820 key
821 };
822
823 if matches!(value, LuaValue::Nil) {
824 return Ok(());
825 }
826
827 if self.is_dummy() && !matches!(key, LuaValue::Int(_)) {
828 self.set_node_vector(DUMMY_TABLE_INIT_HASH_NODES)?;
829 let mp = self.main_position(key);
830 self.node[mp].set_key(key);
831 self.node[mp].value = value;
832 return Ok(());
833 }
834
835 let mp = self.main_position(key);
836 let mp_occupied = self.is_dummy() || !matches!(self.node[mp].value, LuaValue::Nil);
837 if mp_occupied {
838 let f = self.get_free_pos();
839 let f = match f {
840 None => {
841 self.rehash(key)?;
842 return self.set(key, value);
843 }
844 Some(idx) => idx,
845 };
846
847 debug_assert!(!self.is_dummy());
848 let othern = self.main_position_from_node(mp);
849
850 if othern != mp {
851 let mut prev = othern;
852 while (prev as isize + self.node[prev].next as isize) as usize != mp {
853 prev = (prev as isize + self.node[prev].next as isize) as usize;
854 }
855 self.node[prev].next = (f as isize - prev as isize) as i32;
856 let mp_key = self.node[mp].key_value();
857 let mp_val = self.node[mp].value.clone();
858 let mp_next = self.node[mp].next;
859 self.node[f].key = mp_key;
860 self.node[f].value = mp_val;
861 if mp_next != 0 {
862 self.node[f].next = mp_next + (mp as isize - f as isize) as i32;
863 self.node[mp].next = 0;
864 } else {
865 self.node[f].next = 0;
866 }
867 self.node[mp].value = LuaValue::Nil;
868 } else {
869 if self.node[mp].next != 0 {
870 let target = (mp as isize + self.node[mp].next as isize) as usize;
871 self.node[f].next = (target as isize - f as isize) as i32;
872 } else {
873 debug_assert!(self.node[f].next == 0);
874 }
875 self.node[mp].next = (f as isize - mp as isize) as i32;
876 self.node[f].set_key(key);
877 debug_assert!(matches!(self.node[f].value, LuaValue::Nil));
878 self.node[f].value = value;
879 return Ok(());
880 }
881 }
882 self.node[mp].set_key(key);
883 debug_assert!(matches!(self.node[mp].value, LuaValue::Nil));
884 self.node[mp].value = value;
885 Ok(())
886 }
887
888 fn get_int_slot(&self, key: i64) -> TableSlotRef {
889 let alimit = self.alimit as u64;
890 let uk = key as u64;
891 if uk.wrapping_sub(1) < alimit {
892 return TableSlotRef::Array((key - 1) as usize);
893 }
894 if !self.is_real_asize() && alimit > 0 {
895 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
896 if masked < alimit {
897 return TableSlotRef::Array((key - 1) as usize);
898 }
899 }
900 if self.is_dummy() {
901 return TableSlotRef::Absent;
902 }
903 let mut n = self.hash_idx_for_int(key);
904 loop {
905 if self.node[n].key_is_int() && self.node[n].key_int() == key {
906 return TableSlotRef::Hash(n);
907 }
908 let nx = self.node[n].next;
909 if nx == 0 {
910 break;
911 }
912 n = (n as isize + nx as isize) as usize;
913 }
914 TableSlotRef::Absent
915 }
916
917 #[inline]
924 fn get_int_value(&self, key: i64) -> LuaValue {
925 let alimit = self.alimit as u64;
926 let uk = key as u64;
927 if uk.wrapping_sub(1) < alimit {
928 return self.array[(key - 1) as usize].clone();
929 }
930 self.get_int_value_cold(key)
931 }
932
933 #[cold]
934 #[inline(never)]
935 fn get_int_value_cold(&self, key: i64) -> LuaValue {
936 let alimit = self.alimit as u64;
937 let uk = key as u64;
938 if !self.is_real_asize() && alimit > 0 {
939 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
940 if masked < alimit {
941 return self.array[(key - 1) as usize].clone();
942 }
943 }
944 if self.is_dummy() {
945 return LuaValue::Nil;
946 }
947 let mut n = self.hash_idx_for_int(key);
948 loop {
949 if self.node[n].key_is_int() && self.node[n].key_int() == key {
950 return self.node[n].value.clone();
951 }
952 let nx = self.node[n].next;
953 if nx == 0 {
954 break;
955 }
956 n = (n as isize + nx as isize) as usize;
957 }
958 LuaValue::Nil
959 }
960
961 #[inline(always)]
962 fn get_short_str_slot(&self, key: &GcRef<LuaString>) -> TableSlotRef {
963 debug_assert!(key.is_short());
964 if self.is_dummy() {
965 return TableSlotRef::Absent;
966 }
967 let mut n = self.hashpow2_idx(key.hash());
968 loop {
969 if self.node[n].key_is_short_str() {
970 let ks = self.node[n].key_string();
971 if lua_string_content_eq(ks, key) {
972 return TableSlotRef::Hash(n);
973 }
974 }
975 let nx = self.node[n].next;
976 if nx == 0 {
977 return TableSlotRef::Absent;
978 }
979 n = (n as isize + nx as isize) as usize;
980 }
981 }
982
983 #[inline(always)]
984 fn try_update_short_str(
985 &mut self,
986 key: &GcRef<LuaString>,
987 value: LuaValue,
988 ) -> Result<(), LuaValue> {
989 debug_assert!(key.is_short());
990 if self.is_dummy() {
991 return Err(value);
992 }
993 let mut n = self.hashpow2_idx(key.hash());
994 loop {
995 if self.node[n].key_is_short_str() {
996 let ks = self.node[n].key_string();
997 if lua_string_content_eq(ks, key) {
998 self.node[n].value = value;
999 return Ok(());
1000 }
1001 }
1002 let nx = self.node[n].next;
1003 if nx == 0 {
1004 return Err(value);
1005 }
1006 n = (n as isize + nx as isize) as usize;
1007 }
1008 }
1009
1010 #[inline(always)]
1011 fn try_update_int(&mut self, key: i64, value: LuaValue) -> Result<(), LuaValue> {
1012 let alimit = self.alimit as u64;
1013 let uk = key as u64;
1014 if uk.wrapping_sub(1) < alimit {
1015 self.array[(key - 1) as usize] = value;
1016 return Ok(());
1017 }
1018 if !self.is_real_asize() && alimit > 0 {
1019 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
1020 if masked < alimit {
1021 self.array[(key - 1) as usize] = value;
1022 return Ok(());
1023 }
1024 }
1025 if !self.is_dummy() {
1026 let mut n = self.hash_idx_for_int(key);
1027 loop {
1028 if self.node[n].key_is_int() && self.node[n].key_int() == key {
1029 self.node[n].value = value;
1030 return Ok(());
1031 }
1032 let nx = self.node[n].next;
1033 if nx == 0 {
1034 break;
1035 }
1036 n = (n as isize + nx as isize) as usize;
1037 }
1038 }
1039 Err(value)
1040 }
1041
1042 #[inline]
1050 fn get_str_value(&self, key: &GcRef<LuaString>) -> LuaValue {
1051 debug_assert!(key.is_short());
1052 if self.is_dummy() {
1053 return LuaValue::Nil;
1054 }
1055 let mut n = self.hashpow2_idx(key.hash());
1056 loop {
1057 if self.node[n].key_is_short_str() {
1058 let ks = self.node[n].key_string();
1059 if lua_string_content_eq(ks, key) {
1060 return self.node[n].value.clone();
1061 }
1062 }
1063 let nx = self.node[n].next;
1064 if nx == 0 {
1065 return LuaValue::Nil;
1066 }
1067 n = (n as isize + nx as isize) as usize;
1068 }
1069 }
1070
1071 #[cold]
1076 #[inline(never)]
1077 fn get_generic_value(&self, key: &LuaValue) -> LuaValue {
1078 let slot = self.get_slot(key);
1079 self.slot_value(slot)
1080 }
1081
1082 fn get_str_slot(&self, key: &GcRef<LuaString>) -> TableSlotRef {
1083 if key.is_short() {
1084 self.get_short_str_slot(key)
1085 } else {
1086 let ko = LuaValue::Str(key.clone());
1087 self.get_generic_slot(&ko)
1088 }
1089 }
1090
1091 fn get_slot(&self, key: &LuaValue) -> TableSlotRef {
1092 match key {
1093 LuaValue::Str(s) if s.is_short() => self.get_short_str_slot(s),
1094 LuaValue::Int(i) => self.get_int_slot(*i),
1095 LuaValue::Nil => TableSlotRef::Absent,
1096 LuaValue::Float(f) => {
1097 let f = *f;
1098 let k = f as i64;
1099 if k as f64 == f {
1100 self.get_int_slot(k)
1101 } else {
1102 self.get_generic_slot(key)
1103 }
1104 }
1105 _ => self.get_generic_slot(key),
1106 }
1107 }
1108
1109 fn slot_value(&self, slot: TableSlotRef) -> LuaValue {
1110 match slot {
1111 TableSlotRef::Array(i) => self.array[i].clone(),
1112 TableSlotRef::Hash(i) => self.node[i].value.clone(),
1113 TableSlotRef::Absent => LuaValue::Nil,
1114 }
1115 }
1116
1117 fn finish_set(
1118 &mut self,
1119 key: &LuaValue,
1120 slot: TableSlotRef,
1121 value: LuaValue,
1122 ) -> Result<(), LuaError> {
1123 match slot {
1124 TableSlotRef::Absent => self.new_key(key, value),
1125 TableSlotRef::Array(i) => {
1126 self.array[i] = value;
1127 Ok(())
1128 }
1129 TableSlotRef::Hash(i) => {
1130 self.node[i].value = value;
1131 Ok(())
1132 }
1133 }
1134 }
1135
1136 fn set(&mut self, key: &LuaValue, value: LuaValue) -> Result<(), LuaError> {
1137 let slot = self.get_slot(key);
1138 self.finish_set(key, slot, value)
1139 }
1140
1141 fn set_int(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1145 let slot = self.get_int_slot(key);
1146 if matches!(slot, TableSlotRef::Absent) {
1147 if key > 0 && (key as u64) <= ARRAY_GROW_CAP as u64 {
1148 let cur = self.alimit as i64;
1149 if key == cur + 1 && !matches!(value, LuaValue::Nil) {
1150 let new_size = (key as u32).next_power_of_two().max(4);
1151 let capped = new_size.min(ARRAY_GROW_CAP);
1152 if capped > self.alimit {
1153 let nsize = self.alloc_sizenode();
1154 self.resize(capped, nsize)?;
1155 let new_slot = self.get_int_slot(key);
1156 return self.finish_set(&LuaValue::Int(key), new_slot, value);
1157 }
1158 }
1159 }
1160 }
1161 match slot {
1162 TableSlotRef::Absent => {
1163 let k = LuaValue::Int(key);
1164 self.new_key(&k, value)
1165 }
1166 TableSlotRef::Array(i) => {
1167 self.array[i] = value;
1168 Ok(())
1169 }
1170 TableSlotRef::Hash(i) => {
1171 self.node[i].value = value;
1172 Ok(())
1173 }
1174 }
1175 }
1176
1177 #[inline]
1184 fn try_raw_set_int_fast(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1185 let alimit = self.alimit as u64;
1186 let uk = key as u64;
1187 if uk.wrapping_sub(1) < alimit {
1188 self.array[(key - 1) as usize] = value;
1189 return Ok(());
1190 }
1191 self.try_raw_set_int_cold(key, value)
1192 }
1193
1194 #[cold]
1195 #[inline(never)]
1196 fn try_raw_set_int_cold(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1197 if self.array.len() + self.node.len() >= TOTAL_GROW_CAP
1198 && matches!(self.get_int_slot(key), TableSlotRef::Absent)
1199 {
1200 return Err(LuaError::Memory);
1201 }
1202 self.set_int_value_cold(key, value)
1203 }
1204
1205 #[cold]
1212 #[inline(never)]
1213 fn set_int_value_cold(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1214 let alimit = self.alimit as u64;
1215 let uk = key as u64;
1216 if !self.is_real_asize() && alimit > 0 {
1217 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
1218 if masked < alimit {
1219 self.array[(key - 1) as usize] = value;
1220 return Ok(());
1221 }
1222 }
1223 if !self.is_dummy() {
1224 let mut n = self.hash_idx_for_int(key);
1225 loop {
1226 if self.node[n].key_is_int() && self.node[n].key_int() == key {
1227 self.node[n].value = value;
1228 return Ok(());
1229 }
1230 let nx = self.node[n].next;
1231 if nx == 0 {
1232 break;
1233 }
1234 n = (n as isize + nx as isize) as usize;
1235 }
1236 }
1237 if key > 0 && (key as u64) <= ARRAY_GROW_CAP as u64 {
1238 let cur = self.alimit as i64;
1239 if key == cur + 1 && !matches!(value, LuaValue::Nil) {
1240 let new_size = (key as u32).next_power_of_two().max(4);
1241 let capped = new_size.min(ARRAY_GROW_CAP);
1242 if capped > self.alimit {
1243 let nsize = self.alloc_sizenode();
1244 self.resize(capped, nsize)?;
1245 let new_slot = self.get_int_slot(key);
1246 return self.finish_set(&LuaValue::Int(key), new_slot, value);
1247 }
1248 }
1249 }
1250 let k = LuaValue::Int(key);
1251 self.new_key(&k, value)
1252 }
1253
1254 fn hash_search(&self, mut j: u64) -> u64 {
1257 let mut i: u64;
1258 if j == 0 {
1259 j = 1;
1260 }
1261 loop {
1262 i = j;
1263 if j <= (i64::MAX as u64) / 2 {
1264 j *= 2;
1265 } else {
1266 j = i64::MAX as u64;
1267 let s = self.get_int_slot(j as i64);
1268 if matches!(s, TableSlotRef::Absent) || matches!(self.slot_value(s), LuaValue::Nil)
1269 {
1270 break;
1271 } else {
1272 return j;
1273 }
1274 }
1275 let s = self.get_int_slot(j as i64);
1276 if matches!(s, TableSlotRef::Absent) {
1277 break;
1278 }
1279 if matches!(self.slot_value(s), LuaValue::Nil) {
1280 break;
1281 }
1282 }
1283 while j - i > 1 {
1284 let m = i / 2 + j / 2;
1285 let s = self.get_int_slot(m as i64);
1286 let empty =
1287 matches!(s, TableSlotRef::Absent) || matches!(self.slot_value(s), LuaValue::Nil);
1288 if empty {
1289 j = m;
1290 } else {
1291 i = m;
1292 }
1293 }
1294 i
1295 }
1296
1297 fn bin_search(array: &[LuaValue], mut i: u32, mut j: u32) -> u32 {
1298 while j - i > 1 {
1299 let m = (i + j) / 2;
1300 if matches!(array[(m - 1) as usize], LuaValue::Nil) {
1301 j = m;
1302 } else {
1303 i = m;
1304 }
1305 }
1306 i
1307 }
1308
1309 fn getn(&mut self) -> u64 {
1312 let limit = self.alimit;
1313 if limit > 0 && matches!(self.array[(limit - 1) as usize], LuaValue::Nil) {
1314 if limit >= 2 && !matches!(self.array[(limit - 2) as usize], LuaValue::Nil) {
1315 if self.is_pow2_real_asize() && !Self::is_pow2(limit - 1) {
1316 self.alimit = limit - 1;
1317 self.flags.set_no_real_asize();
1318 }
1319 return (limit - 1) as u64;
1320 } else {
1321 let boundary = Self::bin_search(&self.array, 0, limit);
1322 if self.is_pow2_real_asize() && boundary > self.real_asize() / 2 {
1323 self.alimit = boundary;
1324 self.flags.set_no_real_asize();
1325 }
1326 return boundary as u64;
1327 }
1328 }
1329 if !self.limit_equals_asize() {
1330 if matches!(self.array[limit as usize], LuaValue::Nil) {
1331 return limit as u64;
1332 }
1333 let real = self.real_asize();
1334 if matches!(self.array[(real - 1) as usize], LuaValue::Nil) {
1335 let old_alimit = self.alimit;
1336 let boundary = Self::bin_search(&self.array, old_alimit, real);
1337 self.alimit = boundary;
1338 return boundary as u64;
1339 }
1340 }
1341 let limit = self.real_asize();
1342 debug_assert!(
1343 limit == self.real_asize()
1344 && (limit == 0 || !matches!(self.array[(limit - 1) as usize], LuaValue::Nil))
1345 );
1346 let next_key = (limit as i64).saturating_add(1);
1347 let next_slot = self.get_int_slot(next_key);
1348 let next_empty = matches!(next_slot, TableSlotRef::Absent)
1349 || matches!(self.slot_value(next_slot), LuaValue::Nil);
1350 if self.is_dummy() || next_empty {
1351 return limit as u64;
1352 }
1353 self.hash_search(limit as u64)
1354 }
1355}
1356
1357#[derive(Debug)]
1365pub struct LuaTable {
1366 inner: RefCell<TableInner>,
1367 metatable: RefCell<Option<GcRef<LuaTable>>>,
1368 has_metatable: Cell<bool>,
1369 weak_mode: Cell<u8>,
1370}
1371
1372impl std::fmt::Debug for TableInner {
1373 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1374 f.debug_struct("TableInner")
1375 .field("alimit", &self.alimit)
1376 .field("array_len", &self.array.len())
1377 .field("node_len", &self.node.len())
1378 .finish()
1379 }
1380}
1381
1382impl Default for LuaTable {
1383 fn default() -> Self {
1384 LuaTable {
1385 inner: RefCell::new(TableInner::new()),
1386 metatable: RefCell::new(None),
1387 has_metatable: Cell::new(false),
1388 weak_mode: Cell::new(0),
1389 }
1390 }
1391}
1392
1393impl LuaTable {
1394 pub fn placeholder() -> Self {
1397 Self::default()
1398 }
1399
1400 pub fn with_inner<R>(&self, f: impl FnOnce(&TableInner) -> R) -> R {
1403 f(&self.inner.borrow())
1404 }
1405
1406 pub fn buffer_bytes(&self) -> usize {
1411 let inner = self.inner.borrow();
1412 inner.array.capacity() * std::mem::size_of::<LuaValue>()
1413 + inner.node.capacity() * std::mem::size_of::<TableNode>()
1414 }
1415
1416 #[inline(always)]
1426 pub fn get(&self, k: &LuaValue) -> LuaValue {
1427 let inner = self.inner.borrow();
1428 match k {
1429 LuaValue::Nil => LuaValue::Nil,
1430 LuaValue::Int(i) => inner.get_int_value(*i),
1431 LuaValue::Str(s) if s.is_short() => inner.get_str_value(s),
1432 _ => inner.get_generic_value(k),
1433 }
1434 }
1435
1436 #[inline(always)]
1442 pub fn get_int(&self, key: i64) -> LuaValue {
1443 let inner = self.inner.borrow();
1444 inner.get_int_value(key)
1445 }
1446
1447 #[inline(always)]
1455 pub fn get_short_str(&self, k: &GcRef<LuaString>) -> LuaValue {
1456 let inner = self.inner.borrow();
1457 if k.is_short() {
1458 inner.get_str_value(k)
1459 } else {
1460 let slot = inner.get_str_slot(k);
1461 inner.slot_value(slot)
1462 }
1463 }
1464
1465 pub fn get_str_bytes(&self, key_bytes: &[u8]) -> LuaValue {
1469 let mut found = LuaValue::Nil;
1470 self.for_each_entry(|k, v| {
1471 if !matches!(found, LuaValue::Nil) {
1472 return;
1473 }
1474 if let LuaValue::Str(s) = k {
1475 if s.as_bytes() == key_bytes {
1476 found = v.clone();
1477 }
1478 }
1479 });
1480 found
1481 }
1482
1483 pub fn raw_set(&self, k: LuaValue, v: LuaValue) {
1486 if matches!(k, LuaValue::Nil) {
1487 return;
1488 }
1489 if let LuaValue::Float(f) = &k {
1490 if f.is_nan() {
1491 return;
1492 }
1493 }
1494 let mut inner = self.inner.borrow_mut();
1495 let _ = inner.set(&k, v);
1496 }
1497
1498 #[inline]
1504 pub fn try_raw_set(&self, k: LuaValue, v: LuaValue) -> Result<(), LuaError> {
1505 match &k {
1506 LuaValue::Nil => Err(LuaError::runtime(format_args!("table index is nil"))),
1507 LuaValue::Float(f) if f.is_nan() => {
1508 Err(LuaError::runtime(format_args!("table index is NaN")))
1509 }
1510 LuaValue::Int(i) => {
1511 let key = *i;
1512 let mut inner = self.inner.borrow_mut();
1513 inner.try_raw_set_int_fast(key, v)
1514 }
1515 LuaValue::Float(f) => {
1516 let f = *f;
1517 let k_int = f as i64;
1518 if k_int as f64 == f {
1519 let mut inner = self.inner.borrow_mut();
1520 inner.try_raw_set_int_fast(k_int, v)
1521 } else {
1522 self.try_raw_set_generic(k, v)
1523 }
1524 }
1525 _ => self.try_raw_set_generic(k, v),
1526 }
1527 }
1528
1529 #[inline(always)]
1533 pub fn try_update_short_str(&self, k: &GcRef<LuaString>, v: LuaValue) -> Result<(), LuaValue> {
1534 if !k.is_short() {
1535 return Err(v);
1536 }
1537 let mut inner = self.inner.borrow_mut();
1538 inner.try_update_short_str(k, v)
1539 }
1540
1541 #[inline(always)]
1545 pub fn try_update_int(&self, k: i64, v: LuaValue) -> Result<(), LuaValue> {
1546 let mut inner = self.inner.borrow_mut();
1547 inner.try_update_int(k, v)
1548 }
1549
1550 #[cold]
1553 #[inline(never)]
1554 fn try_raw_set_generic(&self, k: LuaValue, v: LuaValue) -> Result<(), LuaError> {
1555 let mut inner = self.inner.borrow_mut();
1556 if inner.array.len() + inner.node.len() >= TOTAL_GROW_CAP
1557 && matches!(inner.get_slot(&k), TableSlotRef::Absent)
1558 {
1559 return Err(LuaError::Memory);
1560 }
1561 inner.set(&k, v)
1562 }
1563
1564 #[inline]
1571 pub fn try_raw_set_int(&self, k: i64, v: LuaValue) -> Result<(), LuaError> {
1572 let mut inner = self.inner.borrow_mut();
1573 inner.try_raw_set_int_fast(k, v)
1574 }
1575
1576 pub fn resize(&self, new_asize: u32, new_hsize: u32) -> Result<(), LuaError> {
1579 let mut inner = self.inner.borrow_mut();
1580 inner.resize(new_asize, new_hsize)
1581 }
1582
1583 pub fn array_len(&self) -> usize {
1586 self.inner.borrow().array.len()
1587 }
1588
1589 pub fn len(&self) -> usize {
1592 let inner = self.inner.borrow();
1593 let mut n = 0usize;
1594 for v in inner.array.iter() {
1595 if !matches!(v, LuaValue::Nil) {
1596 n += 1;
1597 }
1598 }
1599 for node in inner.node.iter() {
1600 if !matches!(node.value, LuaValue::Nil) {
1601 n += 1;
1602 }
1603 }
1604 n
1605 }
1606 pub fn is_empty(&self) -> bool {
1607 self.len() == 0
1608 }
1609
1610 pub fn getn(&self) -> u64 {
1612 let mut inner = self.inner.borrow_mut();
1613 inner.getn()
1614 }
1615
1616 pub fn contains_key(&self, k: &LuaValue) -> bool {
1619 if matches!(k, LuaValue::Nil) {
1620 return false;
1621 }
1622 let inner = self.inner.borrow();
1623 let slot = inner.get_slot(k);
1624 !matches!(slot, TableSlotRef::Absent)
1625 }
1626
1627 pub fn metatable(&self) -> Option<GcRef<LuaTable>> {
1628 self.metatable.borrow().clone()
1629 }
1630
1631 #[inline(always)]
1632 pub fn has_metatable(&self) -> bool {
1633 self.has_metatable.get()
1634 }
1635
1636 pub fn set_metatable(&self, mt: Option<GcRef<LuaTable>>) {
1640 let mode = mt.as_ref().map(|t| extract_weak_mode(t)).unwrap_or(0);
1641 self.weak_mode.set(mode);
1642 self.has_metatable.set(mt.is_some());
1643 *self.metatable.borrow_mut() = mt;
1644 }
1645
1646 pub fn weak_mode(&self) -> u8 {
1647 self.weak_mode.get()
1648 }
1649
1650 pub fn next_pair(&self, k: &LuaValue) -> Option<(LuaValue, LuaValue)> {
1652 let inner = self.inner.borrow();
1653 inner.next_pair(k).ok().flatten()
1654 }
1655
1656 pub fn try_next_pair(&self, k: &LuaValue) -> Result<Option<(LuaValue, LuaValue)>, LuaError> {
1659 let inner = self.inner.borrow();
1660 inner.next_pair(k)
1661 }
1662
1663 pub fn for_each_entry(&self, mut f: impl FnMut(&LuaValue, &LuaValue)) {
1667 let inner = self.inner.borrow();
1668 for (i, v) in inner.array.iter().enumerate() {
1669 if !matches!(v, LuaValue::Nil) {
1670 let k = LuaValue::Int((i + 1) as i64);
1671 f(&k, v);
1672 }
1673 }
1674 for node in inner.node.iter() {
1675 if !matches!(node.value, LuaValue::Nil) {
1676 f(&node.key, &node.value);
1677 }
1678 }
1679 }
1680
1681 pub fn prune_weak_dead(&self, is_reachable: &dyn Fn(usize) -> bool) -> Vec<LuaValue> {
1685 self.prune_weak_dead_with(is_reachable, is_reachable)
1686 }
1687
1688 pub fn prune_weak_dead_with(
1693 &self,
1694 is_key_reachable: &dyn Fn(usize) -> bool,
1695 is_value_reachable: &dyn Fn(usize) -> bool,
1696 ) -> Vec<LuaValue> {
1697 self.prune_weak_dead_with_value(
1698 &|v| collectable_identity(v).map_or(true, is_key_reachable),
1699 &|v| collectable_identity(v).map_or(true, is_value_reachable),
1700 )
1701 }
1702
1703 pub fn prune_weak_dead_with_value(
1707 &self,
1708 is_key_reachable: &dyn Fn(&LuaValue) -> bool,
1709 is_value_reachable: &dyn Fn(&LuaValue) -> bool,
1710 ) -> Vec<LuaValue> {
1711 let mode = self.weak_mode.get();
1712 if mode == 0 {
1713 return Vec::new();
1714 }
1715 let weak_k = (mode & WEAK_KEYS) != 0;
1716 let weak_v = (mode & WEAK_VALUES) != 0;
1717 let mut to_mark: Vec<LuaValue> = Vec::new();
1718 let mut inner = self.inner.borrow_mut();
1719 for i in 0..inner.array.len() {
1720 let v = inner.array[i].clone();
1721 if matches!(v, LuaValue::Nil) {
1722 continue;
1723 }
1724 if weak_v && value_is_dead_collectable(&v, is_value_reachable) {
1725 inner.array[i] = LuaValue::Nil;
1726 continue;
1727 }
1728 if weak_v {
1729 if matches!(v, LuaValue::Str(_)) {
1730 to_mark.push(v);
1731 }
1732 }
1733 }
1734 let mut i = 0;
1735 while i < inner.node.len() {
1736 let v = inner.node[i].value.clone();
1737 if matches!(v, LuaValue::Nil) {
1738 i += 1;
1739 continue;
1740 }
1741 let k = inner.node[i].key.clone();
1742 if weak_v && value_is_dead_collectable(&v, is_value_reachable) {
1743 inner.clear_dead_hash_node(i);
1744 continue;
1745 }
1746 if weak_k && value_is_dead_collectable(&k, is_key_reachable) {
1747 inner.clear_dead_hash_node(i);
1748 continue;
1749 }
1750 if weak_k {
1751 if matches!(k, LuaValue::Str(_)) {
1752 to_mark.push(k);
1753 }
1754 }
1755 if weak_v {
1756 if matches!(v, LuaValue::Str(_)) {
1757 to_mark.push(v);
1758 }
1759 }
1760 i += 1;
1761 }
1762 to_mark
1763 }
1764
1765 pub fn ephemeron_values_to_mark(&self, is_reachable: &dyn Fn(usize) -> bool) -> Vec<LuaValue> {
1767 self.ephemeron_values_to_mark_with_value(&|v| {
1768 collectable_identity(v).map_or(true, is_reachable)
1769 })
1770 }
1771
1772 pub fn ephemeron_values_to_mark_with_value(
1775 &self,
1776 is_reachable: &dyn Fn(&LuaValue) -> bool,
1777 ) -> Vec<LuaValue> {
1778 let mode = self.weak_mode.get();
1779 if (mode & WEAK_KEYS) == 0 || (mode & WEAK_VALUES) != 0 {
1780 return Vec::new();
1781 }
1782 let inner = self.inner.borrow();
1783 let mut out = Vec::new();
1784 for node in inner.node.iter() {
1785 if matches!(node.value, LuaValue::Nil) {
1786 continue;
1787 }
1788 if !value_is_dead_collectable(&node.key, is_reachable) {
1789 out.push(node.value.clone());
1790 }
1791 }
1792 for (i, v) in inner.array.iter().enumerate() {
1793 if matches!(v, LuaValue::Nil) {
1794 continue;
1795 }
1796 let k = LuaValue::Int((i + 1) as i64);
1797 if !value_is_dead_collectable(&k, is_reachable) {
1798 out.push(v.clone());
1799 }
1800 }
1801 out
1802 }
1803}
1804
1805fn value_is_dead_collectable(v: &LuaValue, is_reachable: &dyn Fn(&LuaValue) -> bool) -> bool {
1810 collectable_identity(v).is_some() && !is_reachable(v)
1811}
1812
1813fn collectable_identity(v: &LuaValue) -> Option<usize> {
1814 match v {
1815 LuaValue::Table(t) => Some(t.identity()),
1816 LuaValue::UserData(u) => Some(u.identity()),
1817 LuaValue::Thread(th) => Some(th.identity()),
1818 LuaValue::Function(c) => match c {
1819 LuaClosure::Lua(x) => Some(x.identity()),
1820 LuaClosure::C(x) => Some(x.identity()),
1821 LuaClosure::LightC(_) => None,
1822 },
1823 LuaValue::Str(_)
1824 | LuaValue::Nil
1825 | LuaValue::Bool(_)
1826 | LuaValue::Int(_)
1827 | LuaValue::Float(_)
1828 | LuaValue::LightUserData(_) => None,
1829 }
1830}
1831
1832fn extract_weak_mode(mt: &LuaTable) -> u8 {
1836 let inner = mt.inner.borrow();
1837 for node in inner.node.iter() {
1838 if let LuaValue::Str(ks) = &node.key {
1839 if ks.as_bytes() == b"__mode" {
1840 if let LuaValue::Str(vs) = &node.value {
1841 let bytes = vs.as_bytes();
1842 let mut mode = 0u8;
1843 if bytes.iter().any(|b| *b == b'k') {
1844 mode |= WEAK_KEYS;
1845 }
1846 if bytes.iter().any(|b| *b == b'v') {
1847 mode |= WEAK_VALUES;
1848 }
1849 return mode;
1850 }
1851 return 0;
1852 }
1853 }
1854 }
1855 0
1856}
1857
1858