Skip to main content

luaur_analysis/functions/
filter_map.rs

1use crate::functions::follow_type::follow_type_id;
2use crate::functions::get_type_alt_j::get_type_id;
3use crate::records::union_type::UnionType;
4use crate::type_aliases::type_id::TypeId;
5use crate::type_aliases::type_id_predicate::TypeIdPredicate;
6use alloc::vec::Vec;
7
8pub fn filter_map(type_: TypeId, predicate: TypeIdPredicate) -> Vec<TypeId> {
9    let type_ = unsafe { follow_type_id(type_) };
10
11    unsafe {
12        if !get_type_id::<UnionType>(type_).is_null() {
13            let utv = get_type_id::<UnionType>(type_);
14            // Dedupe while preserving the union's option order. The C++ original
15            // uses `std::set<TypeId>` (ordered by pointer address — deterministic
16            // within a run but ASLR-dependent across runs); a `HashSet<TypeId>`
17            // iterates in per-instance RandomState order, making the resulting
18            // union's option order — and every diagnostic derived from it —
19            // nondeterministic even within a single process. Insertion-order
20            // dedup is fully deterministic and keeps diagnostics stable.
21            let mut options: Vec<TypeId> = Vec::new();
22
23            for &option in (*utv).options.iter() {
24                let followed_option = follow_type_id(option);
25                if let Some(out) = predicate(followed_option) {
26                    if !options.contains(&out) {
27                        options.push(out);
28                    }
29                }
30            }
31
32            options
33        } else if let Some(out) = predicate(type_) {
34            vec![out]
35        } else {
36            Vec::new()
37        }
38    }
39}