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 fn get_short_str_slot(&self, key: &GcRef<LuaString>) -> TableSlotRef {
962 debug_assert!(key.is_short());
963 if self.is_dummy() {
964 return TableSlotRef::Absent;
965 }
966 let mut n = self.hashpow2_idx(key.hash());
967 loop {
968 if self.node[n].key_is_short_str() {
969 let ks = self.node[n].key_string();
970 if lua_string_content_eq(ks, key) {
971 return TableSlotRef::Hash(n);
972 }
973 }
974 let nx = self.node[n].next;
975 if nx == 0 {
976 return TableSlotRef::Absent;
977 }
978 n = (n as isize + nx as isize) as usize;
979 }
980 }
981
982 #[inline]
990 fn get_str_value(&self, key: &GcRef<LuaString>) -> LuaValue {
991 debug_assert!(key.is_short());
992 if self.is_dummy() {
993 return LuaValue::Nil;
994 }
995 let mut n = self.hashpow2_idx(key.hash());
996 loop {
997 if self.node[n].key_is_short_str() {
998 let ks = self.node[n].key_string();
999 if lua_string_content_eq(ks, key) {
1000 return self.node[n].value.clone();
1001 }
1002 }
1003 let nx = self.node[n].next;
1004 if nx == 0 {
1005 return LuaValue::Nil;
1006 }
1007 n = (n as isize + nx as isize) as usize;
1008 }
1009 }
1010
1011 #[cold]
1016 #[inline(never)]
1017 fn get_generic_value(&self, key: &LuaValue) -> LuaValue {
1018 let slot = self.get_slot(key);
1019 self.slot_value(slot)
1020 }
1021
1022 fn get_str_slot(&self, key: &GcRef<LuaString>) -> TableSlotRef {
1023 if key.is_short() {
1024 self.get_short_str_slot(key)
1025 } else {
1026 let ko = LuaValue::Str(key.clone());
1027 self.get_generic_slot(&ko)
1028 }
1029 }
1030
1031 fn get_slot(&self, key: &LuaValue) -> TableSlotRef {
1032 match key {
1033 LuaValue::Str(s) if s.is_short() => self.get_short_str_slot(s),
1034 LuaValue::Int(i) => self.get_int_slot(*i),
1035 LuaValue::Nil => TableSlotRef::Absent,
1036 LuaValue::Float(f) => {
1037 let f = *f;
1038 let k = f as i64;
1039 if k as f64 == f {
1040 self.get_int_slot(k)
1041 } else {
1042 self.get_generic_slot(key)
1043 }
1044 }
1045 _ => self.get_generic_slot(key),
1046 }
1047 }
1048
1049 fn slot_value(&self, slot: TableSlotRef) -> LuaValue {
1050 match slot {
1051 TableSlotRef::Array(i) => self.array[i].clone(),
1052 TableSlotRef::Hash(i) => self.node[i].value.clone(),
1053 TableSlotRef::Absent => LuaValue::Nil,
1054 }
1055 }
1056
1057 fn finish_set(
1058 &mut self,
1059 key: &LuaValue,
1060 slot: TableSlotRef,
1061 value: LuaValue,
1062 ) -> Result<(), LuaError> {
1063 match slot {
1064 TableSlotRef::Absent => self.new_key(key, value),
1065 TableSlotRef::Array(i) => {
1066 self.array[i] = value;
1067 Ok(())
1068 }
1069 TableSlotRef::Hash(i) => {
1070 self.node[i].value = value;
1071 Ok(())
1072 }
1073 }
1074 }
1075
1076 fn set(&mut self, key: &LuaValue, value: LuaValue) -> Result<(), LuaError> {
1077 let slot = self.get_slot(key);
1078 self.finish_set(key, slot, value)
1079 }
1080
1081 fn set_int(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1085 let slot = self.get_int_slot(key);
1086 if matches!(slot, TableSlotRef::Absent) {
1087 if key > 0 && (key as u64) <= ARRAY_GROW_CAP as u64 {
1088 let cur = self.alimit as i64;
1089 if key == cur + 1 && !matches!(value, LuaValue::Nil) {
1090 let new_size = (key as u32).next_power_of_two().max(4);
1091 let capped = new_size.min(ARRAY_GROW_CAP);
1092 if capped > self.alimit {
1093 let nsize = self.alloc_sizenode();
1094 self.resize(capped, nsize)?;
1095 let new_slot = self.get_int_slot(key);
1096 return self.finish_set(&LuaValue::Int(key), new_slot, value);
1097 }
1098 }
1099 }
1100 }
1101 match slot {
1102 TableSlotRef::Absent => {
1103 let k = LuaValue::Int(key);
1104 self.new_key(&k, value)
1105 }
1106 TableSlotRef::Array(i) => {
1107 self.array[i] = value;
1108 Ok(())
1109 }
1110 TableSlotRef::Hash(i) => {
1111 self.node[i].value = value;
1112 Ok(())
1113 }
1114 }
1115 }
1116
1117 #[inline]
1124 fn try_raw_set_int_fast(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1125 let alimit = self.alimit as u64;
1126 let uk = key as u64;
1127 if uk.wrapping_sub(1) < alimit {
1128 self.array[(key - 1) as usize] = value;
1129 return Ok(());
1130 }
1131 self.try_raw_set_int_cold(key, value)
1132 }
1133
1134 #[cold]
1135 #[inline(never)]
1136 fn try_raw_set_int_cold(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1137 if self.array.len() + self.node.len() >= TOTAL_GROW_CAP
1138 && matches!(self.get_int_slot(key), TableSlotRef::Absent)
1139 {
1140 return Err(LuaError::Memory);
1141 }
1142 self.set_int_value_cold(key, value)
1143 }
1144
1145 #[cold]
1152 #[inline(never)]
1153 fn set_int_value_cold(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1154 let alimit = self.alimit as u64;
1155 let uk = key as u64;
1156 if !self.is_real_asize() && alimit > 0 {
1157 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
1158 if masked < alimit {
1159 self.array[(key - 1) as usize] = value;
1160 return Ok(());
1161 }
1162 }
1163 if !self.is_dummy() {
1164 let mut n = self.hash_idx_for_int(key);
1165 loop {
1166 if self.node[n].key_is_int() && self.node[n].key_int() == key {
1167 self.node[n].value = value;
1168 return Ok(());
1169 }
1170 let nx = self.node[n].next;
1171 if nx == 0 {
1172 break;
1173 }
1174 n = (n as isize + nx as isize) as usize;
1175 }
1176 }
1177 if key > 0 && (key as u64) <= ARRAY_GROW_CAP as u64 {
1178 let cur = self.alimit as i64;
1179 if key == cur + 1 && !matches!(value, LuaValue::Nil) {
1180 let new_size = (key as u32).next_power_of_two().max(4);
1181 let capped = new_size.min(ARRAY_GROW_CAP);
1182 if capped > self.alimit {
1183 let nsize = self.alloc_sizenode();
1184 self.resize(capped, nsize)?;
1185 let new_slot = self.get_int_slot(key);
1186 return self.finish_set(&LuaValue::Int(key), new_slot, value);
1187 }
1188 }
1189 }
1190 let k = LuaValue::Int(key);
1191 self.new_key(&k, value)
1192 }
1193
1194 fn hash_search(&self, mut j: u64) -> u64 {
1197 let mut i: u64;
1198 if j == 0 {
1199 j = 1;
1200 }
1201 loop {
1202 i = j;
1203 if j <= (i64::MAX as u64) / 2 {
1204 j *= 2;
1205 } else {
1206 j = i64::MAX as u64;
1207 let s = self.get_int_slot(j as i64);
1208 if matches!(s, TableSlotRef::Absent) || matches!(self.slot_value(s), LuaValue::Nil)
1209 {
1210 break;
1211 } else {
1212 return j;
1213 }
1214 }
1215 let s = self.get_int_slot(j as i64);
1216 if matches!(s, TableSlotRef::Absent) {
1217 break;
1218 }
1219 if matches!(self.slot_value(s), LuaValue::Nil) {
1220 break;
1221 }
1222 }
1223 while j - i > 1 {
1224 let m = i / 2 + j / 2;
1225 let s = self.get_int_slot(m as i64);
1226 let empty =
1227 matches!(s, TableSlotRef::Absent) || matches!(self.slot_value(s), LuaValue::Nil);
1228 if empty {
1229 j = m;
1230 } else {
1231 i = m;
1232 }
1233 }
1234 i
1235 }
1236
1237 fn bin_search(array: &[LuaValue], mut i: u32, mut j: u32) -> u32 {
1238 while j - i > 1 {
1239 let m = (i + j) / 2;
1240 if matches!(array[(m - 1) as usize], LuaValue::Nil) {
1241 j = m;
1242 } else {
1243 i = m;
1244 }
1245 }
1246 i
1247 }
1248
1249 fn getn(&mut self) -> u64 {
1252 let limit = self.alimit;
1253 if limit > 0 && matches!(self.array[(limit - 1) as usize], LuaValue::Nil) {
1254 if limit >= 2 && !matches!(self.array[(limit - 2) as usize], LuaValue::Nil) {
1255 if self.is_pow2_real_asize() && !Self::is_pow2(limit - 1) {
1256 self.alimit = limit - 1;
1257 self.flags.set_no_real_asize();
1258 }
1259 return (limit - 1) as u64;
1260 } else {
1261 let boundary = Self::bin_search(&self.array, 0, limit);
1262 if self.is_pow2_real_asize() && boundary > self.real_asize() / 2 {
1263 self.alimit = boundary;
1264 self.flags.set_no_real_asize();
1265 }
1266 return boundary as u64;
1267 }
1268 }
1269 if !self.limit_equals_asize() {
1270 if matches!(self.array[limit as usize], LuaValue::Nil) {
1271 return limit as u64;
1272 }
1273 let real = self.real_asize();
1274 if matches!(self.array[(real - 1) as usize], LuaValue::Nil) {
1275 let old_alimit = self.alimit;
1276 let boundary = Self::bin_search(&self.array, old_alimit, real);
1277 self.alimit = boundary;
1278 return boundary as u64;
1279 }
1280 }
1281 let limit = self.real_asize();
1282 debug_assert!(
1283 limit == self.real_asize()
1284 && (limit == 0 || !matches!(self.array[(limit - 1) as usize], LuaValue::Nil))
1285 );
1286 let next_key = (limit as i64).saturating_add(1);
1287 let next_slot = self.get_int_slot(next_key);
1288 let next_empty = matches!(next_slot, TableSlotRef::Absent)
1289 || matches!(self.slot_value(next_slot), LuaValue::Nil);
1290 if self.is_dummy() || next_empty {
1291 return limit as u64;
1292 }
1293 self.hash_search(limit as u64)
1294 }
1295}
1296
1297#[derive(Debug)]
1305pub struct LuaTable {
1306 inner: RefCell<TableInner>,
1307 metatable: RefCell<Option<GcRef<LuaTable>>>,
1308 weak_mode: Cell<u8>,
1309}
1310
1311impl std::fmt::Debug for TableInner {
1312 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1313 f.debug_struct("TableInner")
1314 .field("alimit", &self.alimit)
1315 .field("array_len", &self.array.len())
1316 .field("node_len", &self.node.len())
1317 .finish()
1318 }
1319}
1320
1321impl Default for LuaTable {
1322 fn default() -> Self {
1323 LuaTable {
1324 inner: RefCell::new(TableInner::new()),
1325 metatable: RefCell::new(None),
1326 weak_mode: Cell::new(0),
1327 }
1328 }
1329}
1330
1331impl LuaTable {
1332 pub fn placeholder() -> Self {
1335 Self::default()
1336 }
1337
1338 pub fn with_inner<R>(&self, f: impl FnOnce(&TableInner) -> R) -> R {
1341 f(&self.inner.borrow())
1342 }
1343
1344 pub fn buffer_bytes(&self) -> usize {
1349 let inner = self.inner.borrow();
1350 inner.array.capacity() * std::mem::size_of::<LuaValue>()
1351 + inner.node.capacity() * std::mem::size_of::<TableNode>()
1352 }
1353
1354 #[inline(always)]
1364 pub fn get(&self, k: &LuaValue) -> LuaValue {
1365 let inner = self.inner.borrow();
1366 match k {
1367 LuaValue::Nil => LuaValue::Nil,
1368 LuaValue::Int(i) => inner.get_int_value(*i),
1369 LuaValue::Str(s) if s.is_short() => inner.get_str_value(s),
1370 _ => inner.get_generic_value(k),
1371 }
1372 }
1373
1374 #[inline(always)]
1380 pub fn get_int(&self, key: i64) -> LuaValue {
1381 let inner = self.inner.borrow();
1382 inner.get_int_value(key)
1383 }
1384
1385 #[inline(always)]
1393 pub fn get_short_str(&self, k: &GcRef<LuaString>) -> LuaValue {
1394 let inner = self.inner.borrow();
1395 if k.is_short() {
1396 inner.get_str_value(k)
1397 } else {
1398 let slot = inner.get_str_slot(k);
1399 inner.slot_value(slot)
1400 }
1401 }
1402
1403 pub fn get_str_bytes(&self, key_bytes: &[u8]) -> LuaValue {
1407 let mut found = LuaValue::Nil;
1408 self.for_each_entry(|k, v| {
1409 if !matches!(found, LuaValue::Nil) {
1410 return;
1411 }
1412 if let LuaValue::Str(s) = k {
1413 if s.as_bytes() == key_bytes {
1414 found = v.clone();
1415 }
1416 }
1417 });
1418 found
1419 }
1420
1421 pub fn raw_set(&self, k: LuaValue, v: LuaValue) {
1424 if matches!(k, LuaValue::Nil) {
1425 return;
1426 }
1427 if let LuaValue::Float(f) = &k {
1428 if f.is_nan() {
1429 return;
1430 }
1431 }
1432 let mut inner = self.inner.borrow_mut();
1433 let _ = inner.set(&k, v);
1434 }
1435
1436 #[inline]
1442 pub fn try_raw_set(&self, k: LuaValue, v: LuaValue) -> Result<(), LuaError> {
1443 match &k {
1444 LuaValue::Nil => Err(LuaError::runtime(format_args!("table index is nil"))),
1445 LuaValue::Float(f) if f.is_nan() => {
1446 Err(LuaError::runtime(format_args!("table index is NaN")))
1447 }
1448 LuaValue::Int(i) => {
1449 let key = *i;
1450 let mut inner = self.inner.borrow_mut();
1451 inner.try_raw_set_int_fast(key, v)
1452 }
1453 LuaValue::Float(f) => {
1454 let f = *f;
1455 let k_int = f as i64;
1456 if k_int as f64 == f {
1457 let mut inner = self.inner.borrow_mut();
1458 inner.try_raw_set_int_fast(k_int, v)
1459 } else {
1460 self.try_raw_set_generic(k, v)
1461 }
1462 }
1463 _ => self.try_raw_set_generic(k, v),
1464 }
1465 }
1466
1467 #[cold]
1470 #[inline(never)]
1471 fn try_raw_set_generic(&self, k: LuaValue, v: LuaValue) -> Result<(), LuaError> {
1472 let mut inner = self.inner.borrow_mut();
1473 if inner.array.len() + inner.node.len() >= TOTAL_GROW_CAP
1474 && matches!(inner.get_slot(&k), TableSlotRef::Absent)
1475 {
1476 return Err(LuaError::Memory);
1477 }
1478 inner.set(&k, v)
1479 }
1480
1481 #[inline]
1488 pub fn try_raw_set_int(&self, k: i64, v: LuaValue) -> Result<(), LuaError> {
1489 let mut inner = self.inner.borrow_mut();
1490 inner.try_raw_set_int_fast(k, v)
1491 }
1492
1493 pub fn resize(&self, new_asize: u32, new_hsize: u32) -> Result<(), LuaError> {
1496 let mut inner = self.inner.borrow_mut();
1497 inner.resize(new_asize, new_hsize)
1498 }
1499
1500 pub fn array_len(&self) -> usize {
1503 self.inner.borrow().array.len()
1504 }
1505
1506 pub fn len(&self) -> usize {
1509 let inner = self.inner.borrow();
1510 let mut n = 0usize;
1511 for v in inner.array.iter() {
1512 if !matches!(v, LuaValue::Nil) {
1513 n += 1;
1514 }
1515 }
1516 for node in inner.node.iter() {
1517 if !matches!(node.value, LuaValue::Nil) {
1518 n += 1;
1519 }
1520 }
1521 n
1522 }
1523 pub fn is_empty(&self) -> bool {
1524 self.len() == 0
1525 }
1526
1527 pub fn getn(&self) -> u64 {
1529 let mut inner = self.inner.borrow_mut();
1530 inner.getn()
1531 }
1532
1533 pub fn contains_key(&self, k: &LuaValue) -> bool {
1536 if matches!(k, LuaValue::Nil) {
1537 return false;
1538 }
1539 let inner = self.inner.borrow();
1540 let slot = inner.get_slot(k);
1541 !matches!(slot, TableSlotRef::Absent)
1542 }
1543
1544 pub fn metatable(&self) -> Option<GcRef<LuaTable>> {
1545 self.metatable.borrow().clone()
1546 }
1547
1548 pub fn set_metatable(&self, mt: Option<GcRef<LuaTable>>) {
1552 let mode = mt.as_ref().map(|t| extract_weak_mode(t)).unwrap_or(0);
1553 self.weak_mode.set(mode);
1554 *self.metatable.borrow_mut() = mt;
1555 }
1556
1557 pub fn weak_mode(&self) -> u8 {
1558 self.weak_mode.get()
1559 }
1560
1561 pub fn next_pair(&self, k: &LuaValue) -> Option<(LuaValue, LuaValue)> {
1563 let inner = self.inner.borrow();
1564 inner.next_pair(k).ok().flatten()
1565 }
1566
1567 pub fn try_next_pair(&self, k: &LuaValue) -> Result<Option<(LuaValue, LuaValue)>, LuaError> {
1570 let inner = self.inner.borrow();
1571 inner.next_pair(k)
1572 }
1573
1574 pub fn for_each_entry(&self, mut f: impl FnMut(&LuaValue, &LuaValue)) {
1578 let inner = self.inner.borrow();
1579 for (i, v) in inner.array.iter().enumerate() {
1580 if !matches!(v, LuaValue::Nil) {
1581 let k = LuaValue::Int((i + 1) as i64);
1582 f(&k, v);
1583 }
1584 }
1585 for node in inner.node.iter() {
1586 if !matches!(node.value, LuaValue::Nil) {
1587 f(&node.key, &node.value);
1588 }
1589 }
1590 }
1591
1592 pub fn prune_weak_dead(&self, is_reachable: &dyn Fn(usize) -> bool) -> Vec<LuaValue> {
1596 self.prune_weak_dead_with(is_reachable, is_reachable)
1597 }
1598
1599 pub fn prune_weak_dead_with(
1604 &self,
1605 is_key_reachable: &dyn Fn(usize) -> bool,
1606 is_value_reachable: &dyn Fn(usize) -> bool,
1607 ) -> Vec<LuaValue> {
1608 self.prune_weak_dead_with_value(
1609 &|v| collectable_identity(v).map_or(true, is_key_reachable),
1610 &|v| collectable_identity(v).map_or(true, is_value_reachable),
1611 )
1612 }
1613
1614 pub fn prune_weak_dead_with_value(
1618 &self,
1619 is_key_reachable: &dyn Fn(&LuaValue) -> bool,
1620 is_value_reachable: &dyn Fn(&LuaValue) -> bool,
1621 ) -> Vec<LuaValue> {
1622 let mode = self.weak_mode.get();
1623 if mode == 0 {
1624 return Vec::new();
1625 }
1626 let weak_k = (mode & WEAK_KEYS) != 0;
1627 let weak_v = (mode & WEAK_VALUES) != 0;
1628 let mut to_mark: Vec<LuaValue> = Vec::new();
1629 let mut inner = self.inner.borrow_mut();
1630 for i in 0..inner.array.len() {
1631 let v = inner.array[i].clone();
1632 if matches!(v, LuaValue::Nil) {
1633 continue;
1634 }
1635 if weak_v && value_is_dead_collectable(&v, is_value_reachable) {
1636 inner.array[i] = LuaValue::Nil;
1637 continue;
1638 }
1639 if weak_v {
1640 if matches!(v, LuaValue::Str(_)) {
1641 to_mark.push(v);
1642 }
1643 }
1644 }
1645 let mut i = 0;
1646 while i < inner.node.len() {
1647 let v = inner.node[i].value.clone();
1648 if matches!(v, LuaValue::Nil) {
1649 i += 1;
1650 continue;
1651 }
1652 let k = inner.node[i].key.clone();
1653 if weak_v && value_is_dead_collectable(&v, is_value_reachable) {
1654 inner.clear_dead_hash_node(i);
1655 continue;
1656 }
1657 if weak_k && value_is_dead_collectable(&k, is_key_reachable) {
1658 inner.clear_dead_hash_node(i);
1659 continue;
1660 }
1661 if weak_k {
1662 if matches!(k, LuaValue::Str(_)) {
1663 to_mark.push(k);
1664 }
1665 }
1666 if weak_v {
1667 if matches!(v, LuaValue::Str(_)) {
1668 to_mark.push(v);
1669 }
1670 }
1671 i += 1;
1672 }
1673 to_mark
1674 }
1675
1676 pub fn ephemeron_values_to_mark(&self, is_reachable: &dyn Fn(usize) -> bool) -> Vec<LuaValue> {
1678 self.ephemeron_values_to_mark_with_value(&|v| {
1679 collectable_identity(v).map_or(true, is_reachable)
1680 })
1681 }
1682
1683 pub fn ephemeron_values_to_mark_with_value(
1686 &self,
1687 is_reachable: &dyn Fn(&LuaValue) -> bool,
1688 ) -> Vec<LuaValue> {
1689 let mode = self.weak_mode.get();
1690 if (mode & WEAK_KEYS) == 0 || (mode & WEAK_VALUES) != 0 {
1691 return Vec::new();
1692 }
1693 let inner = self.inner.borrow();
1694 let mut out = Vec::new();
1695 for node in inner.node.iter() {
1696 if matches!(node.value, LuaValue::Nil) {
1697 continue;
1698 }
1699 if !value_is_dead_collectable(&node.key, is_reachable) {
1700 out.push(node.value.clone());
1701 }
1702 }
1703 for (i, v) in inner.array.iter().enumerate() {
1704 if matches!(v, LuaValue::Nil) {
1705 continue;
1706 }
1707 let k = LuaValue::Int((i + 1) as i64);
1708 if !value_is_dead_collectable(&k, is_reachable) {
1709 out.push(v.clone());
1710 }
1711 }
1712 out
1713 }
1714}
1715
1716fn value_is_dead_collectable(v: &LuaValue, is_reachable: &dyn Fn(&LuaValue) -> bool) -> bool {
1721 collectable_identity(v).is_some() && !is_reachable(v)
1722}
1723
1724fn collectable_identity(v: &LuaValue) -> Option<usize> {
1725 match v {
1726 LuaValue::Table(t) => Some(t.identity()),
1727 LuaValue::UserData(u) => Some(u.identity()),
1728 LuaValue::Thread(th) => Some(th.identity()),
1729 LuaValue::Function(c) => match c {
1730 LuaClosure::Lua(x) => Some(x.identity()),
1731 LuaClosure::C(x) => Some(x.identity()),
1732 LuaClosure::LightC(_) => None,
1733 },
1734 LuaValue::Str(_)
1735 | LuaValue::Nil
1736 | LuaValue::Bool(_)
1737 | LuaValue::Int(_)
1738 | LuaValue::Float(_)
1739 | LuaValue::LightUserData(_) => None,
1740 }
1741}
1742
1743fn extract_weak_mode(mt: &LuaTable) -> u8 {
1747 let inner = mt.inner.borrow();
1748 for node in inner.node.iter() {
1749 if let LuaValue::Str(ks) = &node.key {
1750 if ks.as_bytes() == b"__mode" {
1751 if let LuaValue::Str(vs) = &node.value {
1752 let bytes = vs.as_bytes();
1753 let mut mode = 0u8;
1754 if bytes.iter().any(|b| *b == b'k') {
1755 mode |= WEAK_KEYS;
1756 }
1757 if bytes.iter().any(|b| *b == b'v') {
1758 mode |= WEAK_VALUES;
1759 }
1760 return mode;
1761 }
1762 return 0;
1763 }
1764 }
1765 }
1766 0
1767}
1768
1769