libdof/
lib.rs

1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3
4pub mod combos;
5pub mod dofinitions;
6pub mod interaction;
7pub mod keyboard;
8mod macros;
9pub mod magic;
10pub mod prelude;
11
12use combos::{Combos, ParseCombos};
13use interaction::{KeyPos, Pos};
14use keyboard::{ParseKeyboard, PhysicalKey, PhysicalKeyboard};
15use magic::Magic;
16use serde::{Deserialize, Serialize};
17use serde_with::{serde_as, skip_serializing_none, DisplayFromStr};
18use thiserror::Error;
19
20use std::{collections::BTreeMap, num::ParseFloatError};
21
22use dofinitions::*;
23
24/// A struct to represent the dof keyboard layout spec. This struct is useful for interacting with dofs
25/// and parsing to/from .dof using [`serde_json`](https://crates.io/crates/serde_json). For converting
26/// other formats into dofs, consider taking a look at [`DofIntermediate`](crate::DofIntermediate).
27///
28/// # Example
29///
30/// Parsing into dof and getting the name of the layout:
31///
32/// ```
33/// # use serde_json;
34/// # use libdof::Dof;
35/// # fn p() -> Result<(), Box<dyn std::error::Error>> {
36/// let dof_str = include_str!("../example_dofs/minimal_valid.dof");
37/// let dof = serde_json::from_str::<Dof>(dof_str)?;
38/// let name = dof.name();
39/// # Ok(()) }
40/// # fn main() { p(); }
41/// ```
42#[serde_as]
43#[skip_serializing_none]
44#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
45#[serde(try_from = "DofIntermediate", into = "DofIntermediate")]
46pub struct Dof {
47    name: String,
48    authors: Option<Vec<String>>,
49    board: PhysicalKeyboard,
50    parsed_board: ParseKeyboard,
51    year: Option<u32>,
52    description: Option<String>,
53    languages: Vec<Language>,
54    link: Option<String>,
55    layers: BTreeMap<String, Layer>,
56    anchor: Anchor,
57    magic: Magic,
58    // alt_fingerings: Option<Vec<String>>,
59    combos: Combos,
60    fingering: Fingering,
61    fingering_name: Option<NamedFingering>,
62    has_generated_shift: bool,
63}
64
65impl Dof {
66    /// Get the name of the layout.
67    pub fn name(&self) -> &str {
68        &self.name
69    }
70
71    /// Get an optional slice of authors of the layout.
72    pub fn authors(&self) -> Option<&[String]> {
73        self.authors.as_deref()
74    }
75
76    /// Get the [`KeyboardType`](crate::dofinitions::KeyboardType) of the layout.
77    pub const fn board(&self) -> &PhysicalKeyboard {
78        &self.board
79    }
80
81    /// Get the [`KeyboardType`](crate::dofinitions::KeyboardType) of the layout. `Custom::("")`
82    /// if a custom physical keyboard was provided.
83    pub fn board_type(&self) -> KeyboardType {
84        match &self.parsed_board {
85            ParseKeyboard::Named(n) => n.clone(),
86            _ => KeyboardType::Custom("".into()),
87        }
88    }
89
90    /// Get the optional publication year of the layout.
91    pub const fn year(&self) -> Option<u32> {
92        self.year
93    }
94
95    /// Get the optional description of the layout.
96    pub fn description(&self) -> Option<&str> {
97        self.description.as_deref()
98    }
99
100    /// Get the optional link of the layout.
101    pub fn link(&self) -> Option<&str> {
102        self.link.as_deref()
103    }
104
105    /// Get a slice of [Language](crate::Language) this layout was intended to be used for.
106    pub fn languages(&self) -> &[Language] {
107        &self.languages
108    }
109
110    /// Get a map containing the layer names and its corresponding layer on the layout.
111    pub fn layers(&self) -> &BTreeMap<String, Layer> {
112        &self.layers
113    }
114
115    /// Get the layout anchor, which specifies the coordinate of the top left corner of the layout compared to
116    /// the physical keyboard it's on.
117    pub const fn anchor(&self) -> Anchor {
118        self.anchor
119    }
120
121    /// Get the shape of the fingering and layers of the dof
122    pub fn shape(&self) -> Shape {
123        self.fingering().shape()
124    }
125
126    /// Get the fingering of the keyboard, which specifies for each coordinate which finger is supposed to press
127    /// what key.
128    pub const fn fingering(&self) -> &Fingering {
129        &self.fingering
130    }
131
132    /// If present, get a specified type of fingering that the layout uses.
133    pub fn fingering_name(&self) -> Option<&NamedFingering> {
134        self.fingering_name.as_ref()
135    }
136
137    /// Get the main layer of the layout. Contains a call to `expect()` but since creating a
138    /// `Dof` without a main layer is impossible, it should never fail.
139    pub fn main_layer(&self) -> &Layer {
140        self.layers
141            .get("main")
142            .expect("Creating a Dof without a main layer should be impossible")
143    }
144
145    /// Get the shift layer of the layout. Contains a call to `expect()` but since creating a
146    /// `Dof` without a main layer is impossible, it should never fail.
147    pub fn shift_layer(&self) -> &Layer {
148        self.layers
149            .get("shift")
150            .expect("Creating a Dof without a shift layer should be impossible")
151    }
152
153    /// Get a specific layer on the keyboard, if it exists.
154    pub fn layer(&self, name: &str) -> Option<&Layer> {
155        self.layers.get(name)
156    }
157
158    /// Get a vector of keys with metadata for each key attached. This can be useful if you want
159    /// to filter or any other way look at a specific set of keys on the keyboard.
160    pub fn keys(&self) -> Vec<DescriptiveKey> {
161        self.layers()
162            .iter()
163            .flat_map(|(name, layer)| {
164                layer
165                    .rows()
166                    .enumerate()
167                    .zip(self.fingering.rows())
168                    .zip(self.board.rows())
169                    .flat_map(move |(((row, key_row), finger_row), phys_row)| {
170                        key_row
171                            .iter()
172                            .enumerate()
173                            .zip(finger_row)
174                            .zip(phys_row)
175                            .map(move |(((col, key), &finger), phys)| {
176                                DescriptiveKey::new(key, name, row, col, finger, phys)
177                            })
178                    })
179            })
180            .collect()
181    }
182}
183
184impl TryFrom<DofIntermediate> for Dof {
185    type Error = DofError;
186
187    fn try_from(mut inter: DofIntermediate) -> std::result::Result<Self, Self::Error> {
188        let main_layer = inter.main_layer()?;
189
190        inter.validate_layer_keys(main_layer)?;
191        inter.validate_layer_shapes(main_layer)?;
192
193        let explicit_fingering = inter.explicit_fingering(main_layer)?;
194        let implicit_fingering = match inter.fingering.clone().unwrap_or_default() {
195            ParsedFingering::Implicit(f) => Some(f),
196            _ => None,
197        };
198
199        let has_generated_shift = if !inter.layers.contains_key("shift") {
200            inter.layers.insert(
201                "shift".into(),
202                DofIntermediate::generate_shift_layer(main_layer),
203            );
204            true
205        } else {
206            false
207        };
208
209        let anchor = match inter.anchor {
210            None => inter.board.anchor(),
211            Some(a) => a,
212        };
213
214        let board = PhysicalKeyboard::try_from(inter.board.clone())?
215            .resized(anchor, explicit_fingering.shape())?
216            .into_iter()
217            .map(|v| {
218                v.into_iter()
219                    .map(PhysicalKey::normalized)
220                    .collect::<Vec<_>>()
221            })
222            .collect::<Vec<_>>()
223            .into();
224
225        let languages = match inter.languages {
226            Some(l) => l
227                .into_iter()
228                .map(|(lang, weight)| Language::new(&lang, weight))
229                .collect::<Vec<_>>(),
230            None => vec![Language::default()],
231        };
232
233        let combos = match inter.combos {
234            Some(combos) => combos.into_pos_layers(&inter.layers)?,
235            None => Default::default(),
236            // None => Combos(inter.layers.iter()
237            //     .map(|(name, _)| (name.to_owned(), vec![]))
238            //     .collect())
239        };
240
241        let magic = inter.magic.unwrap_or_default();
242
243        Ok(Self {
244            name: inter.name,
245            authors: inter.authors,
246            board,
247            parsed_board: inter.board,
248            year: inter.year,
249            description: inter.description,
250            languages,
251            link: inter.link,
252            layers: inter.layers,
253            anchor,
254            magic,
255            combos,
256            fingering: explicit_fingering,
257            fingering_name: implicit_fingering,
258            has_generated_shift,
259        })
260    }
261}
262
263impl From<Dof> for DofIntermediate {
264    fn from(mut dof: Dof) -> DofIntermediate {
265        if dof.has_generated_shift {
266            dof.layers.remove("shift");
267        }
268
269        let fingering = dof
270            .fingering_name
271            .map(ParsedFingering::Implicit)
272            .unwrap_or(ParsedFingering::Explicit(dof.fingering));
273
274        let fingering = if fingering == ParsedFingering::default() {
275            None
276        } else {
277            Some(fingering)
278        };
279
280        let languages = match dof.languages.as_slice() {
281            [lang] if lang == &Language::default() => None,
282            _ => Some(
283                dof.languages
284                    .into_iter()
285                    .map(|l| (l.language, l.weight))
286                    .collect(),
287            ),
288        };
289
290        let anchor = match &dof.parsed_board {
291            ParseKeyboard::Named(n) => match n.anchor() {
292                a if a == dof.anchor => None,
293                a => Some(a),
294            },
295            _ => None,
296        };
297
298        let magic = match dof.magic.is_empty() {
299            false => Some(dof.magic),
300            true => None,
301        };
302
303        let combos = dof.combos.into_parse_combos(&dof.layers);
304
305        DofIntermediate {
306            name: dof.name,
307            authors: dof.authors,
308            board: dof.parsed_board,
309            year: dof.year,
310            description: dof.description,
311            languages,
312            link: dof.link,
313            layers: dof.layers,
314            anchor,
315            magic,
316            combos,
317            fingering,
318        }
319    }
320}
321
322#[derive(Debug, Error, PartialEq)]
323enum DofErrorInner {
324    #[error("This layout is missing a main layer")]
325    NoMainLayer,
326    #[error("Found these layer keys '{0:?}' however these layers do not actually exist")]
327    LayersNotFound(Vec<String>),
328    #[error("The shape of these layers: '{0:?}' are not the same as the main layer")]
329    IncompatibleLayerShapes(Vec<String>),
330    #[error("The layer shapes do not match the fingering shape")]
331    IncompatibleFingeringShape,
332    #[error("The provided layout + anchor don't fit within the given fingering")]
333    LayoutDoesntFit,
334    #[error("The anchor provided is bigger than the layout it is used for")]
335    AnchorBiggerThanLayout,
336    #[error("Combo key provided is empty. If this was intended, provide `~` instead.")]
337    EmptyComboKey,
338
339    #[error("Layer {0} containing combo {1} does not exist")]
340    UnknownComboLayer(String, String),
341    #[error("Combo {0} references key {1} at index {2}, which doesn't exist")]
342    InvalidKeyIndex(String, String, usize),
343
344    #[error("Couldn't parse Finger from '{0}'")]
345    FingerParseError(String),
346    #[error("Can't combine keyboard type '{0}' with fingering '{1}'")]
347    UnsupportedKeyboardFingeringCombo(KeyboardType, NamedFingering),
348    #[error("Default fingering only exists for known keyboards: ansi, iso, ortho and colstag")]
349    FingeringForCustomKeyboard,
350
351    #[error("Couldn't parse physical key from '{0}' because a float couldn't be parsed")]
352    KeyParseError(String),
353    #[error("Couldn't parse physical key because the string is empty")]
354    EmptyPhysKey,
355    #[error("Expected 2, 3 or 4 values in physical key definition, found {0} for '{1}'")]
356    ValueAmountError(usize, String),
357    #[error("Keyboard type '{0}' does not match a default physical keyboard.")]
358    UnknownKeyboardType(KeyboardType),
359
360    #[error("the provided layer name '{0}' is invalid")]
361    LayerDoesntExist(String),
362    #[error("the given position ({0}, {1}) is not available on the keyboard")]
363    InvalidPosition(u8, u8),
364
365    #[error("{0}")]
366    Infallible(#[from] std::convert::Infallible),
367    #[error("{0}")]
368    ParseFloatError(#[from] std::num::ParseFloatError),
369    #[error("{0}")]
370    ParseIntError(#[from] std::num::ParseIntError),
371
372    #[error("{0}")]
373    Custom(String),
374}
375
376use DofErrorInner as DErr;
377
378type Result<T> = std::result::Result<T, DofError>;
379
380/// The main error struct of the library. Internally it uses a Box containing [`DofErrorInner`](crate::DofErrorInner)
381/// to save space.
382#[derive(Debug, Error, PartialEq)]
383#[error("{0}")]
384pub struct DofError(#[source] Box<DofErrorInner>);
385
386impl DofError {
387    /// Allows users of the crate to create their own error messages if needed.
388    pub fn custom(msg: &str) -> Self {
389        DofError(Box::new(DErr::Custom(msg.into())))
390    }
391}
392
393impl From<DofErrorInner> for DofError {
394    fn from(value: DofErrorInner) -> Self {
395        Self(Box::new(value))
396    }
397}
398
399impl From<ParseFloatError> for DofError {
400    fn from(value: ParseFloatError) -> Self {
401        DErr::ParseFloatError(value).into()
402    }
403}
404
405/// Used to represent the language(s) a layout is optimized for, containing the name of a language
406/// as well as a weight, the latter being useful for layouts that are made for a combination of
407/// languages with some amount of % split.
408///
409/// The Default implementation of Language is English with weight 100.
410#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
411pub struct Language {
412    /// Language
413    pub language: String,
414    /// Weight of the language, meaning how important it is compared to possible other languages in
415    /// the `Dof`.
416    pub weight: usize,
417}
418
419impl Default for Language {
420    fn default() -> Self {
421        Language {
422            language: "English".into(),
423            weight: 100,
424        }
425    }
426}
427
428impl Language {
429    /// Create a new language
430    pub fn new(language: &str, weight: usize) -> Self {
431        let language = language.into();
432        Self { language, weight }
433    }
434
435    /// Presets the weight to be 100, small shorthand for when you only need one language though in theory
436    /// you could use two of these languages to represent a `(100 + 100) / 2 = 50%` split.
437    pub fn only(language: &str) -> Self {
438        Self {
439            language: language.into(),
440            weight: 100,
441        }
442    }
443}
444
445/// Overarching trait for any type that contains a `Vec<Vec<K>>` represinting one aspect of
446/// a keyboard(layout). In libdof these are `Layer` and `Fingering`, but this could also be
447/// implemented for a heatmap type or a physical keyboard for example.
448pub trait Keyboard {
449    /// A type representing a key.
450    type K: Clone;
451
452    /// Get an iterator over each row of the keyboard.
453    fn rows(&self) -> impl Iterator<Item = &Vec<Self::K>> {
454        self.inner().iter()
455    }
456
457    /// Get an iterator over the individual keys of the keyboard.
458    fn keys(&self) -> impl Iterator<Item = &Self::K> {
459        self.rows().flatten()
460    }
461
462    /// Get the shape of the keyboard.
463    fn shape(&self) -> Shape {
464        self.rows().map(|r| r.len()).collect::<Vec<_>>().into()
465    }
466
467    /// Get the amount of rows of the keyboard.
468    fn row_count(&self) -> usize {
469        self.rows().count()
470    }
471
472    /// Get a reference to the inner rows of the keyboard.
473    fn inner(&self) -> &[Vec<Self::K>];
474
475    /// Convert into underlying vectors of the keyboard.
476    fn into_inner(self) -> Vec<Vec<Self::K>>;
477
478    /// For each row of the keyboard, checks whether or not it's smaller or equal to the given
479    /// shape's row.
480    fn fits_in(&self, shape: &Shape) -> bool {
481        self.shape().fits_in(shape)
482    }
483
484    /// Given a specific keyboard, an [`Anchor`](crate::Anchor) and the [`Shape`](crate::Shape),
485    /// resize to the given shape. Returns an error if the shape is bigger than the provided keyboard.
486    fn resized(&self, Anchor(x, y): Anchor, desired_shape: Shape) -> Result<Vec<Vec<Self::K>>> {
487        let (offset_x, offset_y) = (x as usize, y as usize);
488
489        let anchor_resized = self
490            .inner()
491            .get(offset_y..)
492            .ok_or(DErr::AnchorBiggerThanLayout)?
493            .iter()
494            .map(|r| r.get(offset_x..).ok_or(DErr::AnchorBiggerThanLayout.into()))
495            .collect::<Result<Vec<_>>>()?;
496
497        anchor_resized
498            .into_iter()
499            .zip(desired_shape.into_inner())
500            .map(|(row, shape_size)| {
501                row.get(..shape_size)
502                    .ok_or(DErr::LayoutDoesntFit.into())
503                    .map(|v| v.to_vec())
504            })
505            .collect::<Result<Vec<_>>>()
506            .map(Into::into)
507    }
508}
509
510/// Struct that represents the fingering of each layout. It is an abstraction over `Vec<Vec<Finger>>`.
511#[serde_as]
512#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
513pub struct Fingering(#[serde_as(as = "Vec<FingeringStrAsRow>")] Vec<Vec<Finger>>);
514
515impl Keyboard for Fingering {
516    type K = Finger;
517
518    fn inner(&self) -> &[Vec<Self::K>] {
519        &self.0
520    }
521
522    fn into_inner(self) -> Vec<Vec<Self::K>> {
523        self.0
524    }
525}
526
527impl From<Vec<Vec<Finger>>> for Fingering {
528    fn from(f: Vec<Vec<Finger>>) -> Self {
529        Self(f)
530    }
531}
532
533keyboard_conv!(Finger, FingeringStrAsRow);
534
535/// Abstraction over the way an actual .dof file is allowed to represent the fingering of a layout, being either
536/// explicit through providing a list of fingerings for each key, or implicit, by providing a name.
537#[serde_as]
538#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
539#[serde(untagged)]
540pub enum ParsedFingering {
541    /// Covers the case where fingering is specified explicitly for each key
542    Explicit(Fingering),
543    /// Covers the case where fingering is specified implicitly, by providing a name like `traditional`,
544    /// `standard` or `angle`
545    Implicit(#[serde_as(as = "DisplayFromStr")] NamedFingering),
546}
547
548impl Default for ParsedFingering {
549    fn default() -> Self {
550        Self::Implicit(Default::default())
551    }
552}
553
554/// An abstraction of `Vec<Vec<Key>>` to represent a layer on a layout.
555#[serde_as]
556#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
557pub struct Layer(#[serde_as(as = "Vec<LayerStrAsRow>")] Vec<Vec<Key>>);
558
559impl Keyboard for Layer {
560    type K = Key;
561
562    fn inner(&self) -> &[Vec<Self::K>] {
563        &self.0
564    }
565
566    fn into_inner(self) -> Vec<Vec<Self::K>> {
567        self.0
568    }
569}
570
571impl From<Vec<Vec<Key>>> for Layer {
572    fn from(f: Vec<Vec<Key>>) -> Self {
573        Self(f)
574    }
575}
576
577keyboard_conv!(Key, LayerStrAsRow);
578
579/// An anchor represents where the top left key on a `Dof` is compared to where it would be on a physical
580/// keyboard. For example, if you were to provide a 3x10 raster of letters but would like this applied to an
581/// ANSI keyboard, the `Anchor` would be (1, 1), as the top left corner of the `Dof` (being where qwerty `q`
582/// is) would need to be shifted one left and one up to be in the top left corner of the physical keyboard.
583/// Therefore, the default value of an anchor is dependent on the physical keyboard it is applied to.
584#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
585pub struct Anchor(u8, u8);
586
587impl Anchor {
588    /// Create a new anchor
589    pub const fn new(x: u8, y: u8) -> Self {
590        Anchor(x, y)
591    }
592
593    /// Return the x coordinate as usize
594    pub const fn x(&self) -> usize {
595        self.0 as usize
596    }
597
598    /// Return the y coordinate as usize
599    pub const fn y(&self) -> usize {
600        self.1 as usize
601    }
602}
603
604/// A Key with metadata attached. These are produced by calling [`Dof::keys()`](crate::Dof::keys()).
605#[derive(Clone, Debug, PartialEq)]
606pub struct DescriptiveKey<'a> {
607    output: &'a Key,
608    layer: &'a str,
609    pos: Pos,
610    finger: Finger,
611    phys: &'a PhysicalKey,
612}
613
614impl<'a> DescriptiveKey<'a> {
615    /// Create a new DescriptiveKey.
616    fn new(
617        output: &'a Key,
618        layer: &'a str,
619        row: usize,
620        col: usize,
621        finger: Finger,
622        physical_pos: &'a PhysicalKey,
623    ) -> Self {
624        let pos = Pos::new(row, col);
625        Self {
626            output,
627            layer,
628            pos,
629            finger,
630            phys: physical_pos,
631        }
632    }
633
634    /// Get the [`KeyPos`](crate::interaction::KeyPos) of a certain key, containing the layer name as well
635    /// its row and column coordinates.
636    pub fn keypos(&self) -> KeyPos {
637        KeyPos::new(self.layer, self.pos)
638    }
639
640    /// Get the key's row and column.
641    pub const fn pos(&self) -> Pos {
642        self.pos
643    }
644
645    /// Get the key's row.
646    pub const fn row(&self) -> usize {
647        self.pos.row()
648    }
649
650    /// Get the key's column.
651    pub const fn col(&self) -> usize {
652        self.pos.col()
653    }
654
655    /// Get the finger the key is supposed to be pressed with.
656    pub const fn finger(&self) -> Finger {
657        self.finger
658    }
659
660    /// Get the key's output.
661    pub const fn output(&self) -> &Key {
662        self.output
663    }
664
665    /// Get the key's physical location
666    pub const fn physical_pos(&self) -> &PhysicalKey {
667        self.phys
668    }
669
670    /// Get the name of the layer of the key.
671    pub fn layer_name(&self) -> &str {
672        self.layer
673    }
674
675    /// Check if the key is on a certain finger.
676    pub const fn is_on_finger(&self, finger: Finger) -> bool {
677        (self.finger as u8) == (finger as u8)
678    }
679
680    /// Check if the key is on any of the provided fingers.
681    pub fn is_on_fingers(&self, fingers: &[Finger]) -> bool {
682        fingers.iter().any(|f| self.finger == *f)
683    }
684
685    /// Check if the key is on left hand, including left thumb.
686    pub const fn is_on_left_hand(&self) -> bool {
687        self.finger.is_on_left_hand()
688    }
689
690    /// Check if the key is on left hand, including left thumb.
691    pub const fn is_on_right_hand(&self) -> bool {
692        self.finger.is_on_right_hand()
693    }
694
695    /// Check if the key is on a specific layer.
696    pub fn is_on_layer(&self, layer: &str) -> bool {
697        self.layer == layer
698    }
699
700    /// Check if the key is of type [`Key::Char`](crate::dofinitions::Key::Char) which outputs
701    /// a single character.
702    pub const fn is_char_key(&self) -> bool {
703        self.output.is_char()
704    }
705
706    /// Check if the key is of type [`Key::Word`](crate::dofinitions::Key::Word) which outputs a specific
707    /// string.
708    pub const fn is_word_key(&self) -> bool {
709        self.output.is_word()
710    }
711
712    /// Check if the key is of type [`Key::Empty`](crate::dofinitions::Key::Empty) which doesn't output
713    /// anything.
714    pub const fn is_empty_key(&self) -> bool {
715        self.output.is_empty()
716    }
717
718    /// Check if the key is of type [`Key::Transparent`](crate::dofinitions::Key::Char) which outputs
719    /// whatever it is the main layer outputs in that position.
720    pub const fn is_transparent_key(&self) -> bool {
721        self.output.is_transparent()
722    }
723
724    /// Check if the key is of type [`Key::Layer`](crate::dofinitions::Key::Layer) which holds the name.
725    /// of a layer on the layout
726    pub const fn is_layer_key(&self) -> bool {
727        self.output.is_layer()
728    }
729
730    /// Get the output if the key is of type [`Key::Char`](crate::dofinitions::Key::Char).
731    pub const fn char_output(&self) -> Option<char> {
732        self.output.char_output()
733    }
734
735    /// Get the output if the key is of type [`Key::Word`](crate::dofinitions::Key::Word).
736    pub fn word_output(&self) -> Option<&str> {
737        self.output.word_output()
738    }
739
740    /// Get the layer name if the key is of type [`Key::Layer`](crate::dofinitions::Key::Layer).
741    pub fn layer_output(&self) -> Option<&str> {
742        self.output.layer_label()
743    }
744
745     /// Get the magic key label if the key is of type [`Key::Magic`](crate::dofinitions::Key::Magic).
746    pub fn magic_label(&self) -> Option<&str> {
747        self.output.magic_label()
748    }
749}
750
751/// Main struct to use for parsing, and a more or less literal interpretation of what a .dof file can contain.
752/// As its fields are public, this can also be useful for implementing `TryFrom<Type> for Dof` because at the
753/// end of that function you can call `intermediate.try_into()` to handle all validation for you.
754#[allow(missing_docs)]
755#[serde_as]
756#[skip_serializing_none]
757#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
758pub struct DofIntermediate {
759    pub name: String,
760    pub authors: Option<Vec<String>>,
761    pub board: ParseKeyboard,
762    pub year: Option<u32>,
763    pub description: Option<String>,
764    pub languages: Option<BTreeMap<String, usize>>,
765    pub link: Option<String>,
766    pub layers: BTreeMap<String, Layer>,
767    pub anchor: Option<Anchor>,
768    pub magic: Option<Magic>,
769    // pub alt_fingerings: Option<Vec<String>>,
770    pub combos: Option<ParseCombos>,
771    pub fingering: Option<ParsedFingering>,
772}
773
774impl DofIntermediate {
775    /// Get the main layer if it exists. If it doesn't return a `NoMainLayer` error.
776    pub fn main_layer(&self) -> Result<&Layer> {
777        self.layers.get("main").ok_or(DErr::NoMainLayer.into())
778    }
779
780    /// If not provided, will generate a default shift layer with some sane defaults. This is useful
781    /// if your shift layer isn't doing anything special. The defaults are:
782    /// * Letters are uppercased, unless their uppercase version spans multiple characters,
783    /// * Symbols and numbers are given their qwerty uppercase. This means that `7` becomes `&`, `'`
784    ///   becomes `"`, `[` becomes `{`, etc,
785    /// * Special keys become Transparent.
786    ///
787    /// **Words are unaffected!** This means that if you would like Word keys to output something different,
788    /// you must specify a custom shift layer.
789    pub fn generate_shift_layer(main: &Layer) -> Layer {
790        main.0
791            .iter()
792            .map(|row| row.iter().map(|k| k.shifted()).collect::<Vec<_>>())
793            .collect::<Vec<_>>()
794            .into()
795    }
796
797    /// Validation check to see if the layers the [`Key::Layer`](crate::dofinitions::Key::Layer)
798    /// keys point to layers that actually exist.
799    pub fn validate_layer_keys(&self, main: &Layer) -> Result<()> {
800        let layers_dont_exist = main
801            .keys()
802            .filter_map(|k| match k {
803                Key::Layer { label: n } if !self.layers.contains_key(n) => Some(n.clone()),
804                _ => None,
805            })
806            .collect::<Vec<_>>();
807
808        if layers_dont_exist.is_empty() {
809            Ok(())
810        } else {
811            Err(DErr::LayersNotFound(layers_dont_exist).into())
812        }
813    }
814
815    /// Validation check to see if all layers are the same shape as the main layer.
816    pub fn validate_layer_shapes(&self, main: &Layer) -> Result<()> {
817        let main_shape = main.shape();
818
819        let incompatible_shapes = self
820            .layers
821            .iter()
822            .map(|(name, l)| (name, l.shape()))
823            .filter(|(_, shape)| shape != &main_shape)
824            .map(|(name, _)| name.clone())
825            .collect::<Vec<_>>();
826
827        if incompatible_shapes.is_empty() {
828            Ok(())
829        } else {
830            Err(DErr::IncompatibleLayerShapes(incompatible_shapes).into())
831        }
832    }
833
834    /// Validation check to see if the provided fingering has the same shape as the main layer.
835    /// If left implicit (by leaving just a name of a fingering, like `traditional` or `angle`)
836    /// will try to generate a fingering with the same shape as the main layer.
837    pub fn explicit_fingering(&self, main: &Layer) -> Result<Fingering> {
838        use ParsedFingering::*;
839
840        let d = Default::default();
841        let fingering = match &self.fingering {
842            Some(f) => f,
843            None => &d,
844        };
845
846        match fingering {
847            Explicit(f) if f.shape() == main.shape() => Ok(f.clone()),
848            Explicit(_) => Err(DErr::IncompatibleFingeringShape.into()),
849            Implicit(named) => {
850                let fingering = self.board.fingering(named)?;
851
852                let anchor = match self.anchor {
853                    Some(a) => a,
854                    None => self.board.anchor(),
855                };
856
857                fingering.resized(anchor, main.shape()).map(Into::into)
858            }
859        }
860    }
861}
862
863#[cfg(test)]
864mod tests {
865    use keyboard::{RelativeKey, RelativeKeyboard};
866
867    use crate::magic::MagicKey;
868
869    use super::*;
870
871    #[test]
872    fn no_main_layer() {
873        let minimal_test = DofIntermediate {
874            name: "Qwerty".into(),
875            authors: None,
876            board: ParseKeyboard::Named(KeyboardType::Ansi),
877            year: None,
878            description: None,
879            languages: Default::default(),
880            link: None,
881            anchor: None,
882            layers: BTreeMap::new(),
883            fingering: Some(ParsedFingering::Implicit(NamedFingering::Angle)),
884            combos: None,
885            magic: None,
886        };
887
888        let v = Dof::try_from(minimal_test);
889
890        assert_eq!(v, Err(DofError::from(DErr::NoMainLayer)));
891    }
892
893    #[test]
894    fn parse_minimal() {
895        let minimal_json = include_str!("../example_dofs/minimal_parsable.dof");
896
897        let minimal_test = DofIntermediate {
898            name: "Qwerty".into(),
899            authors: None,
900            board: ParseKeyboard::Named(KeyboardType::Ansi),
901            year: None,
902            description: None,
903            languages: None,
904            link: None,
905            anchor: None,
906            layers: BTreeMap::new(),
907            fingering: None,
908            combos: None,
909            magic: None,
910        };
911
912        let dof_minimal = serde_json::from_str::<DofIntermediate>(minimal_json)
913            .expect("couldn't parse implicit json");
914
915        assert_eq!(dof_minimal, minimal_test);
916    }
917
918    #[test]
919    fn minimal_succesful_dof() {
920        use Finger::*;
921        use Key::*;
922
923        let minimal_json = include_str!("../example_dofs/minimal_valid.dof");
924
925        let d = serde_json::from_str::<Dof>(minimal_json).expect("Couldn't serialize as Dof");
926
927        let d_manual = Dof {
928            name: "Qwerty".into(),
929            authors: None,
930            board: PhysicalKeyboard::try_from(ParseKeyboard::Named(KeyboardType::Ansi))
931                .unwrap()
932                .resized(KeyboardType::Ansi.anchor(), vec![10, 11, 10].into())
933                .unwrap()
934                .into(),
935            parsed_board: ParseKeyboard::Named(KeyboardType::Ansi),
936            year: None,
937            description: None,
938            languages: vec![Default::default()],
939            link: None,
940            anchor: Anchor::new(1, 1),
941            layers: BTreeMap::from_iter([
942                (
943                    "main".into(),
944                    vec![
945                        vec![
946                            Char('q'),
947                            Char('w'),
948                            Char('e'),
949                            Char('r'),
950                            Char('t'),
951                            Char('y'),
952                            Char('u'),
953                            Char('i'),
954                            Char('o'),
955                            Char('p'),
956                        ],
957                        vec![
958                            Char('a'),
959                            Char('s'),
960                            Char('d'),
961                            Char('f'),
962                            Char('g'),
963                            Char('h'),
964                            Char('j'),
965                            Char('k'),
966                            Char('l'),
967                            Char(';'),
968                            Char('\''),
969                        ],
970                        vec![
971                            Char('z'),
972                            Char('x'),
973                            Char('c'),
974                            Char('v'),
975                            Char('b'),
976                            Char('n'),
977                            Char('m'),
978                            Char(','),
979                            Char('.'),
980                            Char('/'),
981                        ],
982                    ]
983                    .into(),
984                ),
985                (
986                    "shift".into(),
987                    Layer(vec![
988                        vec![
989                            Char('Q'),
990                            Char('W'),
991                            Char('E'),
992                            Char('R'),
993                            Char('T'),
994                            Char('Y'),
995                            Char('U'),
996                            Char('I'),
997                            Char('O'),
998                            Char('P'),
999                        ],
1000                        vec![
1001                            Char('A'),
1002                            Char('S'),
1003                            Char('D'),
1004                            Char('F'),
1005                            Char('G'),
1006                            Char('H'),
1007                            Char('J'),
1008                            Char('K'),
1009                            Char('L'),
1010                            Char(':'),
1011                            Char('\"'),
1012                        ],
1013                        vec![
1014                            Char('Z'),
1015                            Char('X'),
1016                            Char('C'),
1017                            Char('V'),
1018                            Char('B'),
1019                            Char('N'),
1020                            Char('M'),
1021                            Char('<'),
1022                            Char('>'),
1023                            Char('?'),
1024                        ],
1025                    ]),
1026                ),
1027            ]),
1028            combos: Default::default(),
1029            magic: Default::default(),
1030            fingering: {
1031                vec![
1032                    vec![LP, LR, LM, LI, LI, RI, RI, RM, RR, RP],
1033                    vec![LP, LR, LM, LI, LI, RI, RI, RM, RR, RP, RP],
1034                    vec![LR, LM, LI, LI, LI, RI, RI, RM, RR, RP],
1035                ]
1036                .into()
1037            },
1038            fingering_name: Some(NamedFingering::Angle),
1039            has_generated_shift: true,
1040        };
1041
1042        assert_eq!(d, d_manual);
1043
1044        let reconvert_json =
1045            serde_json::to_string_pretty(&d).expect("Couldn't reconvert to json value");
1046
1047        println!("{reconvert_json}")
1048    }
1049
1050    #[test]
1051    fn parse_aptmak() {
1052        use Finger::*;
1053        use Key::*;
1054
1055        let aptmak_json = include_str!("../example_dofs/aptmak.dof");
1056
1057        let d = serde_json::from_str::<Dof>(aptmak_json).expect("Couldn't serialize as Dof");
1058
1059        let d_manual = Dof {
1060            name: "Aptmak".into(),
1061            authors: None,
1062            board: PhysicalKeyboard::try_from(ParseKeyboard::Named(KeyboardType::Colstag))
1063                .unwrap()
1064                .resized(KeyboardType::Colstag.anchor(), vec![10, 10, 10, 6].into())
1065                .unwrap()
1066                .into(),
1067            parsed_board: ParseKeyboard::Named(KeyboardType::Colstag),
1068            year: None,
1069            description: None,
1070            languages: vec![Default::default()],
1071            link: None,
1072            anchor: KeyboardType::Colstag.anchor(),
1073            layers: BTreeMap::from_iter([
1074                (
1075                    "main".into(),
1076                    vec![
1077                        vec![
1078                            Char('v'),
1079                            Char('w'),
1080                            Char('f'),
1081                            Char('p'),
1082                            Char('b'),
1083                            Char('j'),
1084                            Char('l'),
1085                            Char('u'),
1086                            Char('y'),
1087                            Char('\''),
1088                        ],
1089                        vec![
1090                            Char('r'),
1091                            Char('s'),
1092                            Char('t'),
1093                            Char('h'),
1094                            Char('k'),
1095                            Char('x'),
1096                            Char('n'),
1097                            Char('a'),
1098                            Char('i'),
1099                            Char('o'),
1100                        ],
1101                        vec![
1102                            Char(';'),
1103                            Char('c'),
1104                            Char('g'),
1105                            Char('d'),
1106                            Char('q'),
1107                            Char('z'),
1108                            Char('m'),
1109                            Char(','),
1110                            Char('.'),
1111                            Char('/'),
1112                        ],
1113                        vec![
1114                            Empty,
1115                            Special(SpecialKey::Space),
1116                            Empty,
1117                            Empty,
1118                            Char('e'),
1119                            Empty,
1120                        ],
1121                    ]
1122                    .into(),
1123                ),
1124                (
1125                    "shift".into(),
1126                    vec![
1127                        vec![
1128                            Char('V'),
1129                            Char('W'),
1130                            Char('F'),
1131                            Char('P'),
1132                            Char('B'),
1133                            Char('J'),
1134                            Char('L'),
1135                            Char('U'),
1136                            Char('Y'),
1137                            Char('"'),
1138                        ],
1139                        vec![
1140                            Char('R'),
1141                            Char('S'),
1142                            Char('T'),
1143                            Char('H'),
1144                            Char('K'),
1145                            Char('X'),
1146                            Char('N'),
1147                            Char('A'),
1148                            Char('I'),
1149                            Char('O'),
1150                        ],
1151                        vec![
1152                            Char(':'),
1153                            Char('C'),
1154                            Char('G'),
1155                            Char('D'),
1156                            Char('Q'),
1157                            Char('Z'),
1158                            Char('M'),
1159                            Char('<'),
1160                            Char('>'),
1161                            Char('?'),
1162                        ],
1163                        vec![Empty, Transparent, Empty, Empty, Char('E'), Empty],
1164                    ]
1165                    .into(),
1166                ),
1167            ]),
1168            combos: Default::default(),
1169            magic: Default::default(),
1170            fingering: {
1171                vec![
1172                    vec![LP, LR, LM, LI, LI, RI, RI, RM, RR, RP],
1173                    vec![LP, LR, LM, LI, LI, RI, RI, RM, RR, RP],
1174                    vec![LP, LR, LM, LI, LI, RI, RI, RM, RR, RP],
1175                    vec![LT, LT, LT, RT, RT, RT],
1176                ]
1177                .into()
1178            },
1179            fingering_name: Some(NamedFingering::Traditional),
1180            has_generated_shift: true,
1181        };
1182
1183        assert_eq!(d, d_manual);
1184
1185        let reconvert_json =
1186            serde_json::to_string_pretty(&d).expect("Couldn't reconvert to json value");
1187
1188        println!("{reconvert_json}")
1189    }
1190
1191    #[test]
1192    fn maximal_succesful() {
1193        let maximal_json = include_str!("../example_dofs/maximal.dof");
1194
1195        serde_json::from_str::<Dof>(maximal_json).expect("Couldn't parse or validate Dof");
1196    }
1197
1198    #[test]
1199    fn deserialize_minimal() {
1200        let minimal_test = DofIntermediate {
1201            name: "Qwerty".into(),
1202            authors: None,
1203            board: ParseKeyboard::Named(KeyboardType::Ansi),
1204            year: None,
1205            description: None,
1206            languages: None,
1207            link: None,
1208            anchor: None,
1209            layers: BTreeMap::new(),
1210            fingering: Some(ParsedFingering::Implicit(NamedFingering::Angle)),
1211            combos: None,
1212            magic: None,
1213        };
1214
1215        let s = serde_json::to_string_pretty(&minimal_test).unwrap();
1216
1217        println!("{s}")
1218    }
1219
1220    #[test]
1221    fn buggy() {
1222        let buggy_json = include_str!("../example_dofs/buggy.dof");
1223
1224        let buggy = serde_json::from_str::<Dof>(buggy_json).expect("couldn't parse buggy json");
1225
1226        assert_eq!(buggy.layers.len(), 4);
1227        assert_eq!(buggy.anchor, Anchor(0, 0));
1228    }
1229
1230    fn rk(width: f64) -> RelativeKey {
1231        RelativeKey {
1232            width,
1233            has_key: true,
1234        }
1235    }
1236
1237    #[test]
1238    fn parse_maximal() {
1239        use combos::ck;
1240        use Finger::*;
1241        use Key::*;
1242        use SpecialKey::*;
1243
1244        let maximal_json = include_str!("../example_dofs/maximal.dof");
1245
1246        let maximal_test = DofIntermediate {
1247            name: "Qwerty".into(),
1248            authors: Some(vec!["Christopher Latham Sholes".into()]),
1249            year: Some(1878),
1250            description: Some("the OG. Without Qwerty, none of this would be necessary.".into()),
1251            languages: Some(BTreeMap::from_iter([("english".to_owned(), 100)])),
1252            link: Some("https://en.wikipedia.org/wiki/QWERTY".into()),
1253            anchor: Some(Anchor::new(0, 0)),
1254            layers: BTreeMap::from_iter([
1255                (
1256                    "main".into(),
1257                    crate::Layer::from(vec![
1258                        vec![
1259                            Char('`'),
1260                            Char('1'),
1261                            Char('2'),
1262                            Char('3'),
1263                            Char('4'),
1264                            Char('5'),
1265                            Char('6'),
1266                            Char('7'),
1267                            Char('8'),
1268                            Char('9'),
1269                            Char('0'),
1270                            Char('-'),
1271                            Char('='),
1272                            Special(Backspace),
1273                        ],
1274                        vec![
1275                            Special(Tab),
1276                            Char('q'),
1277                            Char('w'),
1278                            Char('e'),
1279                            Char('r'),
1280                            Char('t'),
1281                            Char('y'),
1282                            Char('u'),
1283                            Char('i'),
1284                            Char('o'),
1285                            Char('p'),
1286                            Char('['),
1287                            Char(']'),
1288                            Char('\\'),
1289                        ],
1290                        vec![
1291                            Special(Caps),
1292                            Char('a'),
1293                            Char('s'),
1294                            Char('d'),
1295                            Char('f'),
1296                            Char('g'),
1297                            Char('h'),
1298                            Char('j'),
1299                            Char('k'),
1300                            Char('l'),
1301                            Char(';'),
1302                            Char('\''),
1303                            Special(Enter),
1304                        ],
1305                        vec![
1306                            Special(Shift),
1307                            Char('z'),
1308                            Char('x'),
1309                            Char('c'),
1310                            Char('v'),
1311                            Char('b'),
1312                            Char('n'),
1313                            Char('m'),
1314                            Char(','),
1315                            Char('.'),
1316                            Char('/'),
1317                            Special(Shift),
1318                        ],
1319                        vec![
1320                            Empty,
1321                            Empty,
1322                            Magic {
1323                                label: "mgc".into()
1324                            },
1325                            Special(Space),
1326                            Layer {
1327                                label: "altgr".into(),
1328                            },
1329                            Empty,
1330                            Empty,
1331                            Char('ß'),
1332                        ],
1333                    ]),
1334                ),
1335                (
1336                    "shift".into(),
1337                    crate::Layer::from(vec![
1338                        vec![
1339                            Char('~'),
1340                            Char('!'),
1341                            Char('@'),
1342                            Char('#'),
1343                            Char('$'),
1344                            Char('%'),
1345                            Char('^'),
1346                            Char('&'),
1347                            Char('*'),
1348                            Char('('),
1349                            Char(')'),
1350                            Char('_'),
1351                            Char('+'),
1352                            Special(Backspace),
1353                        ],
1354                        vec![
1355                            Special(Tab),
1356                            Char('Q'),
1357                            Char('W'),
1358                            Char('E'),
1359                            Char('R'),
1360                            Char('T'),
1361                            Char('Y'),
1362                            Char('U'),
1363                            Char('I'),
1364                            Char('O'),
1365                            Char('P'),
1366                            Char('{'),
1367                            Char('}'),
1368                            Char('|'),
1369                        ],
1370                        vec![
1371                            Special(Caps),
1372                            Char('A'),
1373                            Char('S'),
1374                            Char('D'),
1375                            Char('F'),
1376                            Char('G'),
1377                            Char('H'),
1378                            Char('J'),
1379                            Char('K'),
1380                            Char('L'),
1381                            Char(':'),
1382                            Char('\"'),
1383                            Special(Enter),
1384                        ],
1385                        vec![
1386                            Special(Shift),
1387                            Char('Z'),
1388                            Char('X'),
1389                            Char('C'),
1390                            Char('V'),
1391                            Char('B'),
1392                            Char('N'),
1393                            Char('M'),
1394                            Char('<'),
1395                            Char('>'),
1396                            Char('?'),
1397                            Special(Shift),
1398                        ],
1399                        vec![
1400                            Empty,
1401                            Empty,
1402                            Magic {
1403                                label: "mgc".into()
1404                            },
1405                            Special(Space),
1406                            Word("altgr".into()),
1407                            Empty,
1408                            Empty,
1409                            Word("SS".into()),
1410                        ],
1411                    ]),
1412                ),
1413                (
1414                    "altgr".into(),
1415                    crate::Layer::from(vec![
1416                        vec![
1417                            Transparent,
1418                            Transparent,
1419                            Transparent,
1420                            Transparent,
1421                            Transparent,
1422                            Transparent,
1423                            Transparent,
1424                            Transparent,
1425                            Transparent,
1426                            Transparent,
1427                            Transparent,
1428                            Transparent,
1429                            Transparent,
1430                            Special(Backspace),
1431                        ],
1432                        vec![
1433                            Special(Tab),
1434                            Transparent,
1435                            Transparent,
1436                            Transparent,
1437                            Transparent,
1438                            Word("tb".into()),
1439                            Transparent,
1440                            Char('ü'),
1441                            Transparent,
1442                            Char('ö'),
1443                            Transparent,
1444                            Transparent,
1445                            Transparent,
1446                            Transparent,
1447                        ],
1448                        vec![
1449                            Special(Caps),
1450                            Char('ä'),
1451                            Transparent,
1452                            Transparent,
1453                            Transparent,
1454                            Magic {
1455                                label: "mgc2".into()
1456                            },
1457                            Transparent,
1458                            Transparent,
1459                            Transparent,
1460                            Transparent,
1461                            Transparent,
1462                            Transparent,
1463                            Special(Enter),
1464                        ],
1465                        vec![
1466                            Special(Shift),
1467                            Transparent,
1468                            Transparent,
1469                            Transparent,
1470                            Transparent,
1471                            Transparent,
1472                            Transparent,
1473                            Transparent,
1474                            Transparent,
1475                            Transparent,
1476                            Transparent,
1477                            Special(Shift),
1478                        ],
1479                        vec![
1480                            Empty,
1481                            Empty,
1482                            Magic {
1483                                label: "mgc".into()
1484                            },
1485                            Special(Space),
1486                            Transparent,
1487                            Empty,
1488                            Empty,
1489                            Empty,
1490                        ],
1491                    ]),
1492                ),
1493            ]),
1494            fingering: {
1495                Some(ParsedFingering::Explicit(Fingering::from(vec![
1496                    vec![LP, LP, LR, LM, LI, LI, RI, RI, RM, RR, RP, RP, RP, RP],
1497                    vec![LP, LP, LR, LM, LI, LI, RI, RI, RM, RR, RP, RP, RP, RP],
1498                    vec![LP, LP, LR, LM, LI, LI, RI, RI, RM, RR, RP, RP, RP],
1499                    vec![LP, LR, LM, LI, LI, LI, RI, RI, RM, RR, RP, RP],
1500                    vec![LP, LP, LT, LT, LT, RT, RT, RP],
1501                ])))
1502            },
1503            board: ParseKeyboard::Relative(RelativeKeyboard::from(vec![
1504                vec![
1505                    rk(1.0),
1506                    rk(1.0),
1507                    rk(1.0),
1508                    rk(1.0),
1509                    rk(1.0),
1510                    rk(1.0),
1511                    rk(1.0),
1512                    rk(1.0),
1513                    rk(1.0),
1514                    rk(1.0),
1515                    rk(1.0),
1516                    rk(1.0),
1517                    rk(1.0),
1518                    rk(2.0),
1519                ],
1520                vec![
1521                    rk(1.5),
1522                    rk(1.0),
1523                    rk(1.0),
1524                    rk(1.0),
1525                    rk(1.0),
1526                    rk(1.0),
1527                    rk(1.0),
1528                    rk(1.0),
1529                    rk(1.0),
1530                    rk(1.0),
1531                    rk(1.0),
1532                    rk(1.0),
1533                    rk(1.0),
1534                    rk(1.5),
1535                ],
1536                vec![
1537                    rk(1.75),
1538                    rk(1.0),
1539                    rk(1.0),
1540                    rk(1.0),
1541                    rk(1.0),
1542                    rk(1.0),
1543                    rk(1.0),
1544                    rk(1.0),
1545                    rk(1.0),
1546                    rk(1.0),
1547                    rk(1.0),
1548                    rk(1.0),
1549                    rk(2.25),
1550                ],
1551                vec![
1552                    rk(2.25),
1553                    rk(1.0),
1554                    rk(1.0),
1555                    rk(1.0),
1556                    rk(1.0),
1557                    rk(1.0),
1558                    rk(1.0),
1559                    rk(1.0),
1560                    rk(1.0),
1561                    rk(1.0),
1562                    rk(1.0),
1563                    rk(2.75),
1564                ],
1565                vec![
1566                    rk(1.25),
1567                    rk(1.25),
1568                    rk(1.25),
1569                    rk(6.25),
1570                    rk(1.25),
1571                    rk(1.25),
1572                    rk(1.25),
1573                    rk(1.25),
1574                ],
1575            ])),
1576            combos: Some(ParseCombos(BTreeMap::from([
1577                (
1578                    "main".to_string(),
1579                    BTreeMap::from([
1580                        (vec![ck(Char('d'), 0), ck(Char('f'), 0)], Char('x')),
1581                        (vec![ck(Char('j'), 0), ck(Char('k'), 0)], Char('6')),
1582                    ]),
1583                ),
1584                (
1585                    "shift".to_string(),
1586                    BTreeMap::from([(vec![ck(Special(Shift), 1), ck(Char('?'), 0)], Char('X'))]),
1587                ),
1588            ]))),
1589            magic: Some(crate::magic::Magic {
1590                keys: BTreeMap::from([
1591                    (
1592                        "mgc".into(),
1593                        MagicKey {
1594                            label: "mgc".into(),
1595                            rules: BTreeMap::from([
1596                                ("a".into(), "b".into()),
1597                                ("abc".into(), "defghijklmnopqrstuvwxyz".into()),
1598                            ]),
1599                            max_leading_length: 3,
1600                            max_output_length: 23,
1601                        },
1602                    ),
1603                    (
1604                        "mgc2".into(),
1605                        MagicKey {
1606                            label: "mgc2".into(),
1607                            rules: BTreeMap::from([("more".into(), " magic".into())]),
1608                            max_leading_length: 4,
1609                            max_output_length: 6,
1610                        },
1611                    ),
1612                ]),
1613            }),
1614        };
1615
1616        let dof_maximal = serde_json::from_str::<DofIntermediate>(maximal_json)
1617            .expect("couldn't parse explicit json");
1618
1619        assert_eq!(dof_maximal, maximal_test);
1620    }
1621
1622    #[test]
1623    fn lang_fn() {
1624        let languages = &[Language::new("English", 100)];
1625
1626        let languages = match languages {
1627            [lang] if lang == &Language::default() => None,
1628            _ => Some(languages),
1629        };
1630
1631        println!("{:?}", languages)
1632    }
1633}