Skip to main content

luaur_vm/functions/
lua_h_getn.rs

1use crate::functions::lua_h_getnum::lua_h_getnum;
2use crate::macros::dummynode::dummynode;
3use crate::macros::getaboundary::getaboundary;
4use crate::macros::ttisnil::ttisnil;
5use crate::records::lua_node::LuaNode;
6use crate::records::lua_table::LuaTable;
7use crate::type_aliases::t_value::TValue;
8use core::ffi::c_int;
9use luaur_common::macros::luau_assert::LUAU_ASSERT;
10
11#[inline]
12unsafe fn maybesetaboundary(t: *mut LuaTable, boundary: c_int) {
13    if (*t).union.aboundary <= 0 {
14        (*t).union.aboundary = -boundary;
15    }
16}
17
18unsafe fn updateaboundary(t: *mut LuaTable, boundary: c_int) -> c_int {
19    if boundary < (*t).sizearray && ttisnil!((*t).array.add((boundary - 1) as usize)) {
20        if boundary >= 2 && !ttisnil!((*t).array.add((boundary - 2) as usize)) {
21            maybesetaboundary(t, boundary - 1);
22            return boundary - 1;
23        }
24    } else if boundary + 1 < (*t).sizearray
25        && !ttisnil!((*t).array.add(boundary as usize))
26        && ttisnil!((*t).array.add((boundary + 1) as usize))
27    {
28        maybesetaboundary(t, boundary + 1);
29        return boundary + 1;
30    }
31
32    0
33}
34
35#[allow(non_snake_case)]
36pub unsafe fn lua_h_getn(t: *mut LuaTable) -> c_int {
37    let boundary = getaboundary(t);
38
39    if boundary > 0 {
40        if !ttisnil!((*t).array.add(((*t).sizearray - 1) as usize))
41            && (*t).node == dummynode as *mut LuaNode
42        {
43            return (*t).sizearray;
44        }
45
46        if boundary < (*t).sizearray
47            && !ttisnil!((*t).array.add((boundary - 1) as usize))
48            && ttisnil!((*t).array.add(boundary as usize))
49        {
50            return boundary;
51        }
52
53        let foundboundary = updateaboundary(t, boundary);
54        if foundboundary > 0 {
55            return foundboundary;
56        }
57    }
58
59    let j = (*t).sizearray;
60
61    if j > 0 && ttisnil!((*t).array.add((j - 1) as usize)) {
62        let mut base: *mut TValue = (*t).array;
63        let mut rest = j;
64
65        while rest >> 1 != 0 {
66            let half = rest >> 1;
67            if !ttisnil!(base.add(half as usize)) {
68                base = base.add(half as usize);
69            }
70            rest -= half;
71        }
72
73        let boundary = if !ttisnil!(base) { 1 } else { 0 } + base.offset_from((*t).array) as c_int;
74        maybesetaboundary(t, boundary);
75        boundary
76    } else {
77        LUAU_ASSERT!((*t).node == dummynode as *mut LuaNode || ttisnil!(lua_h_getnum(t, j + 1)));
78        j
79    }
80}
81
82#[export_name = "luaH_getn"]
83pub unsafe extern "C" fn lua_h_getn_export(t: *mut core::ffi::c_void) -> c_int {
84    lua_h_getn(t as *mut LuaTable)
85}
86
87#[allow(unused_imports)]
88pub use lua_h_getn as luaH_getn;