chai/
config.rs

1//! 配置文件的定义
2//!
3//! 这部分内容太多,就不一一注释了。后期会写一个「`config.yaml` 详解」来统一解释各种配置文件的字段。
4//!
5
6use crate::optimizers::simulated_annealing::退火方法;
7use serde::{Deserialize, Serialize};
8use serde_with::skip_serializing_none;
9use std::collections::HashMap;
10
11// config.info begin
12#[skip_serializing_none]
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct Info {
15    pub name: Option<String>,
16    pub version: Option<String>,
17    pub author: Option<String>,
18    pub description: Option<String>,
19}
20// config.info end
21
22// config.data begin
23#[skip_serializing_none]
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct Data {
26    pub character_set: Option<String>,
27    pub repertoire: Option<PrimitiveRepertoire>,
28    pub glyph_customization: Option<HashMap<String, Glyph>>,
29    pub reading_customization: Option<HashMap<String, Vec<Reading>>>,
30    pub tags: Option<Vec<String>>,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34#[serde(tag = "command", rename_all = "snake_case")]
35#[allow(non_snake_case)]
36pub enum Draw {
37    H { parameterList: [i8; 1] },
38    V { parameterList: [i8; 1] },
39    C { parameterList: [i8; 6] },
40    Z { parameterList: [i8; 6] },
41    A { parameterList: [i8; 1] },
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
45#[serde(untagged)]
46#[allow(non_snake_case)]
47pub enum Stroke {
48    SVGStroke {
49        feature: String,
50        start: (i8, i8),
51        curveList: Vec<Draw>,
52    },
53    ReferenceStroke {
54        feature: String,
55        index: usize,
56    },
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct Block {
61    pub index: usize,
62    pub strokes: usize,
63}
64
65#[skip_serializing_none]
66#[derive(Debug, Clone, Serialize, Deserialize)]
67#[serde(tag = "type", rename_all = "snake_case")]
68#[allow(non_snake_case)]
69pub enum Glyph {
70    BasicComponent {
71        tags: Option<Vec<String>>,
72        strokes: Vec<Stroke>,
73    },
74    DerivedComponent {
75        tags: Option<Vec<String>>,
76        source: String,
77        strokes: Vec<Stroke>,
78    },
79    SplicedComponent {
80        tags: Option<Vec<String>>,
81        operator: String,
82        operandList: Vec<String>,
83        order: Option<Vec<Block>>,
84    },
85    Compound {
86        tags: Option<Vec<String>>,
87        operator: String,
88        operandList: Vec<String>,
89        order: Option<Vec<Block>>,
90    },
91}
92
93#[skip_serializing_none]
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct Reading {
96    pub pinyin: String,
97    pub importance: f64,
98}
99
100#[skip_serializing_none]
101#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct PrimitiveCharacter {
103    pub unicode: usize,
104    pub tygf: u8,
105    pub gb2312: u8,
106    #[serialize_always] // JavaScript null
107    pub name: Option<String>,
108    #[serialize_always] // JavaScript null
109    pub gf0014_id: Option<usize>,
110    #[serialize_always] // JavaScript null
111    pub gf3001_id: Option<usize>,
112    pub readings: Vec<Reading>,
113    pub glyphs: Vec<Glyph>,
114    pub ambiguous: bool,
115}
116
117pub type PrimitiveRepertoire = HashMap<String, PrimitiveCharacter>;
118// config.data end
119
120// config.analysis begin
121#[skip_serializing_none]
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct Analysis {
124    pub classifier: Option<HashMap<String, usize>>,
125    pub degenerator: Option<Degenerator>,
126    pub selector: Option<Vec<String>>,
127    pub customize: Option<HashMap<String, Vec<String>>>,
128    pub strong: Option<Vec<String>>,
129    pub weak: Option<Vec<String>>,
130    pub serializer: Option<String>,
131}
132
133#[skip_serializing_none]
134#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct Degenerator {
136    pub feature: Option<HashMap<String, String>>,
137    pub no_cross: Option<bool>,
138}
139// config.analysis end
140
141// config.algebra begin
142type Algebra = HashMap<String, Vec<Rule>>;
143
144#[derive(Debug, Clone, Serialize, Deserialize)]
145#[serde(tag = "type", rename_all = "snake_case")]
146pub enum Rule {
147    Xform { from: String, to: String },
148    Xlit { from: String, to: String },
149}
150// config.algebra end
151
152// config.form begin
153#[skip_serializing_none]
154#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct FormConfig {
156    pub alphabet: String,
157    pub mapping_type: Option<usize>,
158    pub mapping: HashMap<String, Mapped>,
159    pub grouping: Option<HashMap<String, String>>,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize)]
163#[serde(untagged)]
164pub enum MappedKey {
165    Ascii(char),
166    Reference { element: String, index: usize },
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
170#[serde(untagged)]
171pub enum Mapped {
172    Basic(String),
173    Advanced(Vec<MappedKey>),
174}
175// config.form end
176
177// config.encoder begin
178#[skip_serializing_none]
179#[derive(Debug, Clone, Serialize, Deserialize)]
180pub struct EncoderConfig {
181    // 全局
182    pub max_length: usize,
183    pub select_keys: Option<Vec<char>>,
184    pub auto_select_length: Option<usize>,
185    pub auto_select_pattern: Option<String>,
186    // 一字词全码
187    pub sources: Option<HashMap<String, NodeConfig>>,
188    pub conditions: Option<HashMap<String, EdgeConfig>>,
189    // 多字词全码
190    pub rules: Option<Vec<WordRule>>,
191    // 简码
192    pub short_code: Option<Vec<ShortCodeConfig>>,
193    pub priority_short_codes: Option<Vec<(String, String, usize)>>,
194}
195
196#[skip_serializing_none]
197#[derive(Debug, Clone, Serialize, Deserialize)]
198#[allow(non_snake_case)]
199pub struct CodableObjectConfig {
200    pub r#type: String,
201    pub subtype: Option<String>,
202    pub key: Option<String>,
203    pub rootIndex: Option<i64>,
204    pub strokeIndex: Option<i64>,
205}
206
207#[skip_serializing_none]
208#[derive(Debug, Clone, Serialize, Deserialize)]
209pub struct NodeConfig {
210    #[serialize_always] // JavaScript null
211    pub object: Option<CodableObjectConfig>,
212    pub index: Option<usize>,
213    #[serialize_always] // JavaScript null
214    pub next: Option<String>,
215}
216
217#[skip_serializing_none]
218#[derive(Debug, Clone, Serialize, Deserialize)]
219pub struct EdgeConfig {
220    pub object: CodableObjectConfig,
221    pub operator: String,
222    pub value: Option<String>,
223    #[serialize_always] // JavaScript null
224    pub positive: Option<String>,
225    #[serialize_always] // JavaScript null
226    pub negative: Option<String>,
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize)]
230#[serde(untagged)]
231pub enum ShortCodeConfig {
232    Equal {
233        length_equal: usize,
234        schemes: Vec<Scheme>,
235    },
236    Range {
237        length_in_range: (usize, usize),
238        schemes: Vec<Scheme>,
239    },
240}
241
242#[skip_serializing_none]
243#[derive(Debug, Clone, Serialize, Deserialize)]
244pub struct Scheme {
245    pub prefix: usize,
246    pub count: Option<usize>,
247    pub select_keys: Option<Vec<char>>,
248}
249
250#[derive(Debug, Clone, Serialize, Deserialize)]
251#[serde(untagged)]
252pub enum WordRule {
253    EqualRule {
254        length_equal: usize,
255        formula: String,
256    },
257    RangeRule {
258        length_in_range: (usize, usize),
259        formula: String,
260    },
261}
262// config.encoder end
263
264// config.optimization begin
265#[derive(Debug, Clone, Serialize, Deserialize)]
266pub struct LevelWeights {
267    pub length: usize,
268    pub frequency: f64,
269}
270
271#[skip_serializing_none]
272#[derive(Debug, Clone, Serialize, Deserialize)]
273pub struct TierWeights {
274    pub top: Option<usize>,
275    pub duplication: Option<f64>,
276    pub levels: Option<Vec<LevelWeights>>,
277    pub fingering: Option<FingeringWeights>,
278}
279
280// let types = ["同手", "大跨", "小跨", "干扰", "错手", "三连", "备用", "备用"];
281pub type FingeringWeights = [Option<f64>; 8];
282
283#[skip_serializing_none]
284#[derive(Debug, Clone, Serialize, Deserialize)]
285pub struct PartialWeights {
286    pub tiers: Option<Vec<TierWeights>>,
287    pub duplication: Option<f64>,
288    pub key_distribution: Option<f64>,
289    pub pair_equivalence: Option<f64>,
290    pub extended_pair_equivalence: Option<f64>,
291    pub fingering: Option<FingeringWeights>,
292    pub levels: Option<Vec<LevelWeights>>,
293}
294
295#[derive(Debug, Clone, Serialize, Deserialize)]
296pub struct ElementWithIndex {
297    pub element: String,
298    pub index: usize,
299}
300
301#[derive(Debug, Clone, Serialize, Deserialize)]
302pub struct ElementAffinityTarget {
303    pub element: ElementWithIndex,
304    pub affinity: f64,
305}
306
307#[derive(Debug, Clone, Serialize, Deserialize)]
308pub struct KeyAffinityTarget {
309    pub key: char,
310    pub affinity: f64,
311}
312
313#[derive(Debug, Clone, Serialize, Deserialize)]
314pub struct AffinityList<T> {
315    pub from: ElementWithIndex,
316    pub to: Vec<T>,
317}
318
319#[skip_serializing_none]
320#[derive(Debug, Clone, Serialize, Deserialize)]
321pub struct Regularization {
322    pub strength: Option<f64>,
323    pub element_affinities: Option<Vec<AffinityList<ElementAffinityTarget>>>,
324    pub key_affinities: Option<Vec<AffinityList<KeyAffinityTarget>>>,
325}
326
327#[skip_serializing_none]
328#[derive(Debug, Clone, Serialize, Deserialize)]
329pub struct ObjectiveConfig {
330    pub characters_full: Option<PartialWeights>,
331    pub words_full: Option<PartialWeights>,
332    pub characters_short: Option<PartialWeights>,
333    pub words_short: Option<PartialWeights>,
334    pub regularization: Option<Regularization>,
335}
336
337#[skip_serializing_none]
338#[derive(Debug, Clone, Serialize, Deserialize)]
339pub struct AtomicConstraint {
340    pub element: Option<String>,
341    pub index: Option<usize>,
342    pub keys: Option<Vec<char>>,
343}
344
345#[skip_serializing_none]
346#[derive(Debug, Clone, Serialize, Deserialize)]
347pub struct ConstraintsConfig {
348    pub elements: Option<Vec<AtomicConstraint>>,
349    pub indices: Option<Vec<AtomicConstraint>>,
350    pub element_indices: Option<Vec<AtomicConstraint>>,
351}
352
353#[skip_serializing_none]
354#[derive(Debug, Clone, Serialize, Deserialize)]
355#[serde(tag = "algorithm")]
356pub enum SolverConfig {
357    SimulatedAnnealing(退火方法),
358    // TODO: Add more algorithms
359}
360
361#[skip_serializing_none]
362#[derive(Debug, Clone, Serialize, Deserialize)]
363pub struct OptimizationConfig {
364    pub objective: ObjectiveConfig,
365    pub constraints: Option<ConstraintsConfig>,
366    pub metaheuristic: Option<SolverConfig>,
367}
368// config.optimization end
369
370// config.diagram begin
371
372#[skip_serializing_none]
373#[derive(Debug, Clone, Serialize, Deserialize)]
374pub struct LayoutRow {
375    pub keys: Vec<char>,
376}
377
378#[derive(Debug, Clone, Serialize, Deserialize)]
379#[serde(tag = "type", rename_all = "snake_case")]
380pub enum BoxConfig {
381    Key { style: Option<String> },
382    Uppercase { style: Option<String> },
383    Element { r#match: Option<String>, style: Option<String> },
384    Custom { mapping: Option<String>, style: Option<String> },
385}
386
387#[skip_serializing_none]
388#[derive(Debug, Clone, Serialize, Deserialize)]
389pub struct DiagramConfig {
390    pub layout: Vec<LayoutRow>,
391    pub contents: Vec<BoxConfig>,
392    pub row_style: Option<String>,
393    pub cell_style: Option<String>,
394}
395
396// config.diagram end
397
398#[skip_serializing_none]
399#[derive(Debug, Clone, Serialize, Deserialize)]
400pub struct 配置 {
401    pub version: Option<String>,
402    #[serialize_always] // JavaScript null
403    pub source: Option<String>,
404    pub info: Option<Info>,
405    pub data: Option<Data>,
406    pub analysis: Option<Analysis>,
407    pub algebra: Option<Algebra>,
408    pub form: FormConfig,
409    pub encoder: EncoderConfig,
410    pub optimization: Option<OptimizationConfig>,
411    pub diagram: Option<DiagramConfig>,
412}
413
414impl Default for 配置 {
415    fn default() -> Self {
416        配置 {
417            version: None,
418            source: None,
419            info: None,
420            data: None,
421            analysis: None,
422            algebra: None,
423            form: FormConfig {
424                alphabet: "abcdefghijklmnopqrstuvwxyz".to_string(),
425                mapping_type: None,
426                mapping: HashMap::new(),
427                grouping: None,
428            },
429            encoder: EncoderConfig {
430                max_length: 1,
431                select_keys: None,
432                auto_select_length: None,
433                auto_select_pattern: None,
434                sources: None,
435                conditions: None,
436                rules: None,
437                short_code: None,
438                priority_short_codes: None,
439            },
440            optimization: None,
441            diagram: None,
442        }
443    }
444}