Skip to main content

luaur_common/methods/
f_value_version_setter_f_value_version_setter.rs

1//! `FValueVersionSetter::FValueVersionSetter(const char* name, unsigned version)`.
2//! Reference: `luau/Common/include/Luau/Common.h`. Walks the `bool` and `int`
3//! flag lists, stamping `version` onto every flag whose name matches, and asserts
4//! at least one did (the `LUAU_FLAGVERSION` "must appear after the flag
5//! definition" guard).
6
7use core::ffi::{c_char, c_uint};
8use core::sync::atomic::Ordering;
9
10use crate::records::f_value::{FValue, FValueList};
11use crate::records::f_value_version_setter::FValueVersionSetter;
12
13impl FValueVersionSetter {
14    /// # Safety
15    /// Walks the global flag lists via raw pointers; call after the named flag's
16    /// `register()` (the C++ macro guarantees this ordering within a source file).
17    pub unsafe fn new(name: *const c_char, version: c_uint) -> Self {
18        debug_assert!(version != 0, "LUAU_FLAGVERSION version cannot be 0");
19        let mut found = false;
20
21        let mut p = <bool as FValueList>::head().load(Ordering::Relaxed) as *const FValue<bool>;
22        while !p.is_null() {
23            if cstr_eq((*p).name, name) {
24                (*p).set_version(version);
25                found = true;
26            }
27            p = *(*p).next.get();
28        }
29
30        let mut q = <i32 as FValueList>::head().load(Ordering::Relaxed) as *const FValue<i32>;
31        while !q.is_null() {
32            if cstr_eq((*q).name, name) {
33                (*q).set_version(version);
34                found = true;
35            }
36            q = *(*q).next.get();
37        }
38
39        debug_assert!(
40            found,
41            "LUAU_FLAGVERSION must appear after the flag definition in the same source file"
42        );
43
44        FValueVersionSetter
45    }
46}
47
48/// `strcmp(a, b) == 0` on nul-terminated C strings.
49unsafe fn cstr_eq(a: *const c_char, b: *const c_char) -> bool {
50    let mut i = 0isize;
51    loop {
52        let ca = *a.offset(i);
53        let cb = *b.offset(i);
54        if ca != cb {
55            return false;
56        }
57        if ca == 0 {
58            return true;
59        }
60        i += 1;
61    }
62}