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