1pub mod config;
6pub mod contexts;
7pub mod encoders;
8pub mod interfaces;
9pub mod objectives;
10pub mod operators;
11pub mod optimizers;
12#[cfg(feature = "server")]
13pub mod server;
14
15use config::{安排, 广义码位};
16use objectives::metric::指法标记;
17use rustc_hash::FxHashMap;
18use serde::{Deserialize, Serialize};
19use std::cmp::Reverse;
20use std::io;
21use wasm_bindgen::JsError;
22
23use crate::config::条件;
24
25pub const 最大词长: usize = 10;
27
28pub const 最大按键组合长度: usize = 4;
30
31#[derive(Debug, Serialize, Deserialize, Clone)]
32pub struct 原始元素序列及条件列表 {
33 pub 元素序列: Vec<广义码位>,
34 pub 条件列表: Vec<条件>,
35}
36
37#[derive(Debug, Serialize, Deserialize, Clone)]
39pub struct 原始可编码对象 {
40 pub 词: String,
41 #[serde(default)]
43 pub 元素序列: Option<Vec<广义码位>>,
44 #[serde(default)]
46 pub 全部元素序列: Option<Vec<原始元素序列及条件列表>>,
47 pub 频率: u64,
48 #[serde(default = "原始可编码对象::默认级别")]
49 pub 简码长度: u64,
50}
51
52impl 原始可编码对象 {
53 const fn 默认级别() -> u64 {
54 u64::MAX
55 }
56}
57
58pub type 原始键位分布信息 = FxHashMap<char, 键位分布损失函数>;
59pub type 键位分布信息 = Vec<键位分布损失函数>;
60pub type 原始当量信息 = FxHashMap<String, f64>;
61pub type 当量信息 = Vec<f64>;
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct 键位分布损失函数 {
66 pub 理想值: f64,
67 pub 低于惩罚: f64,
68 pub 高于惩罚: f64,
69}
70
71pub type 元素 = usize;
73
74pub type 元素位 = usize;
76
77pub const 最大元素序列长度: usize = 8;
79
80pub const 最大元素数量: usize = 1024;
83
84pub type 元素序列 = [元素位; 最大元素序列长度];
86
87pub type 元素图 = FxHashMap<元素, Vec<元素>>;
89
90pub const 最大元素编码长度: usize = 4;
92
93pub type 编码 = u64;
95
96#[derive(Debug, Clone)]
98pub struct 可编码对象 {
99 pub 词: String,
100 pub 词长: usize,
101 pub 元素序列: 元素序列,
102 pub 全部元素序列: Vec<(元素序列, 位图)>,
103 pub 频率: u64,
104 pub 简码长度: u64,
105 pub 原始顺序: usize,
106}
107
108#[derive(Debug, Clone, PartialEq, Eq)]
110pub struct 位图 {
111 pub 位图: [u64; 16],
112}
113
114impl 位图 {
115 pub fn new() -> Self {
116 Self { 位图: [0; 16] }
117 }
118
119 pub fn 从条件列表创建(条件列表: &[条件], 棱镜: &棱镜) -> Self {
120 let mut bitmap = Self::new();
121 for 条件 in 条件列表 {
122 if let Some(&元素) = 棱镜.元素转数字.get(&条件.element) {
123 if let Some(&位图索引) = 棱镜.可选元素位图索引.get(&元素) {
124 bitmap.insert(位图索引);
125 } else {
126 eprintln!(
129 "警告:条件中的元素「{}」在棱镜中未找到,已忽略这个条件",
130 条件.element
131 );
132 }
133 }
134 }
135 bitmap
136 }
137
138 pub fn insert(&mut self, i: usize) {
139 let (block, bit) = (i / 64, i % 64);
140 self.位图[block] |= 1 << bit;
141 }
142
143 pub fn remove(&mut self, i: usize) {
144 let (block, bit) = (i / 64, i % 64);
145 self.位图[block] &= !(1 << bit);
146 }
147
148 pub fn subset(&self, other: &Self) -> bool {
149 for i in 0..16 {
150 if self.位图[i] & !other.位图[i] != 0 {
151 return false;
152 }
153 }
154 true
155 }
156
157 pub fn union(&self, other: &Self) -> Self {
158 let mut result = Self::new();
159 for i in 0..16 {
160 result.位图[i] = self.位图[i] | other.位图[i];
161 }
162 result
163 }
164
165 pub fn intersection(&self, other: &Self) -> Self {
166 let mut result = Self::new();
167 for i in 0..16 {
168 result.位图[i] = self.位图[i] & other.位图[i];
169 }
170 result
171 }
172}
173
174#[derive(Clone, Debug, Copy, Default)]
176pub struct 部分编码信息 {
177 pub 原始编码: 编码, pub 原始编码候选位置: u8, pub 实际编码: 编码, pub 选重标记: u8, pub 上一个实际编码: 编码, pub 上一个选重标记: u8, pub 有变化: bool, }
185
186impl 部分编码信息 {
187 #[inline(always)]
188 pub fn 更新(&mut self, 编码: 编码, 选重标记: u8) {
189 if self.实际编码 == 编码 && self.选重标记 == 选重标记 {
190 return;
191 }
192 self.有变化 = true;
193 self.上一个实际编码 = self.实际编码;
194 self.上一个选重标记 = self.选重标记;
195 self.实际编码 = 编码;
196 self.选重标记 = 选重标记;
197 }
198}
199
200#[derive(Clone, Debug)]
202pub struct 编码信息 {
203 pub 词长: usize,
204 pub 频率: u64,
205 pub 全码: 部分编码信息,
206 pub 简码: 部分编码信息,
207}
208
209impl 编码信息 {
210 pub fn new(词: &可编码对象) -> Self {
211 Self {
212 词长: 词.词长,
213 频率: 词.频率,
214 全码: 部分编码信息::default(),
215 简码: 部分编码信息::default(),
216 }
217 }
218}
219
220pub type 键 = u64;
222
223pub type 指法向量 = [u8; 8];
225
226pub type 自动上屏 = Vec<bool>;
228
229#[derive(Debug, Clone, Serialize, Default)]
231pub struct 码表项 {
232 pub 词: String,
233 pub 全码: String,
234 pub 全码排名: u8,
235 pub 简码: String,
236 pub 简码排名: u8,
237}
238
239impl 安排 {
240 pub fn normalize(&self) -> Vec<广义码位> {
241 match self {
242 安排::Advanced(vector) => vector.clone(),
243 安排::Basic(string) => string.chars().map(广义码位::Ascii).collect(),
244 _ => panic!("无法把归并或禁用表示成列表形式"),
245 }
246 }
247}
248
249pub fn 元素标准名称(element: &String, index: usize) -> String {
250 if index == 0 {
251 element.to_string()
252 } else {
253 format!("{element}.{index}")
254 }
255}
256
257#[derive(Debug, Clone)]
258pub struct 棱镜 {
259 pub 键转数字: FxHashMap<char, 键>,
260 pub 数字转键: FxHashMap<键, char>,
261 pub 元素转数字: FxHashMap<String, 元素>,
262 pub 数字转元素: FxHashMap<元素, String>,
263 pub 进制: u64,
264 pub 可选元素位图索引: FxHashMap<元素, usize>,
267}
268
269impl 棱镜 {
270 pub fn 元素总数(&self) -> usize {
271 self.元素转数字.len() + 1 }
273
274 pub fn 数字转编码(&self, code: 编码) -> Vec<char> {
276 let mut chars = Vec::new();
277 let mut remainder = code;
278 while remainder > 0 {
279 let k = remainder % self.进制;
280 remainder /= self.进制;
281 if k == 0 {
282 continue;
283 }
284 let char = self.数字转键.get(&k).unwrap(); chars.push(*char);
286 }
287 chars
288 }
289
290 pub fn 预处理元素序列(
291 &self,
292 词: &String,
293 原始元素序列: &[广义码位],
294 最大码长: usize,
295 ) -> Result<元素序列, 错误> {
296 let mut 元素序列 = 元素序列::default();
297 let 原始元素序列长度 = 原始元素序列.len();
298 if 原始元素序列长度 > 最大码长 {
299 return Err(format!(
300 "编码对象「{词}」包含的元素数量为 {原始元素序列长度},超过了最大码长 {最大码长}"
301 )
302 .into());
303 }
304 for (i, 码位) in 原始元素序列.iter().enumerate() {
305 let 元素位 = match 码位 {
306 广义码位::Reference { element, index } => {
307 if let Some(&元素) = self.元素转数字.get(element) {
308 元素 + index * self.元素总数()
309 } else {
310 return Err(format!(
311 "编码对象「{词}」包含的元素「{element}」无法在键盘映射中找到"
312 )
313 .into());
314 }
315 }
316 广义码位::Ascii(k) => {
317 if let Some(&键) = self.键转数字.get(k) {
318 键 as usize
320 } else {
321 return Err(format!(
322 "编码对象「{词}」包含的按键「{k}」无法在键盘映射中找到"
323 )
324 .into());
325 }
326 }
327 _ => 0,
328 };
329 元素序列[i] = 元素位;
330 }
331 return Ok(元素序列);
332 }
333
334 pub fn 预处理词列表(
335 &self,
336 原始词列表: Vec<原始可编码对象>,
337 最大码长: usize,
338 ) -> Result<Vec<可编码对象>, 错误> {
339 let mut 词列表 = vec![];
340 for (原始顺序, 原始可编码对象) in 原始词列表.into_iter().enumerate() {
341 let 原始可编码对象 {
342 词,
343 频率,
344 元素序列: 原始单一元素序列,
345 全部元素序列: 原始全部元素序列,
346 简码长度,
347 } = 原始可编码对象;
348 let 原始全部元素序列: Vec<原始元素序列及条件列表> = match (原始单一元素序列, 原始全部元素序列) {
349 (Some(seq), None) => vec![原始元素序列及条件列表 { 元素序列: seq, 条件列表: vec![] }],
350 (None, Some(list)) => list,
351 _ => panic!("编码对象「{词}」必须恰好提供「元素序列」或「全部元素序列」之一", 词 = 词),
352 };
353 let mut 全部元素序列 = vec![];
354 assert!(!原始全部元素序列.is_empty(), "编码对象「{词}」至少需要一个元素序列", 词 = 词);
355 assert!(原始全部元素序列.last().unwrap().条件列表.is_empty(), "编码对象「{词}」的最后一个元素序列必须没有任何条件", 词 = 词);
356 for 原始元素序列及条件列表 { 元素序列: 原始元素序列, 条件列表 } in 原始全部元素序列 {
357 let 元素序列 = self.预处理元素序列(&词, &原始元素序列, 最大码长)?;
358 let 位图 = 位图::从条件列表创建(&条件列表, self);
359 全部元素序列.push((元素序列, 位图));
360 }
361 let c = 可编码对象 {
362 词: 词.clone(),
363 词长: 词.chars().count(),
364 频率,
365 简码长度,
366 元素序列: 全部元素序列[0].0,
367 全部元素序列,
368 原始顺序,
369 };
370 词列表.push(c);
371 }
372 词列表.sort_by_key(|x| Reverse(x.频率));
373 Ok(词列表)
374 }
375
376 pub fn 预处理键位分布信息(
378 &self,
379 原始键位分布信息: &原始键位分布信息,
380 ) -> Vec<键位分布损失函数> {
381 let default_loss = 键位分布损失函数 {
382 理想值: 0.0,
383 低于惩罚: 0.0,
384 高于惩罚: 0.0,
385 };
386 let mut 键位分布信息: Vec<键位分布损失函数> = (0..self.进制)
387 .map(|键| {
388 if 键 == 0 {
390 default_loss.clone()
391 } else {
392 let 键名称 = self.数字转键[&键];
393 原始键位分布信息
394 .get(&键名称)
395 .unwrap_or(&default_loss)
396 .clone()
397 }
398 })
399 .collect();
400 键位分布信息.iter_mut().for_each(|x| {
401 x.理想值 /= 100.0;
402 });
403 键位分布信息
404 }
405
406 pub fn 预处理当量信息(
409 &self, 原始当量信息: &原始当量信息, space: usize
410 ) -> Vec<f64> {
411 let mut result: Vec<f64> = vec![0.0; space];
412 for (index, equivalence) in result.iter_mut().enumerate() {
413 let chars = self.数字转编码(index as u64);
414 for correlation_length in [2, 3, 4] {
415 if chars.len() < correlation_length {
416 break;
417 }
418 for i in 0..=(chars.len() - correlation_length) {
420 let substr: String = chars[i..(i + correlation_length)].iter().collect();
421 *equivalence += 原始当量信息.get(&substr).unwrap_or(&0.0);
422 }
423 }
424 }
425 result
426 }
427
428 pub fn 预处理指法标记(&self, 空间: usize) -> Vec<指法向量> {
433 let 指法标记 = 指法标记::new();
434 let mut result: Vec<指法向量> = Vec::with_capacity(空间);
435 for code in 0..空间 {
436 let chars = self.数字转编码(code as u64);
437 if chars.len() < 2 {
438 result.push(指法向量::default());
439 continue;
440 }
441 let mut 指法向量 = 指法向量::default();
442 for i in 0..(chars.len() - 1) {
443 let pair = (chars[i], chars[i + 1]);
444 if 指法标记.同手.contains(&pair) {
445 指法向量[0] += 1;
446 }
447 if 指法标记.同指大跨排.contains(&pair) {
448 指法向量[1] += 1;
449 }
450 if 指法标记.同指小跨排.contains(&pair) {
451 指法向量[2] += 1;
452 }
453 if 指法标记.小指干扰.contains(&pair) {
454 指法向量[3] += 1;
455 }
456 if 指法标记.错手.contains(&pair) {
457 指法向量[4] += 1;
458 }
459 }
460 for i in 0..(chars.len() - 2) {
461 let triple = (chars[i], chars[i + 1], chars[i + 2]);
462 if triple.0 == triple.1 && triple.1 == triple.2 {
463 指法向量[5] += 1;
464 }
465 }
466 result.push(指法向量);
467 }
468 result
469 }
470}
471
472#[derive(Debug, Clone)]
474pub struct 错误 {
475 pub message: String,
476}
477
478impl From<String> for 错误 {
479 fn from(value: String) -> Self {
480 Self { message: value }
481 }
482}
483
484impl From<&str> for 错误 {
485 fn from(value: &str) -> Self {
486 Self {
487 message: value.to_string(),
488 }
489 }
490}
491
492impl From<io::Error> for 错误 {
493 fn from(value: io::Error) -> Self {
494 Self {
495 message: value.to_string(),
496 }
497 }
498}
499
500impl From<serde_json::Error> for 错误 {
501 fn from(value: serde_json::Error) -> Self {
502 Self {
503 message: value.to_string(),
504 }
505 }
506}
507
508impl From<错误> for JsError {
509 fn from(value: 错误) -> Self {
510 JsError::new(&value.message)
511 }
512}
513
514#[cfg(target_arch = "wasm32")]
515pub fn formatted_local_now() -> String {
516 use js_sys::Date;
517 let date = Date::new_0();
518 let month = date.get_month() as u32 + 1; let day = date.get_date() as u32;
520 let hour = date.get_hours() as u32;
521 let minute = date.get_minutes() as u32;
522 let second = date.get_seconds() as u32;
523 format!(
524 "{:02}-{:02}+{:02}_{:02}_{:02}",
525 month, day, hour, minute, second
526 )
527}
528
529#[cfg(not(target_arch = "wasm32"))]
530pub fn formatted_local_now() -> String {
531 use chrono::Local;
532 Local::now().format("%m-%d+%H_%M_%S").to_string()
533}