mod actual_listings; pub mod area_crime_averages; pub mod crime_by_year; pub mod crime_records; mod developments; mod places; mod poi; pub mod postcode_population; mod postcodes; mod property; pub mod spill; pub mod travel_time; /// Apostrophe-like code points that should be elided (not treated as word breaks) when /// normalizing search text. Keyboards, autocorrect and copy-paste all produce different glyphs /// for what users mean as an apostrophe; treating any of them as a separator turns "King's Cross" /// into the tokens `king s cross` and breaks matching. Covers the straight ASCII apostrophe, the /// typographic left/right single quotes, grave/acute accents, the modifier-letter apostrophes, /// prime, and the fullwidth apostrophe. pub(crate) fn is_apostrophe(ch: char) -> bool { matches!( ch, '\u{0027}' // ' APOSTROPHE | '\u{0060}' // ` GRAVE ACCENT | '\u{00B4}' // ´ ACUTE ACCENT | '\u{02B9}' // ʹ MODIFIER LETTER PRIME | '\u{02BB}' // ʻ MODIFIER LETTER TURNED COMMA (ʻokina) | '\u{02BC}' // ʼ MODIFIER LETTER APOSTROPHE | '\u{2018}' // ' LEFT SINGLE QUOTATION MARK | '\u{2019}' // ' RIGHT SINGLE QUOTATION MARK | '\u{201B}' // ‛ SINGLE HIGH-REVERSED-9 QUOTATION MARK | '\u{2032}' // ′ PRIME | '\u{FF07}' // ' FULLWIDTH APOSTROPHE ) } fn panic_payload_message(payload: &(dyn std::any::Any + Send)) -> String { if let Some(message) = payload.downcast_ref::<&'static str>() { (*message).to_string() } else if let Some(message) = payload.downcast_ref::() { message.clone() } else { "unknown panic payload".to_string() } } pub(super) fn run_polars_io(work: F) -> anyhow::Result where T: Send, F: FnOnce() -> anyhow::Result + Send, { if tokio::runtime::Handle::try_current().is_err() { return work(); } std::thread::scope(|scope| { scope.spawn(work).join().map_err(|payload| { anyhow::anyhow!( "Polars worker thread panicked: {}", panic_payload_message(payload.as_ref()) ) })? }) } pub use actual_listings::{ActualListing, ActualListingData}; pub use area_crime_averages::AreaCrimeAverages; pub use crime_by_year::CrimeByYearData; pub use crime_records::CrimeRecords; pub use developments::{DevelopmentData, DevelopmentSite}; pub use places::{ compute_trigrams, normalize_search_text, place_alias_tokens, trigram_similarity, PlaceData, }; pub use poi::{resolve_poi_category_filter, POICategoryGroup, POIData, SchoolMetadata}; pub use postcode_population::PostcodePopulation; pub use postcodes::{OutcodeData, PostcodeData}; pub use property::{ combine_nearest_distances, combined_station_feature_name, combined_station_source_feature_names, precompute_h3, FeatureStats, Histogram, HistoricalPrice, PostcodePoiMetrics, PropertyData, QuantRef, RenovationEvent, TenureEvent, COMBINED_STATION_CATEGORY, }; pub use travel_time::{slugify, TravelTimeStore};