Skip to main content

luaur_ast/methods/
ast_expr_table_get_record.rs

1//! `AstExprTable::getRecord` (`Ast/src/Ast.cpp:396`).
2//!
3//! Returns the value expr of the `Record` item whose key string equals `key`
4//! (a nul-terminated C string). C++: `strcmp(item.key->as<AstExprConstantString>
5//! ()->value.data, key) == 0`. `value` is a `char` (byte) array; the Rust record
6//! models it as `AstArray<char>`, so we compare each scalar's low byte against
7//! `key`'s bytes up to its nul terminator.
8
9use crate::records::ast_expr::AstExpr;
10use crate::records::ast_expr_constant_string::AstExprConstantString;
11use crate::records::ast_expr_table::{AstExprTable, ItemKind};
12use crate::records::ast_node::AstNode;
13
14impl AstExprTable {
15    pub fn get_record(&self, key: *const core::ffi::c_char) -> Option<*mut AstExpr> {
16        for item in self.items.iter() {
17            if item.kind == ItemKind::Record {
18                let string_expr = unsafe {
19                    crate::rtti::ast_node_as::<AstExprConstantString>(item.key as *mut AstNode)
20                };
21                if !string_expr.is_null() {
22                    let value = unsafe { (*string_expr).value };
23                    if char_array_eq_cstr(value.as_slice(), key) {
24                        return Some(item.value);
25                    }
26                }
27            }
28        }
29        None
30    }
31}
32
33/// `strcmp(value.data, key) == 0` where `value` is a (non-nul-terminated) byte
34/// array stored as `char`s and `key` is a nul-terminated C string.
35fn char_array_eq_cstr(value: &[core::ffi::c_char], key: *const core::ffi::c_char) -> bool {
36    let mut i = 0usize;
37    loop {
38        let k = unsafe { *key.add(i) } as u8;
39        if k == 0 {
40            return i == value.len();
41        }
42        if i >= value.len() || (value[i] as u32) != k as u32 {
43            return false;
44        }
45        i += 1;
46    }
47}