@@ -24,10 +24,10 @@ use uffs_core::{export_json, export_table};
2424pub ( super ) struct CppFooterContext < ' a > {
2525 /// Drive letters to include in the footer (e.g., `['C', 'D']`).
2626 pub ( super ) output_targets : & ' a [ char ] ,
27- /// Elapsed time since search started.
28- pub ( super ) elapsed : Duration ,
2927 /// Original search pattern string.
3028 pub ( super ) pattern : & ' a str ,
29+ /// Total result row count for fast-scan heuristic.
30+ pub ( super ) row_count : usize ,
3131}
3232
3333/// Streaming output writer for multi-drive search.
@@ -896,18 +896,20 @@ pub(super) fn write_results(
896896 out : & str ,
897897 output_config : & OutputConfig ,
898898 output_targets : & [ char ] ,
899- elapsed : Duration ,
899+ _elapsed : Duration ,
900900 pattern : & str ,
901901) -> Result < ( ) > {
902902 let is_console = matches ! (
903903 out. to_lowercase( ) . as_str( ) ,
904904 "console" | "con" | "term" | "terminal"
905905 ) ;
906906
907+ let row_count = results. height ( ) ;
908+
907909 let footer_ctx = CppFooterContext {
908910 output_targets,
909- elapsed,
910911 pattern,
912+ row_count,
911913 } ;
912914
913915 if is_console {
@@ -947,7 +949,7 @@ pub(super) fn write_results(
947949/// Append the legacy C++ drive footer for baseline-compatible custom output.
948950///
949951/// Uses CRLF line endings (`\r\n`) to match C++ baseline behavior.
950- /// When `elapsed ` is <= 1 second , appends the fast-scan message.
952+ /// When `row_count ` is < 20,000 , appends the fast-scan message.
951953fn write_cpp_drive_footer < W : Write > ( writer : & mut W , ctx : & CppFooterContext < ' _ > ) -> Result < ( ) > {
952954 if ctx. output_targets . is_empty ( ) {
953955 return Ok ( ( ) ) ;
@@ -963,7 +965,7 @@ fn write_cpp_drive_footer<W: Write>(writer: &mut W, ctx: &CppFooterContext<'_>)
963965 ) ?;
964966 write ! ( writer, "\r \n " ) ?;
965967
966- if ctx. elapsed . as_secs ( ) <= 1 {
968+ if ctx. row_count < 20_000 {
967969 write ! (
968970 writer,
969971 "MMMmmm that was FAST ... maybe your searchstring was wrong?\t {pattern}\r \n " ,
@@ -1018,6 +1020,24 @@ mod tests {
10181020 . map_err ( Into :: into)
10191021 }
10201022
1023+ /// Create a large sample DataFrame (20,000+ rows) for testing slow-scan footer.
1024+ fn large_sample_df ( ) -> Result < DataFrame > {
1025+ let count = 20_000 ;
1026+ let paths: Vec < String > = ( 0 ..count)
1027+ . map ( |i| format ! ( "C:\\ Temp\\ file{}.txt" , i) )
1028+ . collect ( ) ;
1029+ let names: Vec < String > = ( 0 ..count) . map ( |i| format ! ( "file{}.txt" , i) ) . collect ( ) ;
1030+
1031+ let path_refs: Vec < & str > = paths. iter ( ) . map ( |s| s. as_str ( ) ) . collect ( ) ;
1032+ let name_refs: Vec < & str > = names. iter ( ) . map ( |s| s. as_str ( ) ) . collect ( ) ;
1033+
1034+ DataFrame :: new_infer_height ( vec ! [
1035+ Column :: new( "path" . into( ) , & path_refs) ,
1036+ Column :: new( "name" . into( ) , & name_refs) ,
1037+ ] )
1038+ . map_err ( Into :: into)
1039+ }
1040+
10211041 fn sample_index ( ) -> MftIndex {
10221042 let mut index = MftIndex :: new ( 'C' ) ;
10231043 let root_name = index. add_name ( "." ) ;
@@ -1100,14 +1120,14 @@ mod tests {
11001120 format : & str ,
11011121 output_config : & OutputConfig ,
11021122 output_targets : & [ char ] ,
1103- elapsed : Duration ,
1123+ _elapsed : Duration ,
11041124 pattern : & str ,
11051125 ) -> Result < String > {
11061126 let mut output = Vec :: new ( ) ;
11071127 let footer_ctx = CppFooterContext {
11081128 output_targets,
1109- elapsed,
11101129 pattern,
1130+ row_count : results. height ( ) ,
11111131 } ;
11121132 match format {
11131133 "json" => export_json ( results, & mut output) ?,
@@ -1126,14 +1146,14 @@ mod tests {
11261146 format : & str ,
11271147 output_config : & OutputConfig ,
11281148 output_targets : & [ char ] ,
1129- elapsed : Duration ,
1149+ _elapsed : Duration ,
11301150 pattern : & str ,
11311151 ) -> Result < String > {
11321152 let mut output = Vec :: new ( ) ;
11331153 let footer_ctx = CppFooterContext {
11341154 output_targets,
1135- elapsed,
11361155 pattern,
1156+ row_count : results. len ( ) ,
11371157 } ;
11381158 write_native_results_to (
11391159 index,
@@ -1204,14 +1224,17 @@ mod tests {
12041224 let written = fs:: read_to_string ( & path) ?;
12051225 drop ( fs:: remove_file ( & path) ) ;
12061226
1227+ // With 1 row (< 20,000), should include fast-scan message
12071228 assert_eq ! (
12081229 written,
12091230 concat!(
12101231 "\" C:\\ Temp\\ file.txt\" ,\" file.txt\" \n " ,
12111232 "\r \n " ,
12121233 "\r \n " ,
12131234 "Drives? \t 2\t C:|D:\r \n " ,
1214- "\r \n "
1235+ "\r \n " ,
1236+ "MMMmmm that was FAST ... maybe your searchstring was wrong?\t *.txt\r \n " ,
1237+ "Search path. E.g. 'C:/' or 'C:\\ Prog**' \r \n "
12151238 )
12161239 ) ;
12171240 Ok ( ( ) )
@@ -1392,7 +1415,7 @@ mod tests {
13921415 #[ test]
13931416 fn test_cpp_footer_omits_fast_scan_message_when_elapsed_gt_1s ( ) -> TestResult {
13941417 let path = temp_output_path ( "txt" ) ;
1395- let results = sample_df ( ) ?;
1418+ let results = large_sample_df ( ) ?; // Use 20,000 rows to trigger slow scan
13961419 let output_config = OutputConfig :: new ( )
13971420 . with_columns ( "path,name" )
13981421 . with_header ( false ) ;
@@ -1410,16 +1433,14 @@ mod tests {
14101433 let written = fs:: read_to_string ( & path) ?;
14111434 drop ( fs:: remove_file ( & path) ) ;
14121435
1413- assert_eq ! (
1414- written,
1415- concat!(
1416- "\" C:\\ Temp\\ file.txt\" ,\" file.txt\" \n " ,
1417- "\r \n " ,
1418- "\r \n " ,
1419- "Drives? \t 1\t G:\r \n " ,
1420- "\r \n "
1421- )
1422- ) ;
1436+ // Should NOT contain fast-scan message (row_count >= 20,000)
1437+ // Only check footer structure - first row will be "C:\Temp\file0.txt","file0.txt"
1438+ let lines: Vec < & str > = written. lines ( ) . collect ( ) ;
1439+ let footer_start = lines. len ( ) . saturating_sub ( 4 ) ;
1440+ assert_eq ! ( lines[ footer_start] , "" ) ;
1441+ assert_eq ! ( lines[ footer_start + 1 ] , "" ) ;
1442+ assert_eq ! ( lines[ footer_start + 2 ] , "Drives? \t 1\t G:" ) ;
1443+ assert_eq ! ( lines[ footer_start + 3 ] , "" ) ;
14231444 Ok ( ( ) )
14241445 }
14251446}
0 commit comments