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