#![allow(dead_code)]
#[derive(Clone, Copy, Debug)]
pub struct UnicodeFixture {
pub label: &'static str,
pub text: &'static str,
pub byte_len: usize,
pub char_count: usize,
pub grapheme_count: usize,
}
const fn fixture(
label: &'static str,
text: &'static str,
byte_len: usize,
char_count: usize,
grapheme_count: usize,
) -> UnicodeFixture {
UnicodeFixture {
label,
text,
byte_len,
char_count,
grapheme_count,
}
}
pub const CORPUS: &[UnicodeFixture] = &[
fixture("ascii_baseline", "hello world", 11, 11, 11),
fixture("accented_latin", "café", 5, 4, 4),
fixture("accented_words", "naïve résumé", 15, 12, 12),
fixture("cyrillic", "Привет мир", 19, 10, 10),
fixture("greek_final_sigma", "ΟΔΟΣ", 8, 4, 4),
fixture("turkish_dotted_i", "İstanbul", 9, 8, 8),
fixture("cjk", "日本語", 9, 3, 3),
fixture("cjk_mixed_ascii", "日本語 test", 14, 8, 8),
fixture("hangul", "한글 텍스트", 16, 6, 6),
fixture("emoji", "😀", 4, 1, 1),
fixture("emoji_run", "😀😁😂", 12, 3, 3),
fixture(
"emoji_zwj_family",
"\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}",
18,
5,
1,
),
fixture("emoji_skin_tone", "\u{1F44D}\u{1F3FD}", 8, 2, 1),
fixture("flag_emoji", "\u{1F1EF}\u{1F1F5}", 8, 2, 1),
fixture("combining_mark", "e\u{0301}", 3, 2, 1),
fixture("combining_in_word", "cafe\u{0301}", 6, 5, 4),
fixture("rtl_arabic", "مرحبا", 10, 5, 5),
fixture("rtl_hebrew", "שלום", 8, 4, 4),
fixture("zero_width_space", "a\u{200B}b", 5, 3, 3),
fixture("zero_width_joiner", "a\u{200D}b", 5, 3, 2),
fixture("curly_quotes", "\u{201C}x\u{201D}", 7, 3, 3),
fixture("mixed_scripts", "a日b😀c", 10, 5, 5),
];
pub const WIDE_FIXTURES: &[&str] = &["日本語", "한글", "中文字"];
pub fn multi_scalar_graphemes() -> impl Iterator<Item = &'static UnicodeFixture> {
CORPUS
.iter()
.filter(|fixture| fixture.grapheme_count < fixture.char_count)
}
pub fn non_ascii() -> impl Iterator<Item = &'static UnicodeFixture> {
CORPUS.iter().filter(|fixture| !fixture.text.is_ascii())
}
pub struct Lcg(u64);
impl Lcg {
pub fn new(seed: u64) -> Self {
Self(seed)
}
pub fn next_u64(&mut self) -> u64 {
self.0 = self
.0
.wrapping_mul(6_364_136_223_846_793_005)
.wrapping_add(1_442_695_040_888_963_407);
self.0
}
pub fn below(&mut self, len: usize) -> usize {
if len == 0 {
return 0;
}
(self.next_u64() >> 33) as usize % len
}
pub fn pick<'a, T>(&mut self, items: &'a [T]) -> &'a T {
&items[self.below(items.len())]
}
pub fn corpus_string(&mut self, max_atoms: usize) -> String {
let count = 1 + self.below(max_atoms);
let mut text = String::new();
for _ in 0..count {
text.push_str(self.pick(CORPUS).text);
}
text
}
}