Build per-block PermCtx for the permutation-aware comparator. Mirrors `build_perm_ctx` in `rs_compile_validate_aux` below; kept as a local fn here so the `#[cfg(feature = "test-ffi")]` path doesn't escape its scope.
(
all: &[Name],
env: &Env,
stt: &ix_compile::compile::CompileState,
perm: &[usize],
)
| 1163 | /// `LeanBorrowed` accessors are refcount-silent, and each element's |
| 1164 | /// owned handle keeps its Lean objects alive for the `Env`'s lifetime |
| 1165 | /// regardless of what the Lean side does after the FFI call. |
| 1166 | pub fn decode_env_lazy( |
| 1167 | list: LeanList<LeanBorrowed<'_>>, |
| 1168 | cache_entries: usize, |
| 1169 | ) -> Env { |
| 1170 | let shared_list = LeanShared::new(list.inner().to_owned_ref()); |
| 1171 | let objs = collect_list_shared(shared_list.borrow().as_list()); |
| 1172 | let global = Arc::new(GlobalCache::with_capacity(objs.len() * 3)); |
| 1173 | |
| 1174 | // Name index (parallel; bodies untouched). Each element is a |
| 1175 | // `Prod (Name × ConstantInfo)` ctor — field 0 is the name. |
| 1176 | let named: Vec<(Name, LeanShared)> = objs |
| 1177 | .into_par_iter() |
| 1178 | .map(|o| { |
| 1179 | let name = decode_name(o.borrow().as_ctor().get(0), &global); |
| 1180 | (name, o) |
| 1181 | }) |
| 1182 | .collect(); |
| 1183 | let names: Vec<Name> = named.iter().map(|(n, _)| n.clone()).collect(); |
| 1184 | let handles: FxHashMap<Name, LeanShared> = named.into_iter().collect(); |
| 1185 | |
| 1186 | let fetch = move |name: &Name| { |
| 1187 | let obj = handles.get(name)?; |
| 1188 | let mut cache = Cache::new(&global); |
| 1189 | Some(decode_constant_info(obj.borrow().as_ctor().get(1), &mut cache)) |
| 1190 | }; |
| 1191 | Env::new_lazy(names, Box::new(fetch), cache_entries) |
| 1192 | } |
| 1193 | |
| 1194 | // Decode a Lean environment in parallel with hybrid caching. |
| 1195 | pub fn decode_env(list: LeanList<LeanBorrowed<'_>>) -> Env { |
| 1196 | // Phase 1: Mark entire list graph as MT, then collect elements as LeanShared. |
| 1197 | // lean_mark_mt recursively marks all reachable objects. Subsequent |
| 1198 | // LeanShared::new calls on elements are a fast no-op (single is_st check). |
| 1199 | let shared_list = LeanShared::new(list.inner().to_owned_ref()); |
| 1200 | let objs = collect_list_shared(shared_list.borrow().as_list()); |
| 1201 | |
| 1202 | if objs.len() < PARALLEL_THRESHOLD { |
| 1203 | // Sequential fallback for small environments — no MT overhead needed, |
| 1204 | // but objects are already marked. Just borrow directly. |
| 1205 | let global = GlobalCache::new(); |
| 1206 | let mut env = Env::default(); |
| 1207 | for o in &objs { |
| 1208 | let (name, constant_info) = |
| 1209 | decode_name_constant_info(o.borrow(), &global); |
| 1210 | env.insert(name, constant_info); |
| 1211 | } |
| 1212 | return env; |
| 1213 | } |
| 1214 | |
| 1215 | // Estimate: ~3 unique names per constant on average |
| 1216 | let global = GlobalCache::with_capacity(objs.len() * 3); |
| 1217 | |
| 1218 | // Phase 2: Decode in parallel with shared global name cache |
| 1219 | let pairs: Vec<(Name, ConstantInfo)> = objs |
| 1220 | .into_par_iter() |
| 1221 | .map(|shared| decode_name_constant_info(shared.borrow(), &global)) |
| 1222 | .collect(); |
no test coverage detected