Skip to main content

luaur_analysis/functions/
is_string.rs

1use crate::functions::follow_type::follow_type_id;
2use crate::functions::get_type_alt_j::get_type_id;
3use crate::functions::is_prim::is_prim;
4use crate::records::primitive_type::PrimitiveType;
5use crate::records::singleton_type::SingletonType;
6use crate::records::string_singleton::StringSingleton;
7use crate::records::type_iterator::TypeIterator;
8use crate::records::union_type::UnionType;
9use crate::type_aliases::singleton_variant::SingletonVariantMember;
10use crate::type_aliases::type_id::TypeId;
11
12pub fn is_string(ty: TypeId) -> bool {
13    unsafe {
14        let ty = follow_type_id(ty);
15
16        if is_prim(ty, PrimitiveType::String) {
17            return true;
18        }
19
20        let st = get_type_id::<SingletonType>(ty);
21        if !st.is_null() {
22            let st = &*st;
23            if StringSingleton::get_if(&st.variant).is_some() {
24                return true;
25            }
26        }
27
28        let utv = get_type_id::<UnionType>(ty);
29        if !utv.is_null() {
30            // C++ `std::all_of(begin(utv), end(utv), isString)` — iterate via the
31            // UnionTypeIterator, which follows + flattens nested unions and carries
32            // a seen-set to skip cycles. A raw recursion over `utv.options` stack-
33            // overflows on a structurally self-referential union.
34            let mut it = TypeIterator::<UnionType>::type_iterator_type(utv as *const UnionType);
35            let end_it = TypeIterator::<UnionType>::type_iterator_default();
36            while it.operator_ne(&end_it) {
37                let option = it.operator_deref();
38                it.operator_inc();
39                if !is_string(option) {
40                    return false;
41                }
42            }
43            return true;
44        }
45
46        false
47    }
48}