use crate::Sealed;
#[cfg(feature = "case-fold")]
mod fold;
#[cfg(feature = "perf-case-map")]
mod map;
pub trait CharCaseExt: Sealed {
fn to_mono_lowercase(self) -> char;
fn to_simple_or_ascii_fold_case(self) -> char;
#[cfg(feature = "case-fold")]
fn to_simple_fold_case(self) -> char;
#[cfg(feature = "bench")]
fn to_simple_fold_case_unicase(self) -> char;
#[cfg(feature = "bench")]
fn to_simple_fold_case_map(self) -> char;
}
impl CharCaseExt for char {
fn to_mono_lowercase(self) -> char {
#[cfg(not(feature = "perf-case-map"))]
return self.to_lowercase().next().unwrap();
#[cfg(feature = "perf-case-map")]
map::to_mono_lowercase(self)
}
fn to_simple_or_ascii_fold_case(self) -> char {
#[cfg(not(feature = "case-fold"))]
return self.to_ascii_lowercase();
#[cfg(feature = "case-fold")]
self.to_simple_fold_case()
}
#[cfg(feature = "case-fold")]
fn to_simple_fold_case(self) -> char {
#[cfg(not(feature = "perf-case-fold"))]
return fold::unicase::fold(self);
#[cfg(feature = "perf-case-fold")]
fold::map::fold(self)
}
#[cfg(feature = "bench")]
fn to_simple_fold_case_unicase(self) -> char {
fold::unicase::fold(self)
}
#[cfg(feature = "bench")]
fn to_simple_fold_case_map(self) -> char {
fold::map::fold(self)
}
}
pub trait StrCaseExt: Sealed {
fn to_mono_lowercase(&self) -> String;
fn to_simple_or_ascii_fold_case(&self) -> String;
#[cfg(feature = "case-fold")]
fn to_simple_fold_case(&self) -> String;
}
impl StrCaseExt for str {
fn to_mono_lowercase(&self) -> String {
self.chars().map(|c| c.to_mono_lowercase()).collect()
}
fn to_simple_or_ascii_fold_case(&self) -> String {
self.chars()
.map(|c| c.to_simple_or_ascii_fold_case())
.collect()
}
#[cfg(feature = "case-fold")]
fn to_simple_fold_case(&self) -> String {
self.chars().map(|c| c.to_simple_fold_case()).collect()
}
}
#[cfg(test)]
mod tests {
use std::collections::HashSet;
use super::*;
fn mono_set() -> HashSet<char> {
let mut chars = HashSet::new();
for c in 'A'..='Z' {
chars.insert(c);
chars.insert(c.to_ascii_lowercase());
}
for (c, map) in map::tests::LOWERCASE_TABLE {
chars.insert(*c);
chars.insert(char::from_u32(*map).unwrap_or('i'));
}
chars
}
#[test]
fn mono() {
let mono = mono_set();
println!("{} chars", mono.len());
println!("{} upper chars", 26 + map::tests::LOWERCASE_TABLE.len());
}
}
#[cfg(all(not(feature = "doc"), feature = "_test_data"))]
mod tests_data {
use std::collections::HashSet;
include!("../../data/case-folding-simple-chars-all-pairs.rs");
fn regex_set() -> HashSet<char> {
let mut chars = HashSet::new();
for (c, maps) in CASE_FOLDING_SIMPLE {
chars.insert(*c);
for c in maps.iter() {
chars.insert(*c);
}
}
chars
}
#[test]
fn regex() {
let regex = regex_set();
println!("{} chars", regex.len());
}
#[test]
fn mono_sub_regex() {
let regex = regex_set();
let mut chars = HashSet::new();
for (c, map) in map::tests::LOWERCASE_TABLE {
if !regex.contains(c) {
chars.insert(*c);
}
let map = char::from_u32(*map).unwrap_or('i');
if !regex.contains(&map) {
chars.insert(map);
}
}
println!("{} chars", chars.len());
println!("{:?}", chars);
}
#[test]
fn regex_sub_mono() {
let mono = mono_set();
let mut chars = HashSet::new();
let mut multicase = HashSet::new();
for (c, maps) in CASE_FOLDING_SIMPLE {
let set = if maps.len() > 1 {
&mut multicase
} else {
&mut chars
};
if !mono.contains(c) {
set.insert(*c);
}
for c in maps.iter() {
if !mono.contains(c) {
set.insert(*c);
}
}
}
println!("{} chars", chars.len());
println!("{} multicase chars", multicase.len());
println!("{:?}", chars);
println!("{:?}", multicase);
}
}