msime_engine/stroke/
mod.rs1pub mod scheme;
6
7pub use scheme::{StrokeCandidate, StrokeScheme};
8
9pub const STROKES: &str = "hspnz";
11
12pub const WILDCARD: u8 = b'x';
14
15pub const MAX_STROKES: usize = 64;
17
18pub const fn is_stroke(key: u8) -> bool {
20 matches!(key, b'h' | b's' | b'p' | b'n' | b'z')
21}
22
23pub const fn is_key(key: u8) -> bool {
25 is_stroke(key) || key == WILDCARD
26}
27
28pub const fn glyph(key: u8) -> Option<char> {
30 match key {
31 b'h' => Some('一'),
32 b's' => Some('丨'),
33 b'p' => Some('丿'),
34 b'n' => Some('丶'),
35 b'z' => Some('乛'),
36 WILDCARD => Some('*'),
37 _ => None,
38 }
39}
40
41pub const fn key_of_glyph(glyph: char) -> Option<u8> {
43 match glyph {
44 '一' => Some(b'h'),
45 '丨' => Some(b's'),
46 '丿' => Some(b'p'),
47 '丶' => Some(b'n'),
48 '乛' => Some(b'z'),
49 '*' => Some(WILDCARD),
50 _ => None,
51 }
52}
53
54#[cfg(test)]
56pub(crate) mod fixture {
57 use std::path::Path;
58
59 use rusqlite::Connection;
60
61 use crate::language_dictionary::{
62 FORMAT_VERSION, METADATA_FORMAT_VERSION, METADATA_LICENSE, METADATA_SOURCE_COMMIT, SCHEMA,
63 };
64
65 pub(crate) const ENTRIES: [(&str, &str, i64); 12] = [
67 ("h", "一", 9000),
68 ("hh", "二", 5000),
69 ("hhh", "三", 4000),
70 ("hs", "十", 4500),
71 ("hsh", "土", 2000),
72 ("hshh", "土", 10),
73 ("hhsh", "王", 2500),
74 ("hhs", "干", 1500),
75 ("hpn", "大", 5500),
76 ("pn", "人", 6000),
77 ("szh", "口", 3500),
78 ("sz", "乚", 0),
79 ];
80
81 pub(crate) fn build(path: &Path) {
82 let connection = Connection::open(path).unwrap();
83 connection.execute_batch(SCHEMA).unwrap();
84 for (name, value) in [
85 (METADATA_FORMAT_VERSION, FORMAT_VERSION.to_string()),
86 (
87 METADATA_SOURCE_COMMIT,
88 "0000000000000000000000000000000000000000".to_owned(),
89 ),
90 (METADATA_LICENSE, "LGPL-3.0-only".to_owned()),
91 ] {
92 connection
93 .execute("INSERT INTO metadata VALUES (?1, ?2)", (name, value))
94 .unwrap();
95 }
96 for stroke in super::STROKES.chars() {
97 connection
98 .execute("INSERT INTO syllables VALUES (?1)", (stroke.to_string(),))
99 .unwrap();
100 }
101 for (key, text, weight) in ENTRIES {
102 connection
103 .execute(
104 "INSERT INTO entries VALUES (?1, ?2, ?3)",
105 (key, text, weight),
106 )
107 .unwrap();
108 }
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn every_key_has_a_glyph_that_maps_back() {
118 for key in STROKES.bytes().chain([WILDCARD]) {
119 assert!(is_key(key));
120 let glyph = glyph(key).unwrap();
121 assert_eq!(key_of_glyph(glyph), Some(key));
122 }
123 assert!(!is_stroke(WILDCARD));
124 for key in *b"aH1'*" {
125 assert!(!is_key(key));
126 assert_eq!(glyph(key), None);
127 }
128 assert_eq!(key_of_glyph('a'), None);
129 }
130}