@@ -337,18 +337,27 @@ fn platform_default_data_dir(environment: &dyn Environment) -> Option<PathBuf> {
337337fn match_default_storage_layout ( prefix : & Path , storage : & Path ) -> Option < String > {
338338 let normalized = norm_case ( prefix) ;
339339 let rel = normalized. strip_prefix ( storage) . ok ( ) ?;
340- let parts: Vec < _ > = rel. iter ( ) . collect ( ) ;
341- if parts. len ( ) == 3 {
342- Some ( parts[ 2 ] . to_string_lossy ( ) . to_string ( ) )
343- } else {
344- None
340+ // Iterate components directly to avoid a per-call Vec allocation on the
341+ // identification hot path. We need exactly three components.
342+ let mut iter = rel. iter ( ) ;
343+ let _project_name = iter. next ( ) ?;
344+ let _project_id = iter. next ( ) ?;
345+ let venv_name = iter. next ( ) ?;
346+ if iter. next ( ) . is_some ( ) {
347+ return None ;
345348 }
349+ Some ( venv_name. to_string_lossy ( ) . to_string ( ) )
346350}
347351
348352/// True iff `prefix`'s parent equals `dir` (case-insensitive on Windows).
353+ ///
354+ /// `dir` is expected to be already normalized via `norm_case()` (entries
355+ /// cached in `resolve_project_virtual_dirs()` always are), so we only
356+ /// normalize `prefix.parent()` here — avoiding redundant `GetLongPathNameW`
357+ /// / case-folding work on Windows in the identification hot path.
349358fn prefix_is_directly_under ( prefix : & Path , dir : & Path ) -> bool {
350359 match prefix. parent ( ) {
351- Some ( parent) => norm_case ( parent) == norm_case ( dir) ,
360+ Some ( parent) => norm_case ( parent) == dir,
352361 None => false ,
353362 }
354363}
0 commit comments