location.rs (1977B)
1 pub const RADROOTS_PUBLIC_GEOHASH_PRECISION: usize = 5; 2 pub const RADROOTS_PUBLIC_GEOHASH_BASE32: &str = "0123456789bcdefghjkmnpqrstuvwxyz"; 3 4 pub fn is_public_geohash5(value: &str) -> bool { 5 let value = value.trim(); 6 value.len() == RADROOTS_PUBLIC_GEOHASH_PRECISION 7 && value.bytes().all(|byte| { 8 RADROOTS_PUBLIC_GEOHASH_BASE32 9 .as_bytes() 10 .contains(&byte.to_ascii_lowercase()) 11 }) 12 } 13 14 pub fn has_textual_locality( 15 primary: &str, 16 city: Option<&str>, 17 region: Option<&str>, 18 country: Option<&str>, 19 ) -> bool { 20 has_public_location_text(primary) 21 && [city, region, country] 22 .into_iter() 23 .flatten() 24 .any(has_public_location_text) 25 } 26 27 fn has_public_location_text(value: &str) -> bool { 28 let value = value.trim(); 29 !value.is_empty() && !value.eq_ignore_ascii_case("null") 30 } 31 32 #[cfg(test)] 33 #[cfg_attr(coverage_nightly, coverage(off))] 34 mod tests { 35 use super::*; 36 37 #[test] 38 fn public_geohash5_accepts_base32_prefix_and_trims_input() { 39 assert!(is_public_geohash5(" 9q8yy ")); 40 assert!(is_public_geohash5("9Q8YY")); 41 assert!(!is_public_geohash5("9q8y")); 42 assert!(!is_public_geohash5("9q8yyz")); 43 assert!(!is_public_geohash5("9q8ya")); 44 } 45 46 #[test] 47 fn textual_locality_requires_primary_and_one_public_component() { 48 assert!(has_textual_locality( 49 "Market shed", 50 Some("Asheville"), 51 None, 52 None 53 )); 54 assert!(has_textual_locality( 55 "Market shed", 56 Some("null"), 57 Some("NC"), 58 None 59 )); 60 assert!(!has_textual_locality("", Some("Asheville"), None, None)); 61 assert!(!has_textual_locality("Market shed", None, None, None)); 62 assert!(!has_textual_locality( 63 "Market shed", 64 Some("null"), 65 Some(" "), 66 None 67 )); 68 } 69 }