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