1#![forbid(unsafe_code)]
7#![warn(missing_docs)]
8#![warn(unreachable_pub)]
9
10mod builtin;
11mod error;
12mod grapheme;
13mod pattern;
14mod rasm;
15mod resolve;
16
17#[cfg(test)]
18mod tests;
19
20pub use builtin::{builtin_pattern_set, builtin_pattern_set_names, is_builtin_pattern_set};
21pub use error::{CompileError, CompileErrorKind};
22pub use pattern::{compile_pattern_text, PatternSet};
23
24use grapheme::{is_bare_tatweel_at, joined_runs, split_graphemes, KASHIDA};
25use resolve::resolve_run;
26
27#[derive(Clone, Copy, Debug, PartialEq, Eq)]
29pub struct KashidaPoint {
30 pub index: u32,
32 pub priority: u8,
35}
36
37pub fn find_kashida_points_patterns(word: &str, set: &PatternSet) -> Vec<KashidaPoint> {
39 let graphemes = split_graphemes(word);
40 let mut out = Vec::new();
41 for run in joined_runs(&graphemes) {
42 out.extend(resolve_run(&graphemes, &run, set));
43 }
44 out
45}
46
47fn strip_bare_tatweel(word: &str) -> String {
48 if !word.contains(KASHIDA) {
49 return word.to_string();
50 }
51 let chars: Vec<char> = word.chars().collect();
52 let mut out = String::with_capacity(word.len());
53 for k in 0..chars.len() {
54 if is_bare_tatweel_at(&chars, k) {
55 continue;
56 }
57 out.push(chars[k]);
58 }
59 out
60}
61
62pub fn find_kashida_points(
84 word: &str,
85 set: &PatternSet,
86 remove_existing_kashida: bool,
87) -> (String, Vec<KashidaPoint>) {
88 let cleaned = if remove_existing_kashida {
89 strip_bare_tatweel(word)
90 } else {
91 word.to_string()
92 };
93 let points = find_kashida_points_patterns(&cleaned, set);
94 (cleaned, points)
95}