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