From cd46c4c2713b03e8f89c47dc3e64446293c725e5 Mon Sep 17 00:00:00 2001 From: Robert M1 <50460704+githubrobbi@users.noreply.github.com> Date: Sun, 19 Jul 2026 23:14:02 -0700 Subject: [PATCH] feat(core): expose apply_search_filters as a public API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flips apply_search_filters from pub(crate) to pub, plus an explicit pub use re-export (the containing apply module stays private via a pub(crate) glob for everything else in it — row_passes_filters, apply_derived_filters — which are staying internal helpers). This is a visibility change only, exposing a function, not new data: SearchFilters and DisplayRow are already fully public types with their whole field list visible in source today. What's new is the ability to call the existing ~20-axis filter-matching engine from outside uffs-core at all. Motivating use case: a private downstream crate (uffs-index-private, in the uffs-products repo — see PRIVATE_RICH_INDEX_DESIGN.md there) wants to carry more fields per record than the public CompactRecord does (ChangeTime, USN, security_id, owner_id — all already parsed by uffs-mft's StandardInfo today, just unused downstream), without growing the public struct's per-record cost for every UFFS user. It builds its own richer record type, adapts the overlapping fields into a DisplayRow via DisplayRow::new (already a public constructor taking only plain data), and now can run the whole existing filter engine against it unchanged instead of forking or reimplementing it — then applies its own small extra-fields filter pass on top for whatever DisplayRow doesn't carry. Verified: cargo doc confirms the item is genuinely externally reachable at uffs_core::search::filters::apply_search_filters (not just visible in source); fmt/lint-prod/lint-tests/tests all clean. --- crates/uffs-core/src/search/filters/apply.rs | 16 ++++++++++++++-- crates/uffs-core/src/search/filters/mod.rs | 5 +++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/crates/uffs-core/src/search/filters/apply.rs b/crates/uffs-core/src/search/filters/apply.rs index 28285b4bb..835dbf053 100644 --- a/crates/uffs-core/src/search/filters/apply.rs +++ b/crates/uffs-core/src/search/filters/apply.rs @@ -137,8 +137,20 @@ pub(crate) fn row_passes_filters( apply_derived_filters(row, filters) } -/// Apply extended search filters to display rows (in-place). -pub(crate) fn apply_search_filters(rows: &mut Vec, filters: &SearchFilters) { +/// Apply extended search filters to display rows (in-place) — retains +/// only the rows that pass every non-empty filter in `filters`. +/// +/// Public so a downstream crate holding its own richer row data (more +/// fields than [`DisplayRow`] carries) can still reuse this entire +/// filter engine unchanged: build a [`DisplayRow`] via its public +/// [`DisplayRow::new`] constructor from whatever subset of fields +/// overlaps, run it through this function to get every existing filter +/// axis applied verbatim, then apply any additional filters the extra +/// fields need as a separate, small pass of its own. This avoids +/// forking or reimplementing this engine for that case — see +/// `PRIVATE_RICH_INDEX_DESIGN.md` in the `uffs-products` repo for the +/// concrete motivating use case. +pub fn apply_search_filters(rows: &mut Vec, filters: &SearchFilters) { if filters.is_empty() { return; } diff --git a/crates/uffs-core/src/search/filters/mod.rs b/crates/uffs-core/src/search/filters/mod.rs index f3e20c225..286654d19 100644 --- a/crates/uffs-core/src/search/filters/mod.rs +++ b/crates/uffs-core/src/search/filters/mod.rs @@ -18,6 +18,11 @@ mod ext_match; mod path_normalize; mod time_parsing; +// `apply_search_filters` is a deliberately public re-export — see its +// own doc comment for why a downstream crate needs to call it directly. +// The `apply::*` glob below stays `pub(crate)`: everything else in +// `apply` (e.g. `row_passes_filters`) is an internal helper. +pub use apply::apply_search_filters; pub(crate) use apply::*; pub use attr_parsing::*; pub(crate) use ext_match::extract_extension_after_dot;