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: 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}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
44#[serde(untagged)]
45#[allow(non_snake_case)]
46pub enum Stroke {
47    SVGStroke {
48        feature: String,
49        start: (i8, i8),
50        curveList: Vec<Draw>,
51    },
52    ReferenceStroke {
53        feature: String,
54        index: usize,
55    },
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct Block {
60    pub index: usize,
61    pub strokes: usize,
62}
63
64#[skip_serializing_none]
65#[derive(Debug, Clone, Serialize, Deserialize)]
66#[serde(tag = "type", rename_all = "snake_case")]
67#[allow(non_snake_case)]
68pub enum Glyph {
69    BasicComponent {
70        tags: Option<Vec<String>>,
71        strokes: Vec<Stroke>,
72    },
73    DerivedComponent {
74        tags: Option<Vec<String>>,
75        source: String,
76        strokes: Vec<Stroke>,
77    },
78    Compound {
79        tags: Option<Vec<String>>,
80        operator: String,
81        operandList: Vec<String>,
82        order: Option<Vec<Block>>,
83    },
84}
85
86#[skip_serializing_none]
87#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct Reading {
89    pub pinyin: String,
90    pub importance: f64,
91}
92
93#[skip_serializing_none]
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct PrimitiveCharacter {
96    pub unicode: usize,
97    pub tygf: u8,
98    pub gb2312: bool,
99    #[serialize_always] // JavaScript null
100    pub name: Option<String>,
101    #[serialize_always] // JavaScript null
102    pub gf0014_id: Option<usize>,
103    pub readings: Vec<Reading>,
104    pub glyphs: Vec<Glyph>,
105    pub ambiguous: bool,
106}
107
108pub type PrimitiveRepertoire = HashMap<String, PrimitiveCharacter>;
109// config.data end
110
111// config.analysis begin
112#[skip_serializing_none]
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct Analysis {
115    pub classifier: Option<HashMap<String, usize>>,
116    pub degenerator: Option<Degenerator>,
117    pub selector: Option<Vec<String>>,
118    pub customize: Option<HashMap<String, Vec<String>>>,
119    pub strong: Option<Vec<String>>,
120    pub weak: Option<Vec<String>>,
121    pub serializer: Option<String>,
122}
123
124#[skip_serializing_none]
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct Degenerator {
127    pub feature: Option<HashMap<String, String>>,
128    pub no_cross: Option<bool>,
129}
130// config.analysis end
131
132// config.algebra begin
133type Algebra = HashMap<String, Vec<Rule>>;
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
136#[serde(tag = "type", rename_all = "snake_case")]
137pub enum Rule {
138    Xform { from: String, to: String },
139    Xlit { from: String, to: String },
140}
141// config.algebra end
142
143// config.form begin
144#[skip_serializing_none]
145#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct FormConfig {
147    pub alphabet: String,
148    pub mapping_type: Option<usize>,
149    pub mapping: HashMap<String, Mapped>,
150    pub grouping: Option<HashMap<String, String>>,
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize)]
154#[serde(untagged)]
155pub enum MappedKey {
156    Ascii(char),
157    Reference { element: String, index: usize },
158}
159
160#[derive(Debug, Clone, Serialize, Deserialize)]
161#[serde(untagged)]
162pub enum Mapped {
163    Basic(String),
164    Advanced(Vec<MappedKey>),
165}
166// config.form end
167
168// config.encoder begin
169#[skip_serializing_none]
170#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct EncoderConfig {
172    // 全局
173    pub max_length: usize,
174    pub select_keys: Option<Vec<char>>,
175    pub auto_select_length: Option<usize>,
176    pub auto_select_pattern: Option<String>,
177    // 一字词全码
178    pub sources: Option<HashMap<String, NodeConfig>>,
179    pub conditions: Option<HashMap<String, EdgeConfig>>,
180    // 多字词全码
181    pub rules: Option<Vec<WordRule>>,
182    // 简码
183    pub short_code: Option<Vec<ShortCodeConfig>>,
184    pub priority_short_codes: Option<Vec<(String, String, usize)>>,
185}
186
187#[skip_serializing_none]
188#[derive(Debug, Clone, Serialize, Deserialize)]
189#[allow(non_snake_case)]
190pub struct CodableObjectConfig {
191    pub r#type: String,
192    pub subtype: Option<String>,
193    pub key: Option<String>,
194    pub rootIndex: Option<i64>,
195    pub strokeIndex: Option<i64>,
196}
197
198#[skip_serializing_none]
199#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct NodeConfig {
201    #[serialize_always] // JavaScript null
202    pub object: Option<CodableObjectConfig>,
203    pub index: Option<usize>,
204    #[serialize_always] // JavaScript null
205    pub next: Option<String>,
206}
207
208#[skip_serializing_none]
209#[derive(Debug, Clone, Serialize, Deserialize)]
210pub struct EdgeConfig {
211    pub object: CodableObjectConfig,
212    pub operator: String,
213    pub value: Option<String>,
214    #[serialize_always] // JavaScript null
215    pub positive: Option<String>,
216    #[serialize_always] // JavaScript null
217    pub negative: Option<String>,
218}
219
220#[derive(Debug, Clone, Serialize, Deserialize)]
221#[serde(untagged)]
222pub enum ShortCodeConfig {
223    Equal {
224        length_equal: usize,
225        schemes: Vec<Scheme>,
226    },
227    Range {
228        length_in_range: (usize, usize),
229        schemes: Vec<Scheme>,
230    },
231}
232
233#[skip_serializing_none]
234#[derive(Debug, Clone, Serialize, Deserialize)]
235pub struct Scheme {
236    pub prefix: usize,
237    pub count: Option<usize>,
238    pub select_keys: Option<Vec<char>>,
239}
240
241#[derive(Debug, Clone, Serialize, Deserialize)]
242#[serde(untagged)]
243pub enum WordRule {
244    EqualRule {
245        length_equal: usize,
246        formula: String,
247    },
248    RangeRule {
249        length_in_range: (usize, usize),
250        formula: String,
251    },
252}
253// config.encoder end
254
255// config.optimization begin
256#[derive(Debug, Clone, Serialize, Deserialize)]
257pub struct LevelWeights {
258    pub length: usize,
259    pub frequency: f64,
260}
261
262#[skip_serializing_none]
263#[derive(Debug, Clone, Serialize, Deserialize)]
264pub struct TierWeights {
265    pub top: Option<usize>,
266    pub duplication: Option<f64>,
267    pub levels: Option<Vec<LevelWeights>>,
268    pub fingering: Option<FingeringWeights>,
269}
270
271// let types = ["同手", "大跨", "小跨", "干扰", "错手", "三连", "备用", "备用"];
272pub type FingeringWeights = [Option<f64>; 8];
273
274#[skip_serializing_none]
275#[derive(Debug, Clone, Serialize, Deserialize)]
276pub struct PartialWeights {
277    pub tiers: Option<Vec<TierWeights>>,
278    pub duplication: Option<f64>,
279    pub key_distribution: Option<f64>,
280    pub pair_equivalence: Option<f64>,
281    pub extended_pair_equivalence: Option<f64>,
282    pub fingering: Option<FingeringWeights>,
283    pub levels: Option<Vec<LevelWeights>>,
284}
285
286#[skip_serializing_none]
287#[derive(Debug, Clone, Serialize, Deserialize)]
288pub struct ObjectiveConfig {
289    pub characters_full: Option<PartialWeights>,
290    pub words_full: Option<PartialWeights>,
291    pub characters_short: Option<PartialWeights>,
292    pub words_short: Option<PartialWeights>,
293    pub fingering: Option<FingeringWeights>,
294}
295
296#[skip_serializing_none]
297#[derive(Debug, Clone, Serialize, Deserialize)]
298pub struct AtomicConstraint {
299    pub element: Option<String>,
300    pub index: Option<usize>,
301    pub keys: Option<Vec<char>>,
302}
303
304#[skip_serializing_none]
305#[derive(Debug, Clone, Serialize, Deserialize)]
306pub struct ConstraintsConfig {
307    pub elements: Option<Vec<AtomicConstraint>>,
308    pub indices: Option<Vec<AtomicConstraint>>,
309    pub element_indices: Option<Vec<AtomicConstraint>>,
310}
311
312#[skip_serializing_none]
313#[derive(Debug, Clone, Serialize, Deserialize)]
314#[serde(tag = "algorithm")]
315pub enum SolverConfig {
316    SimulatedAnnealing(退火方法),
317    // TODO: Add more algorithms
318}
319
320#[skip_serializing_none]
321#[derive(Debug, Clone, Serialize, Deserialize)]
322pub struct OptimizationConfig {
323    pub objective: ObjectiveConfig,
324    pub constraints: Option<ConstraintsConfig>,
325    pub metaheuristic: Option<SolverConfig>,
326}
327// config.optimization end
328
329#[skip_serializing_none]
330#[derive(Debug, Clone, Serialize, Deserialize)]
331pub struct 配置 {
332    pub version: Option<String>,
333    #[serialize_always] // JavaScript null
334    pub source: Option<String>,
335    pub info: Info,
336    pub data: Option<Data>,
337    pub analysis: Option<Analysis>,
338    pub algebra: Option<Algebra>,
339    pub form: FormConfig,
340    pub encoder: EncoderConfig,
341    pub optimization: Option<OptimizationConfig>,
342}
343
344impl Default for 配置 {
345    fn default() -> Self {
346        配置 {
347            version: None,
348            source: None,
349            info: Info {
350                name: "default".to_string(),
351                version: None,
352                author: None,
353                description: None,
354            },
355            data: None,
356            analysis: None,
357            algebra: None,
358            form: FormConfig {
359                alphabet: "abcdefghijklmnopqrstuvwxyz".to_string(),
360                mapping_type: None,
361                mapping: HashMap::new(),
362                grouping: None,
363            },
364            encoder: EncoderConfig {
365                max_length: 1,
366                select_keys: None,
367                auto_select_length: None,
368                auto_select_pattern: None,
369                sources: None,
370                conditions: None,
371                rules: None,
372                short_code: None,
373                priority_short_codes: None,
374            },
375            optimization: None,
376        }
377    }
378}