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 { value: LuaValue::Nil, key: LuaValue::Nil, next: 0 }
132 }
133
134 fn key_is_nil(&self) -> bool { matches!(self.key, LuaValue::Nil) }
135 fn key_is_int(&self) -> bool { matches!(self.key, LuaValue::Int(_)) }
136 fn key_int(&self) -> i64 {
137 if let LuaValue::Int(i) = self.key { i }
138 else { panic!("TableNode::key_int: key is not int") }
139 }
140 fn key_is_short_str(&self) -> bool {
141 if let LuaValue::Str(s) = &self.key { s.is_short() }
142 else { false }
143 }
144 fn key_string(&self) -> &GcRef<LuaString> {
145 if let LuaValue::Str(s) = &self.key { s }
146 else { panic!("TableNode::key_string: key is not a string") }
147 }
148 fn key_value(&self) -> LuaValue { self.key.clone() }
149 fn set_key(&mut self, k: &LuaValue) { self.key = k.clone(); }
150}
151
152#[inline]
153fn lua_string_content_eq(a: &GcRef<LuaString>, b: &GcRef<LuaString>) -> bool {
154 GcRef::ptr_eq(a, b) || (a.hash() == b.hash() && a.as_bytes() == b.as_bytes())
155}
156
157#[derive(Debug, Clone, Copy)]
164pub enum TableSlotRef {
165 Array(usize),
167 Hash(usize),
169 Absent,
171}
172
173fn ceil_log2(x: u32) -> i32 {
177 static LOG_2: [u8; 256] = [
178 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,5,5,
179 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,6,6,6,6,
180 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,7,7,
181 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,7,7,
182 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,8,8,
183 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,8,8,
184 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,8,8,
185 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,8,8,
186 ];
187 let mut l: i32 = 0;
188 let mut x = x.wrapping_sub(1);
189 while x >= 256 { l += 8; x >>= 8; }
190 l + LOG_2[x as usize] as i32
191}
192
193fn hash_float(n: f64) -> i32 {
201 if n.is_nan() || n.is_infinite() {
202 return 0;
203 }
204 let (mantissa, exp) = frexp(n);
205 let scaled = mantissa * -(i32::MIN as f64);
206 let ni = scaled as i64;
207 if ni as f64 != scaled {
208 return 0;
209 }
210 let u = (exp as u32).wrapping_add(ni as u32);
211 if u <= i32::MAX as u32 { u as i32 } else { !(u as i32) }
212}
213
214fn frexp(x: f64) -> (f64, i32) {
216 if x == 0.0 || x.is_nan() || x.is_infinite() {
217 return (x, 0);
218 }
219 let bits = x.to_bits();
220 let exp_bits = ((bits >> 52) & 0x7FFu64) as i32;
221 if exp_bits == 0 {
222 let scaled = x * (2.0f64.powi(64));
223 let (m, e) = frexp(scaled);
224 return (m, e - 64);
225 }
226 let exp = exp_bits - 1022;
227 let mantissa_bits = (bits & !(0x7FFu64 << 52)) | (0x3FEu64 << 52);
228 (f64::from_bits(mantissa_bits), exp)
229}
230
231pub struct TableInner {
238 pub flags: TableFlags,
239 pub lsizenode: u8,
240 pub alimit: u32,
241 pub array: Vec<LuaValue>,
242 pub node: Vec<TableNode>,
243 pub lastfree: Option<usize>,
244}
245
246impl TableInner {
247 fn new() -> Self {
248 TableInner {
249 flags: TableFlags(0x7F),
250 lsizenode: 0,
251 alimit: 0,
252 array: Vec::new(),
253 node: Vec::new(),
254 lastfree: None,
255 }
256 }
257
258 #[inline]
260 fn is_dummy(&self) -> bool { self.lastfree.is_none() }
261
262 #[inline]
264 fn sizenode(&self) -> u32 { 1u32 << self.lsizenode }
265
266 #[inline]
268 fn alloc_sizenode(&self) -> u32 {
269 if self.is_dummy() { 0 } else { self.sizenode() }
270 }
271
272 #[inline]
274 fn is_real_asize(&self) -> bool { self.flags.is_real_asize() }
275
276 #[inline]
278 fn is_pow2(x: u32) -> bool { x == 0 || x.is_power_of_two() }
279
280 fn real_asize(&self) -> u32 {
282 if self.limit_equals_asize() {
283 return self.alimit;
284 }
285 let mut size = self.alimit;
286 size |= size >> 1;
287 size |= size >> 2;
288 size |= size >> 4;
289 size |= size >> 8;
290 size |= size >> 16;
291 size = size.wrapping_add(1);
292 debug_assert!(
293 Self::is_pow2(size) && size / 2 < self.alimit && self.alimit < size
294 );
295 size
296 }
297
298 #[inline]
299 fn limit_equals_asize(&self) -> bool {
300 self.is_real_asize() || Self::is_pow2(self.alimit)
301 }
302
303 fn is_pow2_real_asize(&self) -> bool {
304 !self.is_real_asize() || Self::is_pow2(self.alimit)
305 }
306
307 fn set_limit_to_size(&mut self) -> u32 {
308 self.alimit = self.real_asize();
309 self.flags.set_real_asize();
310 self.alimit
311 }
312
313 fn hash_idx_for_int(&self, i: i64) -> usize {
316 let ui = i as u64;
317 let sn = self.sizenode() as usize;
318 let modulo = (sn - 1) | 1;
319 if ui <= i32::MAX as u64 {
320 (ui as usize) % modulo
321 } else {
322 (ui as usize) % modulo
323 }
324 }
325
326 #[inline]
327 fn hashpow2_idx(&self, h: u32) -> usize {
328 (h & (self.sizenode() - 1)) as usize
329 }
330
331 #[inline]
332 fn hashmod_idx(&self, h: usize) -> usize {
333 let sn = self.sizenode() as usize;
334 let modulo = (sn - 1) | 1;
335 h % modulo
336 }
337
338 fn main_position(&self, key: &LuaValue) -> usize {
339 match key {
340 LuaValue::Int(i) => self.hash_idx_for_int(*i),
341 LuaValue::Float(f) => {
342 let h = hash_float(*f);
343 self.hashmod_idx(h as usize)
344 }
345 LuaValue::Str(s) if s.is_short() => self.hashpow2_idx(s.hash()),
346 LuaValue::Str(s) => self.hashpow2_idx(s.hash()),
347 LuaValue::Bool(false) => self.hashpow2_idx(0),
348 LuaValue::Bool(true) => self.hashpow2_idx(1),
349 LuaValue::LightUserData(p) => {
350 let h = (*p as usize as u32) as usize;
351 self.hashmod_idx(h)
352 }
353 LuaValue::Function(LuaClosure::LightC(f)) => {
354 let h = (*f as u32) as usize;
355 self.hashmod_idx(h)
356 }
357 LuaValue::Table(t) => {
358 let h = (GcRef::identity(t) as u32) as usize;
359 self.hashmod_idx(h)
360 }
361 LuaValue::Function(LuaClosure::Lua(cl)) => {
362 let h = (GcRef::identity(cl) as u32) as usize;
363 self.hashmod_idx(h)
364 }
365 LuaValue::Function(LuaClosure::C(cl)) => {
366 let h = (GcRef::identity(cl) as u32) as usize;
367 self.hashmod_idx(h)
368 }
369 LuaValue::UserData(u) => {
370 let h = (GcRef::identity(u) as u32) as usize;
371 self.hashmod_idx(h)
372 }
373 LuaValue::Thread(th) => {
374 let h = (GcRef::identity(th) as u32) as usize;
375 self.hashmod_idx(h)
376 }
377 LuaValue::Nil => 0,
378 }
379 }
380
381 fn main_position_from_node(&self, nd: usize) -> usize {
382 let key = self.node[nd].key_value();
383 self.main_position(&key)
384 }
385
386 fn equal_key(k1: &LuaValue, n2: &TableNode) -> bool {
389 let types_match = std::mem::discriminant(k1) == std::mem::discriminant(&n2.key);
390 if !types_match {
391 return false;
392 }
393 match &n2.key {
394 LuaValue::Nil => true,
395 LuaValue::Bool(b) => matches!(k1, LuaValue::Bool(b2) if b == b2),
396 LuaValue::Int(ni) => matches!(k1, LuaValue::Int(ki) if ki == ni),
397 LuaValue::Float(nf) => matches!(k1, LuaValue::Float(kf) if kf == nf),
398 LuaValue::LightUserData(np) => matches!(k1, LuaValue::LightUserData(kp) if kp == np),
399 LuaValue::Function(LuaClosure::LightC(nf)) => {
400 matches!(k1, LuaValue::Function(LuaClosure::LightC(kf)) if kf == nf)
401 }
402 LuaValue::Str(ns) if ns.is_long() => {
403 if let LuaValue::Str(ks) = k1 {
404 lua_string_content_eq(ks, ns)
405 } else { false }
406 }
407 _ => Self::gc_ptr_eq(k1, &n2.key),
408 }
409 }
410
411 fn gc_ptr_eq(a: &LuaValue, b: &LuaValue) -> bool {
412 match (a, b) {
413 (LuaValue::Str(sa), LuaValue::Str(sb)) => GcRef::ptr_eq(sa, sb),
414 (LuaValue::Table(ta), LuaValue::Table(tb)) => GcRef::ptr_eq(ta, tb),
415 (LuaValue::Function(LuaClosure::Lua(fa)), LuaValue::Function(LuaClosure::Lua(fb))) => {
416 GcRef::ptr_eq(fa, fb)
417 }
418 (LuaValue::Function(LuaClosure::C(fa)), LuaValue::Function(LuaClosure::C(fb))) => {
419 GcRef::ptr_eq(fa, fb)
420 }
421 (LuaValue::UserData(ua), LuaValue::UserData(ub)) => GcRef::ptr_eq(ua, ub),
422 (LuaValue::Thread(ta), LuaValue::Thread(tb)) => GcRef::ptr_eq(ta, tb),
423 _ => false,
424 }
425 }
426
427 fn get_generic_slot(&self, key: &LuaValue) -> TableSlotRef {
430 if self.is_dummy() { return TableSlotRef::Absent; }
431 let mut n = self.main_position(key);
432 loop {
433 if Self::equal_key(key, &self.node[n]) {
434 return TableSlotRef::Hash(n);
435 }
436 let nx = self.node[n].next;
437 if nx == 0 { return TableSlotRef::Absent; }
438 n = (n as isize + nx as isize) as usize;
439 }
440 }
441
442 fn array_index(k: i64) -> u32 {
445 let uk = k as u64;
446 if uk.wrapping_sub(1) < MAXASIZE as u64 { k as u32 } else { 0 }
447 }
448
449 fn find_index(&self, key: &LuaValue, asize: u32) -> Result<u32, LuaError> {
453 if matches!(key, LuaValue::Nil) { return Ok(0); }
454 let i = if let LuaValue::Int(k) = key { Self::array_index(*k) } else { 0 };
455 if i.wrapping_sub(1) < asize { return Ok(i); }
456 let slot = self.get_generic_slot(key);
457 match slot {
458 TableSlotRef::Absent => {
459 Err(LuaError::runtime(format_args!("invalid key to 'next'")))
460 }
461 TableSlotRef::Hash(node_idx) => Ok((node_idx as u32 + 1) + asize),
462 TableSlotRef::Array(_) => unreachable!("getgeneric returned Array slot"),
463 }
464 }
465
466 fn next_pair(&self, key: &LuaValue) -> Result<Option<(LuaValue, LuaValue)>, LuaError> {
469 let asize = self.real_asize();
470 let i = self.find_index(key, asize)?;
471 let mut i = i as usize;
472 while i < asize as usize {
473 if !matches!(self.array[i], LuaValue::Nil) {
474 return Ok(Some((LuaValue::Int((i + 1) as i64), self.array[i].clone())));
475 }
476 i += 1;
477 }
478 let mut hi = i.saturating_sub(asize as usize);
479 while hi < self.node.len() {
480 if !matches!(self.node[hi].value, LuaValue::Nil) {
481 return Ok(Some((self.node[hi].key_value(), self.node[hi].value.clone())));
482 }
483 hi += 1;
484 }
485 Ok(None)
486 }
487
488 fn compute_sizes(nums: &[u32], pna: &mut u32) -> u32 {
491 let mut twotoi: u32 = 1;
492 let mut a: u32 = 0;
493 let mut na: u32 = 0;
494 let mut optimal: u32 = 0;
495 for i in 0..nums.len() {
496 if twotoi == 0 || *pna <= twotoi / 2 { break; }
497 a += nums[i];
498 if a > twotoi / 2 {
499 optimal = twotoi;
500 na = a;
501 }
502 twotoi = twotoi.wrapping_mul(2);
503 }
504 debug_assert!(optimal == 0 || optimal / 2 < na && na <= optimal);
505 *pna = na;
506 optimal
507 }
508
509 fn count_int(key: i64, nums: &mut [u32]) -> bool {
510 let k = Self::array_index(key);
511 if k != 0 {
512 nums[ceil_log2(k) as usize] += 1;
513 true
514 } else { false }
515 }
516
517 fn num_use_array(&self, nums: &mut [u32]) -> u32 {
518 debug_assert!(self.is_real_asize(), "numusearray: alimit must be real size");
519 let asize = self.alimit as usize;
520 let mut ause: u32 = 0;
521 let mut i: usize = 1;
522 let mut ttlg: usize = 1;
523 for lg in 0..=(MAXABITS as usize) {
524 let mut lc: u32 = 0;
525 let lim = if ttlg > asize { asize } else { ttlg };
526 if i > lim { break; }
527 while i <= lim {
528 if !matches!(self.array[i - 1], LuaValue::Nil) { lc += 1; }
529 i += 1;
530 }
531 nums[lg] += lc;
532 ause += lc;
533 ttlg = ttlg.saturating_mul(2);
534 }
535 ause
536 }
537
538 fn num_use_hash(&self, nums: &mut [u32], pna: &mut u32) -> i32 {
539 let mut totaluse: i32 = 0;
540 let mut ause: u32 = 0;
541 let mut i = self.node.len();
542 while i > 0 {
543 i -= 1;
544 let n = &self.node[i];
545 if !matches!(n.value, LuaValue::Nil) {
546 if n.key_is_int() {
547 if Self::count_int(n.key_int(), nums) { ause += 1; }
548 }
549 totaluse += 1;
550 }
551 }
552 *pna += ause;
553 totaluse
554 }
555
556 fn set_node_vector(&mut self, size: u32) -> Result<(), LuaError> {
557 if size == 0 {
558 self.node = Vec::new();
559 self.lsizenode = 0;
560 self.lastfree = None;
561 } else {
562 let lsize = ceil_log2(size);
563 if lsize as u32 > MAXHBITS || (1u32 << lsize) > MAXHSIZE {
564 return Err(LuaError::runtime(format_args!("table overflow")));
565 }
566 let actual_size = 1u32 << lsize;
567 let mut nodes = Vec::with_capacity(actual_size as usize);
568 for _ in 0..actual_size { nodes.push(TableNode::empty()); }
569 self.node = nodes;
570 self.lsizenode = lsize as u8;
571 self.lastfree = Some(actual_size as usize);
572 }
573 Ok(())
574 }
575
576 fn reinsert(&mut self, old_nodes: Vec<(LuaValue, LuaValue)>) -> Result<(), LuaError> {
577 for (k, v) in old_nodes {
578 self.set(&k, v)?;
579 }
580 Ok(())
581 }
582
583 fn resize(&mut self, new_asize: u32, nhsize: u32) -> Result<(), LuaError> {
585 let old_asize = self.set_limit_to_size();
586
587 let (mut new_hash_node, mut new_hash_lsize, mut new_hash_lastfree) = {
588 let mut tmp = TableInner::new();
589 tmp.set_node_vector(nhsize)?;
590 (tmp.node, tmp.lsizenode, tmp.lastfree)
591 };
592
593 if new_asize < old_asize {
594 let migrate_end = (old_asize as usize).min(self.array.len());
595 let detached: Vec<(i64, LuaValue)> = ((new_asize as usize)..migrate_end)
596 .filter(|&i| !matches!(self.array[i], LuaValue::Nil))
597 .map(|i| ((i + 1) as i64, self.array[i].clone()))
598 .collect();
599 self.array.truncate(new_asize as usize);
600 self.alimit = new_asize;
601
602 std::mem::swap(&mut self.node, &mut new_hash_node);
603 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
604 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
605
606 for (key, v) in detached {
607 self.set_int(key, v)?;
608 }
609
610 self.alimit = old_asize;
611 std::mem::swap(&mut self.node, &mut new_hash_node);
612 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
613 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
614 }
615
616 self.array.resize_with(new_asize as usize, || LuaValue::Nil);
617
618 std::mem::swap(&mut self.node, &mut new_hash_node);
619 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
620 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
621 self.alimit = new_asize;
622
623 let old_hash_entries: Vec<(LuaValue, LuaValue)> = new_hash_node
624 .iter()
625 .filter(|n| !matches!(n.value, LuaValue::Nil))
626 .map(|n| (n.key_value(), n.value.clone()))
627 .collect();
628 drop(new_hash_node);
629 self.reinsert(old_hash_entries)?;
630
631 Ok(())
632 }
633
634 fn rehash(&mut self, extra_key: &LuaValue) -> Result<(), LuaError> {
635 let mut nums = [0u32; MAXABITS as usize + 1];
636 self.set_limit_to_size();
637
638 let na = self.num_use_array(&mut nums);
639 let mut na = na;
640 let mut totaluse = na as i32;
641
642 totaluse += self.num_use_hash(&mut nums, &mut na);
643
644 if let LuaValue::Int(ek) = extra_key {
645 if Self::count_int(*ek, &mut nums) { na += 1; }
646 }
647 totaluse += 1;
648
649 let asize = Self::compute_sizes(&nums, &mut na);
650
651 let nh = (totaluse - na as i32).max(0) as u32;
652 self.resize(asize, nh)
653 }
654
655 fn get_free_pos(&mut self) -> Option<usize> {
656 if self.is_dummy() { return None; }
657 loop {
658 let lf = self.lastfree?;
659 if lf == 0 {
660 self.lastfree = None;
661 return None;
662 }
663 let idx = lf - 1;
664 self.lastfree = Some(idx);
665 if self.node[idx].key_is_nil() {
666 return Some(idx);
667 }
668 }
669 }
670
671 fn find_chain_predecessor(&self, idx: usize) -> Option<usize> {
672 self.node.iter().enumerate().find(|(prev, node)| {
673 node.next != 0 && (*prev as isize + node.next as isize) == idx as isize
674 }).map(|(prev, _)| prev)
675 }
676
677 fn clear_node(&mut self, idx: usize) {
678 self.node[idx].key = LuaValue::Nil;
679 self.node[idx].value = LuaValue::Nil;
680 self.node[idx].next = 0;
681 }
682
683 fn remove_hash_node(&mut self, idx: usize) {
684 if let Some(prev) = self.find_chain_predecessor(idx) {
685 let next = self.node[idx].next;
686 self.node[prev].next = if next == 0 {
687 0
688 } else {
689 let target = idx as isize + next as isize;
690 (target - prev as isize) as i32
691 };
692 self.clear_node(idx);
693 return;
694 }
695
696 let next = self.node[idx].next;
697 if next == 0 {
698 self.clear_node(idx);
699 return;
700 }
701
702 let next_idx = (idx as isize + next as isize) as usize;
703 let moved_next = self.node[next_idx].next;
704 let moved_key = self.node[next_idx].key_value();
705 let moved_value = self.node[next_idx].value.clone();
706 self.node[idx].key = moved_key;
707 self.node[idx].value = moved_value;
708 self.node[idx].next = if moved_next == 0 {
709 0
710 } else {
711 let target = next_idx as isize + moved_next as isize;
712 (target - idx as isize) as i32
713 };
714 self.clear_node(next_idx);
715 }
716
717 fn clear_dead_hash_node(&mut self, idx: usize) {
718 self.remove_hash_node(idx);
719 }
720
721 fn new_key(&mut self, key: &LuaValue, value: LuaValue) -> Result<(), LuaError> {
722 if matches!(key, LuaValue::Nil) {
723 return Err(LuaError::runtime(format_args!("table index is nil")));
724 }
725 let normalised_key;
726 let key = if let LuaValue::Float(f) = key {
727 let f = *f;
728 if f.is_nan() {
729 return Err(LuaError::runtime(format_args!("table index is NaN")));
730 }
731 let k = f as i64;
732 if k as f64 == f {
733 normalised_key = LuaValue::Int(k);
734 &normalised_key
735 } else { key }
736 } else { key };
737
738 if matches!(value, LuaValue::Nil) { return Ok(()); }
739
740 if self.is_dummy() && !matches!(key, LuaValue::Int(_)) {
741 self.set_node_vector(DUMMY_TABLE_INIT_HASH_NODES)?;
742 let mp = self.main_position(key);
743 self.node[mp].set_key(key);
744 self.node[mp].value = value;
745 return Ok(());
746 }
747
748 let mp = self.main_position(key);
749 let mp_occupied = self.is_dummy() || !matches!(self.node[mp].value, LuaValue::Nil);
750 if mp_occupied {
751 let f = self.get_free_pos();
752 let f = match f {
753 None => {
754 self.rehash(key)?;
755 return self.set(key, value);
756 }
757 Some(idx) => idx,
758 };
759
760 debug_assert!(!self.is_dummy());
761 let othern = self.main_position_from_node(mp);
762
763 if othern != mp {
764 let mut prev = othern;
765 while (prev as isize + self.node[prev].next as isize) as usize != mp {
766 prev = (prev as isize + self.node[prev].next as isize) as usize;
767 }
768 self.node[prev].next = (f as isize - prev as isize) as i32;
769 let mp_key = self.node[mp].key_value();
770 let mp_val = self.node[mp].value.clone();
771 let mp_next = self.node[mp].next;
772 self.node[f].key = mp_key;
773 self.node[f].value = mp_val;
774 if mp_next != 0 {
775 self.node[f].next = mp_next + (mp as isize - f as isize) as i32;
776 self.node[mp].next = 0;
777 } else {
778 self.node[f].next = 0;
779 }
780 self.node[mp].value = LuaValue::Nil;
781 } else {
782 if self.node[mp].next != 0 {
783 let target = (mp as isize + self.node[mp].next as isize) as usize;
784 self.node[f].next = (target as isize - f as isize) as i32;
785 } else {
786 debug_assert!(self.node[f].next == 0);
787 }
788 self.node[mp].next = (f as isize - mp as isize) as i32;
789 self.node[f].set_key(key);
790 debug_assert!(matches!(self.node[f].value, LuaValue::Nil));
791 self.node[f].value = value;
792 return Ok(());
793 }
794 }
795 self.node[mp].set_key(key);
796 debug_assert!(matches!(self.node[mp].value, LuaValue::Nil));
797 self.node[mp].value = value;
798 Ok(())
799 }
800
801 fn get_int_slot(&self, key: i64) -> TableSlotRef {
802 let alimit = self.alimit as u64;
803 let uk = key as u64;
804 if uk.wrapping_sub(1) < alimit {
805 return TableSlotRef::Array((key - 1) as usize);
806 }
807 if !self.is_real_asize() && alimit > 0 {
808 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
809 if masked < alimit {
810 return TableSlotRef::Array((key - 1) as usize);
811 }
812 }
813 if self.is_dummy() { return TableSlotRef::Absent; }
814 let mut n = self.hash_idx_for_int(key);
815 loop {
816 if self.node[n].key_is_int() && self.node[n].key_int() == key {
817 return TableSlotRef::Hash(n);
818 }
819 let nx = self.node[n].next;
820 if nx == 0 { break; }
821 n = (n as isize + nx as isize) as usize;
822 }
823 TableSlotRef::Absent
824 }
825
826 #[inline]
833 fn get_int_value(&self, key: i64) -> LuaValue {
834 let alimit = self.alimit as u64;
835 let uk = key as u64;
836 if uk.wrapping_sub(1) < alimit {
837 return self.array[(key - 1) as usize].clone();
838 }
839 self.get_int_value_cold(key)
840 }
841
842 #[cold]
843 #[inline(never)]
844 fn get_int_value_cold(&self, key: i64) -> LuaValue {
845 let alimit = self.alimit as u64;
846 let uk = key as u64;
847 if !self.is_real_asize() && alimit > 0 {
848 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
849 if masked < alimit {
850 return self.array[(key - 1) as usize].clone();
851 }
852 }
853 if self.is_dummy() { return LuaValue::Nil; }
854 let mut n = self.hash_idx_for_int(key);
855 loop {
856 if self.node[n].key_is_int() && self.node[n].key_int() == key {
857 return self.node[n].value.clone();
858 }
859 let nx = self.node[n].next;
860 if nx == 0 { break; }
861 n = (n as isize + nx as isize) as usize;
862 }
863 LuaValue::Nil
864 }
865
866 fn get_short_str_slot(&self, key: &GcRef<LuaString>) -> TableSlotRef {
867 debug_assert!(key.is_short());
868 if self.is_dummy() { return TableSlotRef::Absent; }
869 let mut n = self.hashpow2_idx(key.hash());
870 loop {
871 if self.node[n].key_is_short_str() {
872 let ks = self.node[n].key_string();
873 if lua_string_content_eq(ks, key) {
874 return TableSlotRef::Hash(n);
875 }
876 }
877 let nx = self.node[n].next;
878 if nx == 0 { return TableSlotRef::Absent; }
879 n = (n as isize + nx as isize) as usize;
880 }
881 }
882
883 #[inline]
891 fn get_str_value(&self, key: &GcRef<LuaString>) -> LuaValue {
892 debug_assert!(key.is_short());
893 if self.is_dummy() { return LuaValue::Nil; }
894 let mut n = self.hashpow2_idx(key.hash());
895 loop {
896 if self.node[n].key_is_short_str() {
897 let ks = self.node[n].key_string();
898 if lua_string_content_eq(ks, key) {
899 return self.node[n].value.clone();
900 }
901 }
902 let nx = self.node[n].next;
903 if nx == 0 { return LuaValue::Nil; }
904 n = (n as isize + nx as isize) as usize;
905 }
906 }
907
908 #[cold]
913 #[inline(never)]
914 fn get_generic_value(&self, key: &LuaValue) -> LuaValue {
915 let slot = self.get_slot(key);
916 self.slot_value(slot)
917 }
918
919 fn get_str_slot(&self, key: &GcRef<LuaString>) -> TableSlotRef {
920 if key.is_short() {
921 self.get_short_str_slot(key)
922 } else {
923 let ko = LuaValue::Str(key.clone());
924 self.get_generic_slot(&ko)
925 }
926 }
927
928 fn get_slot(&self, key: &LuaValue) -> TableSlotRef {
929 match key {
930 LuaValue::Str(s) if s.is_short() => self.get_short_str_slot(s),
931 LuaValue::Int(i) => self.get_int_slot(*i),
932 LuaValue::Nil => TableSlotRef::Absent,
933 LuaValue::Float(f) => {
934 let f = *f;
935 let k = f as i64;
936 if k as f64 == f { self.get_int_slot(k) }
937 else { self.get_generic_slot(key) }
938 }
939 _ => self.get_generic_slot(key),
940 }
941 }
942
943 fn slot_value(&self, slot: TableSlotRef) -> LuaValue {
944 match slot {
945 TableSlotRef::Array(i) => self.array[i].clone(),
946 TableSlotRef::Hash(i) => self.node[i].value.clone(),
947 TableSlotRef::Absent => LuaValue::Nil,
948 }
949 }
950
951 fn finish_set(&mut self, key: &LuaValue, slot: TableSlotRef, value: LuaValue) -> Result<(), LuaError> {
952 match slot {
953 TableSlotRef::Absent => self.new_key(key, value),
954 TableSlotRef::Array(i) => { self.array[i] = value; Ok(()) }
955 TableSlotRef::Hash(i) => { self.node[i].value = value; Ok(()) }
956 }
957 }
958
959 fn set(&mut self, key: &LuaValue, value: LuaValue) -> Result<(), LuaError> {
960 let slot = self.get_slot(key);
961 self.finish_set(key, slot, value)
962 }
963
964 fn set_int(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
968 let slot = self.get_int_slot(key);
969 if matches!(slot, TableSlotRef::Absent) {
970 if key > 0 && (key as u64) <= ARRAY_GROW_CAP as u64 {
971 let cur = self.alimit as i64;
972 if key == cur + 1 && !matches!(value, LuaValue::Nil) {
973 let new_size = (key as u32).next_power_of_two().max(4);
974 let capped = new_size.min(ARRAY_GROW_CAP);
975 if capped > self.alimit {
976 let nsize = self.alloc_sizenode();
977 self.resize(capped, nsize)?;
978 let new_slot = self.get_int_slot(key);
979 return self.finish_set(&LuaValue::Int(key), new_slot, value);
980 }
981 }
982 }
983 }
984 match slot {
985 TableSlotRef::Absent => {
986 let k = LuaValue::Int(key);
987 self.new_key(&k, value)
988 }
989 TableSlotRef::Array(i) => { self.array[i] = value; Ok(()) }
990 TableSlotRef::Hash(i) => { self.node[i].value = value; Ok(()) }
991 }
992 }
993
994 #[inline]
1001 fn try_raw_set_int_fast(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1002 let alimit = self.alimit as u64;
1003 let uk = key as u64;
1004 if uk.wrapping_sub(1) < alimit {
1005 self.array[(key - 1) as usize] = value;
1006 return Ok(());
1007 }
1008 self.try_raw_set_int_cold(key, value)
1009 }
1010
1011 #[cold]
1012 #[inline(never)]
1013 fn try_raw_set_int_cold(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1014 if self.array.len() + self.node.len() >= TOTAL_GROW_CAP
1015 && matches!(self.get_int_slot(key), TableSlotRef::Absent)
1016 {
1017 return Err(LuaError::Memory);
1018 }
1019 self.set_int_value_cold(key, value)
1020 }
1021
1022 #[cold]
1029 #[inline(never)]
1030 fn set_int_value_cold(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1031 let alimit = self.alimit as u64;
1032 let uk = key as u64;
1033 if !self.is_real_asize() && alimit > 0 {
1034 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
1035 if masked < alimit {
1036 self.array[(key - 1) as usize] = value;
1037 return Ok(());
1038 }
1039 }
1040 if !self.is_dummy() {
1041 let mut n = self.hash_idx_for_int(key);
1042 loop {
1043 if self.node[n].key_is_int() && self.node[n].key_int() == key {
1044 self.node[n].value = value;
1045 return Ok(());
1046 }
1047 let nx = self.node[n].next;
1048 if nx == 0 { break; }
1049 n = (n as isize + nx as isize) as usize;
1050 }
1051 }
1052 if key > 0 && (key as u64) <= ARRAY_GROW_CAP as u64 {
1053 let cur = self.alimit as i64;
1054 if key == cur + 1 && !matches!(value, LuaValue::Nil) {
1055 let new_size = (key as u32).next_power_of_two().max(4);
1056 let capped = new_size.min(ARRAY_GROW_CAP);
1057 if capped > self.alimit {
1058 let nsize = self.alloc_sizenode();
1059 self.resize(capped, nsize)?;
1060 let new_slot = self.get_int_slot(key);
1061 return self.finish_set(&LuaValue::Int(key), new_slot, value);
1062 }
1063 }
1064 }
1065 let k = LuaValue::Int(key);
1066 self.new_key(&k, value)
1067 }
1068
1069 fn hash_search(&self, mut j: u64) -> u64 {
1072 let mut i: u64;
1073 if j == 0 { j = 1; }
1074 loop {
1075 i = j;
1076 if j <= (i64::MAX as u64) / 2 {
1077 j *= 2;
1078 } else {
1079 j = i64::MAX as u64;
1080 let s = self.get_int_slot(j as i64);
1081 if matches!(s, TableSlotRef::Absent)
1082 || matches!(self.slot_value(s), LuaValue::Nil)
1083 {
1084 break;
1085 } else { return j; }
1086 }
1087 let s = self.get_int_slot(j as i64);
1088 if matches!(s, TableSlotRef::Absent) { break; }
1089 if matches!(self.slot_value(s), LuaValue::Nil) { break; }
1090 }
1091 while j - i > 1 {
1092 let m = i / 2 + j / 2;
1093 let s = self.get_int_slot(m as i64);
1094 let empty = matches!(s, TableSlotRef::Absent)
1095 || matches!(self.slot_value(s), LuaValue::Nil);
1096 if empty { j = m; } else { i = m; }
1097 }
1098 i
1099 }
1100
1101 fn bin_search(array: &[LuaValue], mut i: u32, mut j: u32) -> u32 {
1102 while j - i > 1 {
1103 let m = (i + j) / 2;
1104 if matches!(array[(m - 1) as usize], LuaValue::Nil) { j = m; }
1105 else { i = m; }
1106 }
1107 i
1108 }
1109
1110 fn getn(&mut self) -> u64 {
1113 let limit = self.alimit;
1114 if limit > 0 && matches!(self.array[(limit - 1) as usize], LuaValue::Nil) {
1115 if limit >= 2 && !matches!(self.array[(limit - 2) as usize], LuaValue::Nil) {
1116 if self.is_pow2_real_asize() && !Self::is_pow2(limit - 1) {
1117 self.alimit = limit - 1;
1118 self.flags.set_no_real_asize();
1119 }
1120 return (limit - 1) as u64;
1121 } else {
1122 let boundary = Self::bin_search(&self.array, 0, limit);
1123 if self.is_pow2_real_asize() && boundary > self.real_asize() / 2 {
1124 self.alimit = boundary;
1125 self.flags.set_no_real_asize();
1126 }
1127 return boundary as u64;
1128 }
1129 }
1130 if !self.limit_equals_asize() {
1131 if matches!(self.array[limit as usize], LuaValue::Nil) {
1132 return limit as u64;
1133 }
1134 let real = self.real_asize();
1135 if matches!(self.array[(real - 1) as usize], LuaValue::Nil) {
1136 let old_alimit = self.alimit;
1137 let boundary = Self::bin_search(&self.array, old_alimit, real);
1138 self.alimit = boundary;
1139 return boundary as u64;
1140 }
1141 }
1142 let limit = self.real_asize();
1143 debug_assert!(
1144 limit == self.real_asize()
1145 && (limit == 0 || !matches!(self.array[(limit - 1) as usize], LuaValue::Nil))
1146 );
1147 let next_key = (limit as i64).saturating_add(1);
1148 let next_slot = self.get_int_slot(next_key);
1149 let next_empty = matches!(next_slot, TableSlotRef::Absent)
1150 || matches!(self.slot_value(next_slot), LuaValue::Nil);
1151 if self.is_dummy() || next_empty {
1152 return limit as u64;
1153 }
1154 self.hash_search(limit as u64)
1155 }
1156}
1157
1158#[derive(Debug)]
1166pub struct LuaTable {
1167 inner: RefCell<TableInner>,
1168 metatable: RefCell<Option<GcRef<LuaTable>>>,
1169 weak_mode: Cell<u8>,
1170}
1171
1172impl std::fmt::Debug for TableInner {
1173 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1174 f.debug_struct("TableInner")
1175 .field("alimit", &self.alimit)
1176 .field("array_len", &self.array.len())
1177 .field("node_len", &self.node.len())
1178 .finish()
1179 }
1180}
1181
1182impl Default for LuaTable {
1183 fn default() -> Self {
1184 LuaTable {
1185 inner: RefCell::new(TableInner::new()),
1186 metatable: RefCell::new(None),
1187 weak_mode: Cell::new(0),
1188 }
1189 }
1190}
1191
1192impl LuaTable {
1193 pub fn placeholder() -> Self { Self::default() }
1196
1197 pub fn with_inner<R>(&self, f: impl FnOnce(&TableInner) -> R) -> R {
1200 f(&self.inner.borrow())
1201 }
1202
1203 pub fn buffer_bytes(&self) -> usize {
1208 let inner = self.inner.borrow();
1209 inner.array.capacity() * std::mem::size_of::<LuaValue>()
1210 + inner.node.capacity() * std::mem::size_of::<TableNode>()
1211 }
1212
1213 #[inline(always)]
1223 pub fn get(&self, k: &LuaValue) -> LuaValue {
1224 let inner = self.inner.borrow();
1225 match k {
1226 LuaValue::Nil => LuaValue::Nil,
1227 LuaValue::Int(i) => inner.get_int_value(*i),
1228 LuaValue::Str(s) if s.is_short() => inner.get_str_value(s),
1229 _ => inner.get_generic_value(k),
1230 }
1231 }
1232
1233 #[inline(always)]
1239 pub fn get_int(&self, key: i64) -> LuaValue {
1240 let inner = self.inner.borrow();
1241 inner.get_int_value(key)
1242 }
1243
1244 #[inline(always)]
1252 pub fn get_short_str(&self, k: &GcRef<LuaString>) -> LuaValue {
1253 let inner = self.inner.borrow();
1254 if k.is_short() {
1255 inner.get_str_value(k)
1256 } else {
1257 let slot = inner.get_str_slot(k);
1258 inner.slot_value(slot)
1259 }
1260 }
1261
1262 pub fn get_str_bytes(&self, key_bytes: &[u8]) -> LuaValue {
1266 let mut found = LuaValue::Nil;
1267 self.for_each_entry(|k, v| {
1268 if !matches!(found, LuaValue::Nil) { return; }
1269 if let LuaValue::Str(s) = k {
1270 if s.as_bytes() == key_bytes {
1271 found = v.clone();
1272 }
1273 }
1274 });
1275 found
1276 }
1277
1278 pub fn raw_set(&self, k: LuaValue, v: LuaValue) {
1281 if matches!(k, LuaValue::Nil) { return; }
1282 if let LuaValue::Float(f) = &k {
1283 if f.is_nan() { return; }
1284 }
1285 let mut inner = self.inner.borrow_mut();
1286 let _ = inner.set(&k, v);
1287 }
1288
1289 #[inline]
1295 pub fn try_raw_set(&self, k: LuaValue, v: LuaValue) -> Result<(), LuaError> {
1296 match &k {
1297 LuaValue::Nil => {
1298 Err(LuaError::runtime(format_args!("table index is nil")))
1299 }
1300 LuaValue::Float(f) if f.is_nan() => {
1301 Err(LuaError::runtime(format_args!("table index is NaN")))
1302 }
1303 LuaValue::Int(i) => {
1304 let key = *i;
1305 let mut inner = self.inner.borrow_mut();
1306 inner.try_raw_set_int_fast(key, v)
1307 }
1308 LuaValue::Float(f) => {
1309 let f = *f;
1310 let k_int = f as i64;
1311 if k_int as f64 == f {
1312 let mut inner = self.inner.borrow_mut();
1313 inner.try_raw_set_int_fast(k_int, v)
1314 } else {
1315 self.try_raw_set_generic(k, v)
1316 }
1317 }
1318 _ => self.try_raw_set_generic(k, v),
1319 }
1320 }
1321
1322 #[cold]
1325 #[inline(never)]
1326 fn try_raw_set_generic(&self, k: LuaValue, v: LuaValue) -> Result<(), LuaError> {
1327 let mut inner = self.inner.borrow_mut();
1328 if inner.array.len() + inner.node.len() >= TOTAL_GROW_CAP
1329 && matches!(inner.get_slot(&k), TableSlotRef::Absent)
1330 {
1331 return Err(LuaError::Memory);
1332 }
1333 inner.set(&k, v)
1334 }
1335
1336 #[inline]
1343 pub fn try_raw_set_int(&self, k: i64, v: LuaValue) -> Result<(), LuaError> {
1344 let mut inner = self.inner.borrow_mut();
1345 inner.try_raw_set_int_fast(k, v)
1346 }
1347
1348 pub fn resize(&self, new_asize: u32, new_hsize: u32) -> Result<(), LuaError> {
1351 let mut inner = self.inner.borrow_mut();
1352 inner.resize(new_asize, new_hsize)
1353 }
1354
1355 pub fn array_len(&self) -> usize { self.inner.borrow().array.len() }
1358
1359 pub fn len(&self) -> usize {
1362 let inner = self.inner.borrow();
1363 let mut n = 0usize;
1364 for v in inner.array.iter() {
1365 if !matches!(v, LuaValue::Nil) { n += 1; }
1366 }
1367 for node in inner.node.iter() {
1368 if !matches!(node.value, LuaValue::Nil) { n += 1; }
1369 }
1370 n
1371 }
1372 pub fn is_empty(&self) -> bool { self.len() == 0 }
1373
1374 pub fn getn(&self) -> u64 {
1376 let mut inner = self.inner.borrow_mut();
1377 inner.getn()
1378 }
1379
1380 pub fn contains_key(&self, k: &LuaValue) -> bool {
1383 if matches!(k, LuaValue::Nil) { return false; }
1384 let inner = self.inner.borrow();
1385 let slot = inner.get_slot(k);
1386 !matches!(slot, TableSlotRef::Absent)
1387 }
1388
1389 pub fn metatable(&self) -> Option<GcRef<LuaTable>> {
1390 self.metatable.borrow().clone()
1391 }
1392
1393 pub fn set_metatable(&self, mt: Option<GcRef<LuaTable>>) {
1397 let mode = mt.as_ref().map(|t| extract_weak_mode(t)).unwrap_or(0);
1398 self.weak_mode.set(mode);
1399 *self.metatable.borrow_mut() = mt;
1400 }
1401
1402 pub fn weak_mode(&self) -> u8 { self.weak_mode.get() }
1403
1404 pub fn next_pair(&self, k: &LuaValue) -> Option<(LuaValue, LuaValue)> {
1406 let inner = self.inner.borrow();
1407 inner.next_pair(k).ok().flatten()
1408 }
1409
1410 pub fn try_next_pair(&self, k: &LuaValue) -> Result<Option<(LuaValue, LuaValue)>, LuaError> {
1413 let inner = self.inner.borrow();
1414 inner.next_pair(k)
1415 }
1416
1417 pub fn for_each_entry(&self, mut f: impl FnMut(&LuaValue, &LuaValue)) {
1421 let inner = self.inner.borrow();
1422 for (i, v) in inner.array.iter().enumerate() {
1423 if !matches!(v, LuaValue::Nil) {
1424 let k = LuaValue::Int((i + 1) as i64);
1425 f(&k, v);
1426 }
1427 }
1428 for node in inner.node.iter() {
1429 if !matches!(node.value, LuaValue::Nil) {
1430 f(&node.key, &node.value);
1431 }
1432 }
1433 }
1434
1435 pub fn prune_weak_dead(&self, is_reachable: &dyn Fn(usize) -> bool) -> Vec<LuaValue> {
1439 self.prune_weak_dead_with(is_reachable, is_reachable)
1440 }
1441
1442 pub fn prune_weak_dead_with(
1447 &self,
1448 is_key_reachable: &dyn Fn(usize) -> bool,
1449 is_value_reachable: &dyn Fn(usize) -> bool,
1450 ) -> Vec<LuaValue> {
1451 self.prune_weak_dead_with_value(
1452 &|v| collectable_identity(v).map_or(true, is_key_reachable),
1453 &|v| collectable_identity(v).map_or(true, is_value_reachable),
1454 )
1455 }
1456
1457 pub fn prune_weak_dead_with_value(
1461 &self,
1462 is_key_reachable: &dyn Fn(&LuaValue) -> bool,
1463 is_value_reachable: &dyn Fn(&LuaValue) -> bool,
1464 ) -> Vec<LuaValue> {
1465 let mode = self.weak_mode.get();
1466 if mode == 0 { return Vec::new(); }
1467 let weak_k = (mode & WEAK_KEYS) != 0;
1468 let weak_v = (mode & WEAK_VALUES) != 0;
1469 let mut to_mark: Vec<LuaValue> = Vec::new();
1470 let mut inner = self.inner.borrow_mut();
1471 for i in 0..inner.array.len() {
1472 let v = inner.array[i].clone();
1473 if matches!(v, LuaValue::Nil) { continue; }
1474 if weak_v && value_is_dead_collectable(&v, is_value_reachable) {
1475 inner.array[i] = LuaValue::Nil;
1476 continue;
1477 }
1478 if weak_v {
1479 if matches!(v, LuaValue::Str(_)) { to_mark.push(v); }
1480 }
1481 }
1482 let mut i = 0;
1483 while i < inner.node.len() {
1484 let v = inner.node[i].value.clone();
1485 if matches!(v, LuaValue::Nil) {
1486 i += 1;
1487 continue;
1488 }
1489 let k = inner.node[i].key.clone();
1490 if weak_v && value_is_dead_collectable(&v, is_value_reachable) {
1491 inner.clear_dead_hash_node(i);
1492 continue;
1493 }
1494 if weak_k && value_is_dead_collectable(&k, is_key_reachable) {
1495 inner.clear_dead_hash_node(i);
1496 continue;
1497 }
1498 if weak_k {
1499 if matches!(k, LuaValue::Str(_)) { to_mark.push(k); }
1500 }
1501 if weak_v {
1502 if matches!(v, LuaValue::Str(_)) { to_mark.push(v); }
1503 }
1504 i += 1;
1505 }
1506 to_mark
1507 }
1508
1509 pub fn ephemeron_values_to_mark(&self, is_reachable: &dyn Fn(usize) -> bool) -> Vec<LuaValue> {
1511 self.ephemeron_values_to_mark_with_value(
1512 &|v| collectable_identity(v).map_or(true, is_reachable),
1513 )
1514 }
1515
1516 pub fn ephemeron_values_to_mark_with_value(
1519 &self,
1520 is_reachable: &dyn Fn(&LuaValue) -> bool,
1521 ) -> Vec<LuaValue> {
1522 let mode = self.weak_mode.get();
1523 if (mode & WEAK_KEYS) == 0 || (mode & WEAK_VALUES) != 0 {
1524 return Vec::new();
1525 }
1526 let inner = self.inner.borrow();
1527 let mut out = Vec::new();
1528 for node in inner.node.iter() {
1529 if matches!(node.value, LuaValue::Nil) { continue; }
1530 if !value_is_dead_collectable(&node.key, is_reachable) {
1531 out.push(node.value.clone());
1532 }
1533 }
1534 for (i, v) in inner.array.iter().enumerate() {
1535 if matches!(v, LuaValue::Nil) { continue; }
1536 let k = LuaValue::Int((i + 1) as i64);
1537 if !value_is_dead_collectable(&k, is_reachable) {
1538 out.push(v.clone());
1539 }
1540 }
1541 out
1542 }
1543}
1544
1545fn value_is_dead_collectable(v: &LuaValue, is_reachable: &dyn Fn(&LuaValue) -> bool) -> bool {
1550 collectable_identity(v).is_some() && !is_reachable(v)
1551}
1552
1553fn collectable_identity(v: &LuaValue) -> Option<usize> {
1554 match v {
1555 LuaValue::Table(t) => Some(t.identity()),
1556 LuaValue::UserData(u) => Some(u.identity()),
1557 LuaValue::Thread(th) => Some(th.identity()),
1558 LuaValue::Function(c) => match c {
1559 LuaClosure::Lua(x) => Some(x.identity()),
1560 LuaClosure::C(x) => Some(x.identity()),
1561 LuaClosure::LightC(_) => None,
1562 },
1563 LuaValue::Str(_)
1564 | LuaValue::Nil
1565 | LuaValue::Bool(_)
1566 | LuaValue::Int(_)
1567 | LuaValue::Float(_)
1568 | LuaValue::LightUserData(_) => None,
1569 }
1570}
1571
1572fn extract_weak_mode(mt: &LuaTable) -> u8 {
1576 let inner = mt.inner.borrow();
1577 for node in inner.node.iter() {
1578 if let LuaValue::Str(ks) = &node.key {
1579 if ks.as_bytes() == b"__mode" {
1580 if let LuaValue::Str(vs) = &node.value {
1581 let bytes = vs.as_bytes();
1582 let mut mode = 0u8;
1583 if bytes.iter().any(|b| *b == b'k') { mode |= WEAK_KEYS; }
1584 if bytes.iter().any(|b| *b == b'v') { mode |= WEAK_VALUES; }
1585 return mode;
1586 }
1587 return 0;
1588 }
1589 }
1590 }
1591 0
1592}
1593
1594