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;
76
77const WEAK_KEYS: u8 = 1 << 0;
78const WEAK_VALUES: u8 = 1 << 1;
79
80#[derive(Clone, Copy, Debug, Default)]
85pub struct TableFlags(pub u8);
86
87impl TableFlags {
88 #[inline]
90 pub fn is_real_asize(self) -> bool {
91 (self.0 & BIT_RAS) == 0
92 }
93
94 #[inline]
96 pub fn set_real_asize(&mut self) {
97 self.0 &= !BIT_RAS;
98 }
99
100 #[inline]
102 pub fn set_no_real_asize(&mut self) {
103 self.0 |= BIT_RAS;
104 }
105
106 #[inline]
108 pub fn invalidate_tm_cache(&mut self) {
109 const MASK_FLAGS: u8 = 0x7F;
110 self.0 &= !MASK_FLAGS;
111 }
112}
113
114pub struct TableNode {
120 pub value: LuaValue,
122 pub key: LuaValue,
124 pub next: i32,
126}
127
128impl TableNode {
129 fn empty() -> Self {
130 TableNode { value: LuaValue::Nil, key: LuaValue::Nil, next: 0 }
131 }
132
133 fn key_is_nil(&self) -> bool { matches!(self.key, LuaValue::Nil) }
134 fn key_is_int(&self) -> bool { matches!(self.key, LuaValue::Int(_)) }
135 fn key_int(&self) -> i64 {
136 if let LuaValue::Int(i) = self.key { i }
137 else { panic!("TableNode::key_int: key is not int") }
138 }
139 fn key_is_short_str(&self) -> bool {
140 if let LuaValue::Str(s) = &self.key { s.is_short() }
141 else { false }
142 }
143 fn key_string(&self) -> &GcRef<LuaString> {
144 if let LuaValue::Str(s) = &self.key { s }
145 else { panic!("TableNode::key_string: key is not a string") }
146 }
147 fn key_value(&self) -> LuaValue { self.key.clone() }
148 fn set_key(&mut self, k: &LuaValue) { self.key = k.clone(); }
149}
150
151#[derive(Debug, Clone, Copy)]
158pub enum TableSlotRef {
159 Array(usize),
161 Hash(usize),
163 Absent,
165}
166
167fn ceil_log2(x: u32) -> i32 {
171 static LOG_2: [u8; 256] = [
172 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,
173 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,
174 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,
175 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,
176 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,
177 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,
178 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,
179 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,
180 ];
181 let mut l: i32 = 0;
182 let mut x = x.wrapping_sub(1);
183 while x >= 256 { l += 8; x >>= 8; }
184 l + LOG_2[x as usize] as i32
185}
186
187fn hash_float(n: f64) -> i32 {
195 if n.is_nan() || n.is_infinite() {
196 return 0;
197 }
198 let (mantissa, exp) = frexp(n);
199 let scaled = mantissa * -(i32::MIN as f64);
200 let ni = scaled as i64;
201 if ni as f64 != scaled {
202 return 0;
203 }
204 let u = (exp as u32).wrapping_add(ni as u32);
205 if u <= i32::MAX as u32 { u as i32 } else { !(u as i32) }
206}
207
208fn frexp(x: f64) -> (f64, i32) {
210 if x == 0.0 || x.is_nan() || x.is_infinite() {
211 return (x, 0);
212 }
213 let bits = x.to_bits();
214 let exp_bits = ((bits >> 52) & 0x7FFu64) as i32;
215 if exp_bits == 0 {
216 let scaled = x * (2.0f64.powi(64));
217 let (m, e) = frexp(scaled);
218 return (m, e - 64);
219 }
220 let exp = exp_bits - 1022;
221 let mantissa_bits = (bits & !(0x7FFu64 << 52)) | (0x3FEu64 << 52);
222 (f64::from_bits(mantissa_bits), exp)
223}
224
225pub struct TableInner {
232 pub flags: TableFlags,
233 pub lsizenode: u8,
234 pub alimit: u32,
235 pub array: Vec<LuaValue>,
236 pub node: Vec<TableNode>,
237 pub lastfree: Option<usize>,
238}
239
240impl TableInner {
241 fn new() -> Self {
242 TableInner {
243 flags: TableFlags(0x7F),
244 lsizenode: 0,
245 alimit: 0,
246 array: Vec::new(),
247 node: Vec::new(),
248 lastfree: None,
249 }
250 }
251
252 #[inline]
254 fn is_dummy(&self) -> bool { self.lastfree.is_none() }
255
256 #[inline]
258 fn sizenode(&self) -> u32 { 1u32 << self.lsizenode }
259
260 #[inline]
262 fn alloc_sizenode(&self) -> u32 {
263 if self.is_dummy() { 0 } else { self.sizenode() }
264 }
265
266 #[inline]
268 fn is_real_asize(&self) -> bool { self.flags.is_real_asize() }
269
270 #[inline]
272 fn is_pow2(x: u32) -> bool { x == 0 || x.is_power_of_two() }
273
274 fn real_asize(&self) -> u32 {
276 if self.limit_equals_asize() {
277 return self.alimit;
278 }
279 let mut size = self.alimit;
280 size |= size >> 1;
281 size |= size >> 2;
282 size |= size >> 4;
283 size |= size >> 8;
284 size |= size >> 16;
285 size = size.wrapping_add(1);
286 debug_assert!(
287 Self::is_pow2(size) && size / 2 < self.alimit && self.alimit < size
288 );
289 size
290 }
291
292 #[inline]
293 fn limit_equals_asize(&self) -> bool {
294 self.is_real_asize() || Self::is_pow2(self.alimit)
295 }
296
297 fn is_pow2_real_asize(&self) -> bool {
298 !self.is_real_asize() || Self::is_pow2(self.alimit)
299 }
300
301 fn set_limit_to_size(&mut self) -> u32 {
302 self.alimit = self.real_asize();
303 self.flags.set_real_asize();
304 self.alimit
305 }
306
307 fn hash_idx_for_int(&self, i: i64) -> usize {
310 let ui = i as u64;
311 let sn = self.sizenode() as usize;
312 let modulo = (sn - 1) | 1;
313 if ui <= i32::MAX as u64 {
314 (ui as usize) % modulo
315 } else {
316 (ui as usize) % modulo
317 }
318 }
319
320 #[inline]
321 fn hashpow2_idx(&self, h: u32) -> usize {
322 (h & (self.sizenode() - 1)) as usize
323 }
324
325 #[inline]
326 fn hashmod_idx(&self, h: usize) -> usize {
327 let sn = self.sizenode() as usize;
328 let modulo = (sn - 1) | 1;
329 h % modulo
330 }
331
332 fn main_position(&self, key: &LuaValue) -> usize {
333 match key {
334 LuaValue::Int(i) => self.hash_idx_for_int(*i),
335 LuaValue::Float(f) => {
336 let h = hash_float(*f);
337 self.hashmod_idx(h as usize)
338 }
339 LuaValue::Str(s) if s.is_short() => self.hashpow2_idx(s.hash()),
340 LuaValue::Str(s) => self.hashpow2_idx(s.hash()),
341 LuaValue::Bool(false) => self.hashpow2_idx(0),
342 LuaValue::Bool(true) => self.hashpow2_idx(1),
343 LuaValue::LightUserData(p) => {
344 let h = (*p as usize as u32) as usize;
345 self.hashmod_idx(h)
346 }
347 LuaValue::Function(LuaClosure::LightC(f)) => {
348 let h = (*f as u32) as usize;
349 self.hashmod_idx(h)
350 }
351 LuaValue::Table(t) => {
352 let h = (GcRef::identity(t) as u32) as usize;
353 self.hashmod_idx(h)
354 }
355 LuaValue::Function(LuaClosure::Lua(cl)) => {
356 let h = (GcRef::identity(cl) as u32) as usize;
357 self.hashmod_idx(h)
358 }
359 LuaValue::Function(LuaClosure::C(cl)) => {
360 let h = (GcRef::identity(cl) as u32) as usize;
361 self.hashmod_idx(h)
362 }
363 LuaValue::UserData(u) => {
364 let h = (GcRef::identity(u) as u32) as usize;
365 self.hashmod_idx(h)
366 }
367 LuaValue::Thread(th) => {
368 let h = (GcRef::identity(th) as u32) as usize;
369 self.hashmod_idx(h)
370 }
371 LuaValue::Nil => 0,
372 }
373 }
374
375 fn main_position_from_node(&self, nd: usize) -> usize {
376 let key = self.node[nd].key_value();
377 self.main_position(&key)
378 }
379
380 fn equal_key(k1: &LuaValue, n2: &TableNode) -> bool {
383 let types_match = std::mem::discriminant(k1) == std::mem::discriminant(&n2.key);
384 if !types_match {
385 return false;
386 }
387 match &n2.key {
388 LuaValue::Nil => true,
389 LuaValue::Bool(b) => matches!(k1, LuaValue::Bool(b2) if b == b2),
390 LuaValue::Int(ni) => matches!(k1, LuaValue::Int(ki) if ki == ni),
391 LuaValue::Float(nf) => matches!(k1, LuaValue::Float(kf) if kf == nf),
392 LuaValue::LightUserData(np) => matches!(k1, LuaValue::LightUserData(kp) if kp == np),
393 LuaValue::Function(LuaClosure::LightC(nf)) => {
394 matches!(k1, LuaValue::Function(LuaClosure::LightC(kf)) if kf == nf)
395 }
396 LuaValue::Str(ns) if ns.is_long() => {
397 if let LuaValue::Str(ks) = k1 {
398 ks.as_bytes() == ns.as_bytes()
399 } else { false }
400 }
401 _ => Self::gc_ptr_eq(k1, &n2.key),
402 }
403 }
404
405 fn gc_ptr_eq(a: &LuaValue, b: &LuaValue) -> bool {
406 match (a, b) {
407 (LuaValue::Str(sa), LuaValue::Str(sb)) => GcRef::ptr_eq(sa, sb),
408 (LuaValue::Table(ta), LuaValue::Table(tb)) => GcRef::ptr_eq(ta, tb),
409 (LuaValue::Function(LuaClosure::Lua(fa)), LuaValue::Function(LuaClosure::Lua(fb))) => {
410 GcRef::ptr_eq(fa, fb)
411 }
412 (LuaValue::Function(LuaClosure::C(fa)), LuaValue::Function(LuaClosure::C(fb))) => {
413 GcRef::ptr_eq(fa, fb)
414 }
415 (LuaValue::UserData(ua), LuaValue::UserData(ub)) => GcRef::ptr_eq(ua, ub),
416 (LuaValue::Thread(ta), LuaValue::Thread(tb)) => GcRef::ptr_eq(ta, tb),
417 _ => false,
418 }
419 }
420
421 fn get_generic_slot(&self, key: &LuaValue) -> TableSlotRef {
424 if self.is_dummy() { return TableSlotRef::Absent; }
425 let mut n = self.main_position(key);
426 loop {
427 if Self::equal_key(key, &self.node[n]) {
428 return TableSlotRef::Hash(n);
429 }
430 let nx = self.node[n].next;
431 if nx == 0 { return TableSlotRef::Absent; }
432 n = (n as isize + nx as isize) as usize;
433 }
434 }
435
436 fn array_index(k: i64) -> u32 {
439 let uk = k as u64;
440 if uk.wrapping_sub(1) < MAXASIZE as u64 { k as u32 } else { 0 }
441 }
442
443 fn find_index(&self, key: &LuaValue, asize: u32) -> Result<u32, LuaError> {
447 if matches!(key, LuaValue::Nil) { return Ok(0); }
448 let i = if let LuaValue::Int(k) = key { Self::array_index(*k) } else { 0 };
449 if i.wrapping_sub(1) < asize { return Ok(i); }
450 let slot = self.get_generic_slot(key);
451 match slot {
452 TableSlotRef::Absent => {
453 Err(LuaError::runtime(format_args!("invalid key to 'next'")))
454 }
455 TableSlotRef::Hash(node_idx) => Ok((node_idx as u32 + 1) + asize),
456 TableSlotRef::Array(_) => unreachable!("getgeneric returned Array slot"),
457 }
458 }
459
460 fn next_pair(&self, key: &LuaValue) -> Result<Option<(LuaValue, LuaValue)>, LuaError> {
463 let asize = self.real_asize();
464 let i = self.find_index(key, asize)?;
465 let mut i = i as usize;
466 while i < asize as usize {
467 if !matches!(self.array[i], LuaValue::Nil) {
468 return Ok(Some((LuaValue::Int((i + 1) as i64), self.array[i].clone())));
469 }
470 i += 1;
471 }
472 let mut hi = i.saturating_sub(asize as usize);
473 while hi < self.node.len() {
474 if !matches!(self.node[hi].value, LuaValue::Nil) {
475 return Ok(Some((self.node[hi].key_value(), self.node[hi].value.clone())));
476 }
477 hi += 1;
478 }
479 Ok(None)
480 }
481
482 fn compute_sizes(nums: &[u32], pna: &mut u32) -> u32 {
485 let mut twotoi: u32 = 1;
486 let mut a: u32 = 0;
487 let mut na: u32 = 0;
488 let mut optimal: u32 = 0;
489 for i in 0..nums.len() {
490 if twotoi == 0 || *pna <= twotoi / 2 { break; }
491 a += nums[i];
492 if a > twotoi / 2 {
493 optimal = twotoi;
494 na = a;
495 }
496 twotoi = twotoi.wrapping_mul(2);
497 }
498 debug_assert!(optimal == 0 || optimal / 2 < na && na <= optimal);
499 *pna = na;
500 optimal
501 }
502
503 fn count_int(key: i64, nums: &mut [u32]) -> bool {
504 let k = Self::array_index(key);
505 if k != 0 {
506 nums[ceil_log2(k) as usize] += 1;
507 true
508 } else { false }
509 }
510
511 fn num_use_array(&self, nums: &mut [u32]) -> u32 {
512 debug_assert!(self.is_real_asize(), "numusearray: alimit must be real size");
513 let asize = self.alimit as usize;
514 let mut ause: u32 = 0;
515 let mut i: usize = 1;
516 let mut ttlg: usize = 1;
517 for lg in 0..=(MAXABITS as usize) {
518 let mut lc: u32 = 0;
519 let lim = if ttlg > asize { asize } else { ttlg };
520 if i > lim { break; }
521 while i <= lim {
522 if !matches!(self.array[i - 1], LuaValue::Nil) { lc += 1; }
523 i += 1;
524 }
525 nums[lg] += lc;
526 ause += lc;
527 ttlg = ttlg.saturating_mul(2);
528 }
529 ause
530 }
531
532 fn num_use_hash(&self, nums: &mut [u32], pna: &mut u32) -> i32 {
533 let mut totaluse: i32 = 0;
534 let mut ause: u32 = 0;
535 let mut i = self.node.len();
536 while i > 0 {
537 i -= 1;
538 let n = &self.node[i];
539 if !matches!(n.value, LuaValue::Nil) {
540 if n.key_is_int() {
541 if Self::count_int(n.key_int(), nums) { ause += 1; }
542 }
543 totaluse += 1;
544 }
545 }
546 *pna += ause;
547 totaluse
548 }
549
550 fn set_node_vector(&mut self, size: u32) -> Result<(), LuaError> {
551 if size == 0 {
552 self.node = Vec::new();
553 self.lsizenode = 0;
554 self.lastfree = None;
555 } else {
556 let lsize = ceil_log2(size);
557 if lsize as u32 > MAXHBITS || (1u32 << lsize) > MAXHSIZE {
558 return Err(LuaError::runtime(format_args!("table overflow")));
559 }
560 let actual_size = 1u32 << lsize;
561 let mut nodes = Vec::with_capacity(actual_size as usize);
562 for _ in 0..actual_size { nodes.push(TableNode::empty()); }
563 self.node = nodes;
564 self.lsizenode = lsize as u8;
565 self.lastfree = Some(actual_size as usize);
566 }
567 Ok(())
568 }
569
570 fn reinsert(&mut self, old_nodes: Vec<(LuaValue, LuaValue)>) -> Result<(), LuaError> {
571 for (k, v) in old_nodes {
572 self.set(&k, v)?;
573 }
574 Ok(())
575 }
576
577 fn resize(&mut self, new_asize: u32, nhsize: u32) -> Result<(), LuaError> {
579 let old_asize = self.set_limit_to_size();
580
581 let (mut new_hash_node, mut new_hash_lsize, mut new_hash_lastfree) = {
582 let mut tmp = TableInner::new();
583 tmp.set_node_vector(nhsize)?;
584 (tmp.node, tmp.lsizenode, tmp.lastfree)
585 };
586
587 if new_asize < old_asize {
588 let migrate_end = (old_asize as usize).min(self.array.len());
589 let detached: Vec<(i64, LuaValue)> = ((new_asize as usize)..migrate_end)
590 .filter(|&i| !matches!(self.array[i], LuaValue::Nil))
591 .map(|i| ((i + 1) as i64, self.array[i].clone()))
592 .collect();
593 self.array.truncate(new_asize as usize);
594 self.alimit = new_asize;
595
596 std::mem::swap(&mut self.node, &mut new_hash_node);
597 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
598 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
599
600 for (key, v) in detached {
601 self.set_int(key, v)?;
602 }
603
604 self.alimit = old_asize;
605 std::mem::swap(&mut self.node, &mut new_hash_node);
606 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
607 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
608 }
609
610 self.array.resize_with(new_asize as usize, || LuaValue::Nil);
611
612 std::mem::swap(&mut self.node, &mut new_hash_node);
613 std::mem::swap(&mut self.lsizenode, &mut new_hash_lsize);
614 std::mem::swap(&mut self.lastfree, &mut new_hash_lastfree);
615 self.alimit = new_asize;
616
617 let old_hash_entries: Vec<(LuaValue, LuaValue)> = new_hash_node
618 .iter()
619 .filter(|n| !matches!(n.value, LuaValue::Nil))
620 .map(|n| (n.key_value(), n.value.clone()))
621 .collect();
622 drop(new_hash_node);
623 self.reinsert(old_hash_entries)?;
624
625 Ok(())
626 }
627
628 fn rehash(&mut self, extra_key: &LuaValue) -> Result<(), LuaError> {
629 let mut nums = [0u32; MAXABITS as usize + 1];
630 self.set_limit_to_size();
631
632 let na = self.num_use_array(&mut nums);
633 let mut na = na;
634 let mut totaluse = na as i32;
635
636 totaluse += self.num_use_hash(&mut nums, &mut na);
637
638 if let LuaValue::Int(ek) = extra_key {
639 if Self::count_int(*ek, &mut nums) { na += 1; }
640 }
641 totaluse += 1;
642
643 let asize = Self::compute_sizes(&nums, &mut na);
644
645 let nh = (totaluse - na as i32).max(0) as u32;
646 self.resize(asize, nh)
647 }
648
649 fn get_free_pos(&mut self) -> Option<usize> {
650 if self.is_dummy() { return None; }
651 loop {
652 let lf = self.lastfree?;
653 if lf == 0 {
654 self.lastfree = None;
655 return None;
656 }
657 let idx = lf - 1;
658 self.lastfree = Some(idx);
659 if self.node[idx].key_is_nil() {
660 return Some(idx);
661 }
662 }
663 }
664
665 fn find_chain_predecessor(&self, idx: usize) -> Option<usize> {
666 self.node.iter().enumerate().find(|(prev, node)| {
667 node.next != 0 && (*prev as isize + node.next as isize) == idx as isize
668 }).map(|(prev, _)| prev)
669 }
670
671 fn clear_node(&mut self, idx: usize) {
672 self.node[idx].key = LuaValue::Nil;
673 self.node[idx].value = LuaValue::Nil;
674 self.node[idx].next = 0;
675 }
676
677 fn remove_hash_node(&mut self, idx: usize) {
678 if let Some(prev) = self.find_chain_predecessor(idx) {
679 let next = self.node[idx].next;
680 self.node[prev].next = if next == 0 {
681 0
682 } else {
683 let target = idx as isize + next as isize;
684 (target - prev as isize) as i32
685 };
686 self.clear_node(idx);
687 return;
688 }
689
690 let next = self.node[idx].next;
691 if next == 0 {
692 self.clear_node(idx);
693 return;
694 }
695
696 let next_idx = (idx as isize + next as isize) as usize;
697 let moved_next = self.node[next_idx].next;
698 let moved_key = self.node[next_idx].key_value();
699 let moved_value = self.node[next_idx].value.clone();
700 self.node[idx].key = moved_key;
701 self.node[idx].value = moved_value;
702 self.node[idx].next = if moved_next == 0 {
703 0
704 } else {
705 let target = next_idx as isize + moved_next as isize;
706 (target - idx as isize) as i32
707 };
708 self.clear_node(next_idx);
709 }
710
711 fn clear_dead_hash_node(&mut self, idx: usize) {
712 self.remove_hash_node(idx);
713 }
714
715 fn new_key(&mut self, key: &LuaValue, value: LuaValue) -> Result<(), LuaError> {
716 if matches!(key, LuaValue::Nil) {
717 return Err(LuaError::runtime(format_args!("table index is nil")));
718 }
719 let normalised_key;
720 let key = if let LuaValue::Float(f) = key {
721 let f = *f;
722 if f.is_nan() {
723 return Err(LuaError::runtime(format_args!("table index is NaN")));
724 }
725 let k = f as i64;
726 if k as f64 == f {
727 normalised_key = LuaValue::Int(k);
728 &normalised_key
729 } else { key }
730 } else { key };
731
732 if matches!(value, LuaValue::Nil) { return Ok(()); }
733
734 if self.is_dummy() && !matches!(key, LuaValue::Int(_)) {
735 self.set_node_vector(DUMMY_TABLE_INIT_HASH_NODES)?;
736 let mp = self.main_position(key);
737 self.node[mp].set_key(key);
738 self.node[mp].value = value;
739 return Ok(());
740 }
741
742 let mp = self.main_position(key);
743 let mp_occupied = self.is_dummy() || !matches!(self.node[mp].value, LuaValue::Nil);
744 if mp_occupied {
745 let f = self.get_free_pos();
746 let f = match f {
747 None => {
748 self.rehash(key)?;
749 return self.set(key, value);
750 }
751 Some(idx) => idx,
752 };
753
754 debug_assert!(!self.is_dummy());
755 let othern = self.main_position_from_node(mp);
756
757 if othern != mp {
758 let mut prev = othern;
759 while (prev as isize + self.node[prev].next as isize) as usize != mp {
760 prev = (prev as isize + self.node[prev].next as isize) as usize;
761 }
762 self.node[prev].next = (f as isize - prev as isize) as i32;
763 let mp_key = self.node[mp].key_value();
764 let mp_val = self.node[mp].value.clone();
765 let mp_next = self.node[mp].next;
766 self.node[f].key = mp_key;
767 self.node[f].value = mp_val;
768 if mp_next != 0 {
769 self.node[f].next = mp_next + (mp as isize - f as isize) as i32;
770 self.node[mp].next = 0;
771 } else {
772 self.node[f].next = 0;
773 }
774 self.node[mp].value = LuaValue::Nil;
775 } else {
776 if self.node[mp].next != 0 {
777 let target = (mp as isize + self.node[mp].next as isize) as usize;
778 self.node[f].next = (target as isize - f as isize) as i32;
779 } else {
780 debug_assert!(self.node[f].next == 0);
781 }
782 self.node[mp].next = (f as isize - mp as isize) as i32;
783 self.node[f].set_key(key);
784 debug_assert!(matches!(self.node[f].value, LuaValue::Nil));
785 self.node[f].value = value;
786 return Ok(());
787 }
788 }
789 self.node[mp].set_key(key);
790 debug_assert!(matches!(self.node[mp].value, LuaValue::Nil));
791 self.node[mp].value = value;
792 Ok(())
793 }
794
795 fn get_int_slot(&self, key: i64) -> TableSlotRef {
796 let alimit = self.alimit as u64;
797 let uk = key as u64;
798 if uk.wrapping_sub(1) < alimit {
799 return TableSlotRef::Array((key - 1) as usize);
800 }
801 if !self.is_real_asize() && alimit > 0 {
802 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
803 if masked < alimit {
804 return TableSlotRef::Array((key - 1) as usize);
805 }
806 }
807 if self.is_dummy() { return TableSlotRef::Absent; }
808 let mut n = self.hash_idx_for_int(key);
809 loop {
810 if self.node[n].key_is_int() && self.node[n].key_int() == key {
811 return TableSlotRef::Hash(n);
812 }
813 let nx = self.node[n].next;
814 if nx == 0 { break; }
815 n = (n as isize + nx as isize) as usize;
816 }
817 TableSlotRef::Absent
818 }
819
820 #[inline]
827 fn get_int_value(&self, key: i64) -> LuaValue {
828 let alimit = self.alimit as u64;
829 let uk = key as u64;
830 if uk.wrapping_sub(1) < alimit {
831 return self.array[(key - 1) as usize].clone();
832 }
833 self.get_int_value_cold(key)
834 }
835
836 #[cold]
837 #[inline(never)]
838 fn get_int_value_cold(&self, key: i64) -> LuaValue {
839 let alimit = self.alimit as u64;
840 let uk = key as u64;
841 if !self.is_real_asize() && alimit > 0 {
842 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
843 if masked < alimit {
844 return self.array[(key - 1) as usize].clone();
845 }
846 }
847 if self.is_dummy() { return LuaValue::Nil; }
848 let mut n = self.hash_idx_for_int(key);
849 loop {
850 if self.node[n].key_is_int() && self.node[n].key_int() == key {
851 return self.node[n].value.clone();
852 }
853 let nx = self.node[n].next;
854 if nx == 0 { break; }
855 n = (n as isize + nx as isize) as usize;
856 }
857 LuaValue::Nil
858 }
859
860 fn get_short_str_slot(&self, key: &GcRef<LuaString>) -> TableSlotRef {
861 debug_assert!(key.is_short());
862 if self.is_dummy() { return TableSlotRef::Absent; }
863 let mut n = self.hashpow2_idx(key.hash());
864 loop {
865 if self.node[n].key_is_short_str() {
866 let ks = self.node[n].key_string();
867 if GcRef::ptr_eq(ks, key) || ks.as_bytes() == key.as_bytes() {
868 return TableSlotRef::Hash(n);
869 }
870 }
871 let nx = self.node[n].next;
872 if nx == 0 { return TableSlotRef::Absent; }
873 n = (n as isize + nx as isize) as usize;
874 }
875 }
876
877 #[inline]
885 fn get_str_value(&self, key: &GcRef<LuaString>) -> LuaValue {
886 debug_assert!(key.is_short());
887 if self.is_dummy() { return LuaValue::Nil; }
888 let mut n = self.hashpow2_idx(key.hash());
889 loop {
890 if self.node[n].key_is_short_str() {
891 let ks = self.node[n].key_string();
892 if GcRef::ptr_eq(ks, key) || ks.as_bytes() == key.as_bytes() {
893 return self.node[n].value.clone();
894 }
895 }
896 let nx = self.node[n].next;
897 if nx == 0 { return LuaValue::Nil; }
898 n = (n as isize + nx as isize) as usize;
899 }
900 }
901
902 #[cold]
907 #[inline(never)]
908 fn get_generic_value(&self, key: &LuaValue) -> LuaValue {
909 let slot = self.get_slot(key);
910 self.slot_value(slot)
911 }
912
913 fn get_str_slot(&self, key: &GcRef<LuaString>) -> TableSlotRef {
914 if key.is_short() {
915 self.get_short_str_slot(key)
916 } else {
917 let ko = LuaValue::Str(key.clone());
918 self.get_generic_slot(&ko)
919 }
920 }
921
922 fn get_slot(&self, key: &LuaValue) -> TableSlotRef {
923 match key {
924 LuaValue::Str(s) if s.is_short() => self.get_short_str_slot(s),
925 LuaValue::Int(i) => self.get_int_slot(*i),
926 LuaValue::Nil => TableSlotRef::Absent,
927 LuaValue::Float(f) => {
928 let f = *f;
929 let k = f as i64;
930 if k as f64 == f { self.get_int_slot(k) }
931 else { self.get_generic_slot(key) }
932 }
933 _ => self.get_generic_slot(key),
934 }
935 }
936
937 fn slot_value(&self, slot: TableSlotRef) -> LuaValue {
938 match slot {
939 TableSlotRef::Array(i) => self.array[i].clone(),
940 TableSlotRef::Hash(i) => self.node[i].value.clone(),
941 TableSlotRef::Absent => LuaValue::Nil,
942 }
943 }
944
945 fn finish_set(&mut self, key: &LuaValue, slot: TableSlotRef, value: LuaValue) -> Result<(), LuaError> {
946 match slot {
947 TableSlotRef::Absent => self.new_key(key, value),
948 TableSlotRef::Array(i) => { self.array[i] = value; Ok(()) }
949 TableSlotRef::Hash(i) => { self.node[i].value = value; Ok(()) }
950 }
951 }
952
953 fn set(&mut self, key: &LuaValue, value: LuaValue) -> Result<(), LuaError> {
954 let slot = self.get_slot(key);
955 self.finish_set(key, slot, value)
956 }
957
958 fn set_int(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
962 let slot = self.get_int_slot(key);
963 if matches!(slot, TableSlotRef::Absent) {
964 if key > 0 && (key as u64) <= ARRAY_GROW_CAP as u64 {
965 let cur = self.alimit as i64;
966 if key == cur + 1 && !matches!(value, LuaValue::Nil) {
967 let new_size = (key as u32).next_power_of_two().max(4);
968 let capped = new_size.min(ARRAY_GROW_CAP);
969 if capped > self.alimit {
970 let nsize = self.alloc_sizenode();
971 self.resize(capped, nsize)?;
972 let new_slot = self.get_int_slot(key);
973 return self.finish_set(&LuaValue::Int(key), new_slot, value);
974 }
975 }
976 }
977 }
978 match slot {
979 TableSlotRef::Absent => {
980 let k = LuaValue::Int(key);
981 self.new_key(&k, value)
982 }
983 TableSlotRef::Array(i) => { self.array[i] = value; Ok(()) }
984 TableSlotRef::Hash(i) => { self.node[i].value = value; Ok(()) }
985 }
986 }
987
988 #[inline]
995 fn try_raw_set_int_fast(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
996 let alimit = self.alimit as u64;
997 let uk = key as u64;
998 if uk.wrapping_sub(1) < alimit {
999 self.array[(key - 1) as usize] = value;
1000 return Ok(());
1001 }
1002 self.try_raw_set_int_cold(key, value)
1003 }
1004
1005 #[cold]
1006 #[inline(never)]
1007 fn try_raw_set_int_cold(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1008 if self.array.len() + self.node.len() >= TOTAL_GROW_CAP
1009 && matches!(self.get_int_slot(key), TableSlotRef::Absent)
1010 {
1011 return Err(LuaError::Memory);
1012 }
1013 self.set_int_value_cold(key, value)
1014 }
1015
1016 #[cold]
1023 #[inline(never)]
1024 fn set_int_value_cold(&mut self, key: i64, value: LuaValue) -> Result<(), LuaError> {
1025 let alimit = self.alimit as u64;
1026 let uk = key as u64;
1027 if !self.is_real_asize() && alimit > 0 {
1028 let masked = (uk.wrapping_sub(1)) & !(alimit.wrapping_sub(1));
1029 if masked < alimit {
1030 self.array[(key - 1) as usize] = value;
1031 return Ok(());
1032 }
1033 }
1034 if !self.is_dummy() {
1035 let mut n = self.hash_idx_for_int(key);
1036 loop {
1037 if self.node[n].key_is_int() && self.node[n].key_int() == key {
1038 self.node[n].value = value;
1039 return Ok(());
1040 }
1041 let nx = self.node[n].next;
1042 if nx == 0 { break; }
1043 n = (n as isize + nx as isize) as usize;
1044 }
1045 }
1046 if key > 0 && (key as u64) <= ARRAY_GROW_CAP as u64 {
1047 let cur = self.alimit as i64;
1048 if key == cur + 1 && !matches!(value, LuaValue::Nil) {
1049 let new_size = (key as u32).next_power_of_two().max(4);
1050 let capped = new_size.min(ARRAY_GROW_CAP);
1051 if capped > self.alimit {
1052 let nsize = self.alloc_sizenode();
1053 self.resize(capped, nsize)?;
1054 let new_slot = self.get_int_slot(key);
1055 return self.finish_set(&LuaValue::Int(key), new_slot, value);
1056 }
1057 }
1058 }
1059 let k = LuaValue::Int(key);
1060 self.new_key(&k, value)
1061 }
1062
1063 fn hash_search(&self, mut j: u64) -> u64 {
1066 let mut i: u64;
1067 if j == 0 { j = 1; }
1068 loop {
1069 i = j;
1070 if j <= (i64::MAX as u64) / 2 {
1071 j *= 2;
1072 } else {
1073 j = i64::MAX as u64;
1074 let s = self.get_int_slot(j as i64);
1075 if matches!(s, TableSlotRef::Absent)
1076 || matches!(self.slot_value(s), LuaValue::Nil)
1077 {
1078 break;
1079 } else { return j; }
1080 }
1081 let s = self.get_int_slot(j as i64);
1082 if matches!(s, TableSlotRef::Absent) { break; }
1083 if matches!(self.slot_value(s), LuaValue::Nil) { break; }
1084 }
1085 while j - i > 1 {
1086 let m = i / 2 + j / 2;
1087 let s = self.get_int_slot(m as i64);
1088 let empty = matches!(s, TableSlotRef::Absent)
1089 || matches!(self.slot_value(s), LuaValue::Nil);
1090 if empty { j = m; } else { i = m; }
1091 }
1092 i
1093 }
1094
1095 fn bin_search(array: &[LuaValue], mut i: u32, mut j: u32) -> u32 {
1096 while j - i > 1 {
1097 let m = (i + j) / 2;
1098 if matches!(array[(m - 1) as usize], LuaValue::Nil) { j = m; }
1099 else { i = m; }
1100 }
1101 i
1102 }
1103
1104 fn getn(&mut self) -> u64 {
1107 let limit = self.alimit;
1108 if limit > 0 && matches!(self.array[(limit - 1) as usize], LuaValue::Nil) {
1109 if limit >= 2 && !matches!(self.array[(limit - 2) as usize], LuaValue::Nil) {
1110 if self.is_pow2_real_asize() && !Self::is_pow2(limit - 1) {
1111 self.alimit = limit - 1;
1112 self.flags.set_no_real_asize();
1113 }
1114 return (limit - 1) as u64;
1115 } else {
1116 let boundary = Self::bin_search(&self.array, 0, limit);
1117 if self.is_pow2_real_asize() && boundary > self.real_asize() / 2 {
1118 self.alimit = boundary;
1119 self.flags.set_no_real_asize();
1120 }
1121 return boundary as u64;
1122 }
1123 }
1124 if !self.limit_equals_asize() {
1125 if matches!(self.array[limit as usize], LuaValue::Nil) {
1126 return limit as u64;
1127 }
1128 let real = self.real_asize();
1129 if matches!(self.array[(real - 1) as usize], LuaValue::Nil) {
1130 let old_alimit = self.alimit;
1131 let boundary = Self::bin_search(&self.array, old_alimit, real);
1132 self.alimit = boundary;
1133 return boundary as u64;
1134 }
1135 }
1136 let limit = self.real_asize();
1137 debug_assert!(
1138 limit == self.real_asize()
1139 && (limit == 0 || !matches!(self.array[(limit - 1) as usize], LuaValue::Nil))
1140 );
1141 let next_key = (limit as i64).saturating_add(1);
1142 let next_slot = self.get_int_slot(next_key);
1143 let next_empty = matches!(next_slot, TableSlotRef::Absent)
1144 || matches!(self.slot_value(next_slot), LuaValue::Nil);
1145 if self.is_dummy() || next_empty {
1146 return limit as u64;
1147 }
1148 self.hash_search(limit as u64)
1149 }
1150}
1151
1152#[derive(Debug)]
1160pub struct LuaTable {
1161 inner: RefCell<TableInner>,
1162 metatable: RefCell<Option<GcRef<LuaTable>>>,
1163 weak_mode: Cell<u8>,
1164}
1165
1166impl std::fmt::Debug for TableInner {
1167 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1168 f.debug_struct("TableInner")
1169 .field("alimit", &self.alimit)
1170 .field("array_len", &self.array.len())
1171 .field("node_len", &self.node.len())
1172 .finish()
1173 }
1174}
1175
1176impl Default for LuaTable {
1177 fn default() -> Self {
1178 LuaTable {
1179 inner: RefCell::new(TableInner::new()),
1180 metatable: RefCell::new(None),
1181 weak_mode: Cell::new(0),
1182 }
1183 }
1184}
1185
1186impl LuaTable {
1187 pub fn placeholder() -> Self { Self::default() }
1190
1191 pub fn with_inner<R>(&self, f: impl FnOnce(&TableInner) -> R) -> R {
1194 f(&self.inner.borrow())
1195 }
1196
1197 pub fn buffer_bytes(&self) -> usize {
1202 let inner = self.inner.borrow();
1203 inner.array.capacity() * std::mem::size_of::<LuaValue>()
1204 + inner.node.capacity() * std::mem::size_of::<TableNode>()
1205 }
1206
1207 #[inline(always)]
1217 pub fn get(&self, k: &LuaValue) -> LuaValue {
1218 let inner = self.inner.borrow();
1219 match k {
1220 LuaValue::Nil => LuaValue::Nil,
1221 LuaValue::Int(i) => inner.get_int_value(*i),
1222 LuaValue::Str(s) if s.is_short() => inner.get_str_value(s),
1223 _ => inner.get_generic_value(k),
1224 }
1225 }
1226
1227 #[inline(always)]
1233 pub fn get_int(&self, key: i64) -> LuaValue {
1234 let inner = self.inner.borrow();
1235 inner.get_int_value(key)
1236 }
1237
1238 #[inline(always)]
1246 pub fn get_short_str(&self, k: &GcRef<LuaString>) -> LuaValue {
1247 let inner = self.inner.borrow();
1248 if k.is_short() {
1249 inner.get_str_value(k)
1250 } else {
1251 let slot = inner.get_str_slot(k);
1252 inner.slot_value(slot)
1253 }
1254 }
1255
1256 pub fn get_str_bytes(&self, key_bytes: &[u8]) -> LuaValue {
1260 let mut found = LuaValue::Nil;
1261 self.for_each_entry(|k, v| {
1262 if !matches!(found, LuaValue::Nil) { return; }
1263 if let LuaValue::Str(s) = k {
1264 if s.as_bytes() == key_bytes {
1265 found = v.clone();
1266 }
1267 }
1268 });
1269 found
1270 }
1271
1272 pub fn raw_set(&self, k: LuaValue, v: LuaValue) {
1275 if matches!(k, LuaValue::Nil) { return; }
1276 if let LuaValue::Float(f) = &k {
1277 if f.is_nan() { return; }
1278 }
1279 let mut inner = self.inner.borrow_mut();
1280 let _ = inner.set(&k, v);
1281 }
1282
1283 #[inline]
1289 pub fn try_raw_set(&self, k: LuaValue, v: LuaValue) -> Result<(), LuaError> {
1290 match &k {
1291 LuaValue::Nil => {
1292 Err(LuaError::runtime(format_args!("table index is nil")))
1293 }
1294 LuaValue::Float(f) if f.is_nan() => {
1295 Err(LuaError::runtime(format_args!("table index is NaN")))
1296 }
1297 LuaValue::Int(i) => {
1298 let key = *i;
1299 let mut inner = self.inner.borrow_mut();
1300 inner.try_raw_set_int_fast(key, v)
1301 }
1302 LuaValue::Float(f) => {
1303 let f = *f;
1304 let k_int = f as i64;
1305 if k_int as f64 == f {
1306 let mut inner = self.inner.borrow_mut();
1307 inner.try_raw_set_int_fast(k_int, v)
1308 } else {
1309 self.try_raw_set_generic(k, v)
1310 }
1311 }
1312 _ => self.try_raw_set_generic(k, v),
1313 }
1314 }
1315
1316 #[cold]
1319 #[inline(never)]
1320 fn try_raw_set_generic(&self, k: LuaValue, v: LuaValue) -> Result<(), LuaError> {
1321 let mut inner = self.inner.borrow_mut();
1322 if inner.array.len() + inner.node.len() >= TOTAL_GROW_CAP
1323 && matches!(inner.get_slot(&k), TableSlotRef::Absent)
1324 {
1325 return Err(LuaError::Memory);
1326 }
1327 inner.set(&k, v)
1328 }
1329
1330 #[inline]
1337 pub fn try_raw_set_int(&self, k: i64, v: LuaValue) -> Result<(), LuaError> {
1338 let mut inner = self.inner.borrow_mut();
1339 inner.try_raw_set_int_fast(k, v)
1340 }
1341
1342 pub fn resize(&self, new_asize: u32, new_hsize: u32) -> Result<(), LuaError> {
1345 let mut inner = self.inner.borrow_mut();
1346 inner.resize(new_asize, new_hsize)
1347 }
1348
1349 pub fn array_len(&self) -> usize { self.inner.borrow().array.len() }
1352
1353 pub fn len(&self) -> usize {
1356 let inner = self.inner.borrow();
1357 let mut n = 0usize;
1358 for v in inner.array.iter() {
1359 if !matches!(v, LuaValue::Nil) { n += 1; }
1360 }
1361 for node in inner.node.iter() {
1362 if !matches!(node.value, LuaValue::Nil) { n += 1; }
1363 }
1364 n
1365 }
1366 pub fn is_empty(&self) -> bool { self.len() == 0 }
1367
1368 pub fn getn(&self) -> u64 {
1370 let mut inner = self.inner.borrow_mut();
1371 inner.getn()
1372 }
1373
1374 pub fn contains_key(&self, k: &LuaValue) -> bool {
1377 if matches!(k, LuaValue::Nil) { return false; }
1378 let inner = self.inner.borrow();
1379 let slot = inner.get_slot(k);
1380 !matches!(slot, TableSlotRef::Absent)
1381 }
1382
1383 pub fn metatable(&self) -> Option<GcRef<LuaTable>> {
1384 self.metatable.borrow().clone()
1385 }
1386
1387 pub fn set_metatable(&self, mt: Option<GcRef<LuaTable>>) {
1391 let mode = mt.as_ref().map(|t| extract_weak_mode(t)).unwrap_or(0);
1392 self.weak_mode.set(mode);
1393 *self.metatable.borrow_mut() = mt;
1394 }
1395
1396 pub fn weak_mode(&self) -> u8 { self.weak_mode.get() }
1397
1398 pub fn next_pair(&self, k: &LuaValue) -> Option<(LuaValue, LuaValue)> {
1400 let inner = self.inner.borrow();
1401 inner.next_pair(k).ok().flatten()
1402 }
1403
1404 pub fn try_next_pair(&self, k: &LuaValue) -> Result<Option<(LuaValue, LuaValue)>, LuaError> {
1407 let inner = self.inner.borrow();
1408 inner.next_pair(k)
1409 }
1410
1411 pub fn for_each_entry(&self, mut f: impl FnMut(&LuaValue, &LuaValue)) {
1415 let inner = self.inner.borrow();
1416 for (i, v) in inner.array.iter().enumerate() {
1417 if !matches!(v, LuaValue::Nil) {
1418 let k = LuaValue::Int((i + 1) as i64);
1419 f(&k, v);
1420 }
1421 }
1422 for node in inner.node.iter() {
1423 if !matches!(node.value, LuaValue::Nil) {
1424 f(&node.key, &node.value);
1425 }
1426 }
1427 }
1428
1429 pub fn prune_weak_dead(&self, is_reachable: &dyn Fn(usize) -> bool) -> Vec<LuaValue> {
1433 let mode = self.weak_mode.get();
1434 if mode == 0 { return Vec::new(); }
1435 let weak_k = (mode & WEAK_KEYS) != 0;
1436 let weak_v = (mode & WEAK_VALUES) != 0;
1437 let mut to_mark: Vec<LuaValue> = Vec::new();
1438 let mut inner = self.inner.borrow_mut();
1439 for i in 0..inner.array.len() {
1440 let v = inner.array[i].clone();
1441 if matches!(v, LuaValue::Nil) { continue; }
1442 if weak_v && value_is_dead_collectable(&v, is_reachable) {
1443 inner.array[i] = LuaValue::Nil;
1444 continue;
1445 }
1446 if weak_v {
1447 if matches!(v, LuaValue::Str(_)) { to_mark.push(v); }
1448 }
1449 }
1450 let mut i = 0;
1451 while i < inner.node.len() {
1452 let v = inner.node[i].value.clone();
1453 if matches!(v, LuaValue::Nil) {
1454 i += 1;
1455 continue;
1456 }
1457 let k = inner.node[i].key.clone();
1458 if weak_v && value_is_dead_collectable(&v, is_reachable) {
1459 inner.clear_dead_hash_node(i);
1460 continue;
1461 }
1462 if weak_k && value_is_dead_collectable(&k, is_reachable) {
1463 inner.clear_dead_hash_node(i);
1464 continue;
1465 }
1466 if weak_k {
1467 if matches!(k, LuaValue::Str(_)) { to_mark.push(k); }
1468 }
1469 if weak_v {
1470 if matches!(v, LuaValue::Str(_)) { to_mark.push(v); }
1471 }
1472 i += 1;
1473 }
1474 to_mark
1475 }
1476
1477 pub fn ephemeron_values_to_mark(&self, is_reachable: &dyn Fn(usize) -> bool) -> Vec<LuaValue> {
1479 let mode = self.weak_mode.get();
1480 if (mode & WEAK_KEYS) == 0 || (mode & WEAK_VALUES) != 0 {
1481 return Vec::new();
1482 }
1483 let inner = self.inner.borrow();
1484 let mut out = Vec::new();
1485 for node in inner.node.iter() {
1486 if matches!(node.value, LuaValue::Nil) { continue; }
1487 if !value_is_dead_collectable(&node.key, is_reachable) {
1488 out.push(node.value.clone());
1489 }
1490 }
1491 for (i, v) in inner.array.iter().enumerate() {
1492 if matches!(v, LuaValue::Nil) { continue; }
1493 let k = LuaValue::Int((i + 1) as i64);
1494 if !value_is_dead_collectable(&k, is_reachable) {
1495 out.push(v.clone());
1496 }
1497 }
1498 out
1499 }
1500}
1501
1502fn value_is_dead_collectable(v: &LuaValue, is_reachable: &dyn Fn(usize) -> bool) -> bool {
1507 match v {
1508 LuaValue::Table(t) => !is_reachable(t.identity()),
1509 LuaValue::UserData(u) => !is_reachable(u.identity()),
1510 LuaValue::Thread(th) => !is_reachable(th.identity()),
1511 LuaValue::Function(c) => match c {
1512 LuaClosure::Lua(x) => !is_reachable(x.identity()),
1513 LuaClosure::C(x) => !is_reachable(x.identity()),
1514 LuaClosure::LightC(_) => false,
1515 },
1516 LuaValue::Str(_)
1517 | LuaValue::Nil
1518 | LuaValue::Bool(_)
1519 | LuaValue::Int(_)
1520 | LuaValue::Float(_)
1521 | LuaValue::LightUserData(_) => false,
1522 }
1523}
1524
1525fn extract_weak_mode(mt: &LuaTable) -> u8 {
1529 let inner = mt.inner.borrow();
1530 for node in inner.node.iter() {
1531 if let LuaValue::Str(ks) = &node.key {
1532 if ks.as_bytes() == b"__mode" {
1533 if let LuaValue::Str(vs) = &node.value {
1534 let bytes = vs.as_bytes();
1535 let mut mode = 0u8;
1536 if bytes.iter().any(|b| *b == b'k') { mode |= WEAK_KEYS; }
1537 if bytes.iter().any(|b| *b == b'v') { mode |= WEAK_VALUES; }
1538 return mode;
1539 }
1540 return 0;
1541 }
1542 }
1543 }
1544 0
1545}
1546
1547