ucd_parse/
bidi_mirroring_glyph.rs

1use std::path::Path;
2
3use crate::{
4    common::{Codepoint, CodepointIter, UcdFile, UcdFileByCodepoint},
5    error::Error,
6};
7
8/// Represents a single row in the `BidiMirroring.txt` file.
9///
10/// The field names were taken from the header of BidiMirroring.txt.
11#[derive(Clone, Debug, Default, Eq, PartialEq)]
12pub struct BidiMirroring {
13    /// The codepoint corresponding to this row.
14    pub codepoint: Codepoint,
15    /// The codepoint that has typically has a glyph that is the mirror image
16    /// of `codepoint`.
17    pub bidi_mirroring_glyph: Codepoint,
18}
19
20impl UcdFile for BidiMirroring {
21    fn relative_file_path() -> &'static Path {
22        Path::new("BidiMirroring.txt")
23    }
24}
25
26impl UcdFileByCodepoint for BidiMirroring {
27    fn codepoints(&self) -> CodepointIter {
28        self.codepoint.into_iter()
29    }
30}
31
32impl std::str::FromStr for BidiMirroring {
33    type Err = Error;
34
35    fn from_str(line: &str) -> Result<BidiMirroring, Error> {
36        let re_parts = regex!(
37            r"(?x)
38                ^
39                \s*(?P<codepoint>[A-F0-9]+)\s*;
40                \s*(?P<substitute_codepoint>[A-F0-9]+)
41                \s+
42                \#(?:.+)
43                $
44                ",
45        );
46        let caps = match re_parts.captures(line.trim()) {
47            Some(caps) => caps,
48            None => return err!("invalid BidiMirroring line"),
49        };
50
51        Ok(BidiMirroring {
52            codepoint: caps["codepoint"].parse()?,
53            bidi_mirroring_glyph: caps["substitute_codepoint"].parse()?,
54        })
55    }
56}
57
58impl std::fmt::Display for BidiMirroring {
59    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60        write!(f, "{};", self.codepoint)?;
61        write!(f, "{};", self.bidi_mirroring_glyph)?;
62        Ok(())
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use crate::common::Codepoint;
69
70    use super::BidiMirroring;
71
72    fn codepoint(n: u32) -> Codepoint {
73        Codepoint::from_u32(n).unwrap()
74    }
75
76    #[test]
77    fn parse() {
78        let line = "0028; 0029 # LEFT PARENTHESIS\n";
79        let data: BidiMirroring = line.parse().unwrap();
80        assert_eq!(
81            data,
82            BidiMirroring {
83                codepoint: codepoint(0x0028),
84                bidi_mirroring_glyph: codepoint(0x0029),
85            }
86        );
87    }
88
89    #[test]
90    fn parse_best_fit() {
91        let line = "228A; 228B # [BEST FIT] SUBSET OF WITH NOT EQUAL TO\n";
92        let data: BidiMirroring = line.parse().unwrap();
93        assert_eq!(
94            data,
95            BidiMirroring {
96                codepoint: codepoint(0x228A),
97                bidi_mirroring_glyph: codepoint(0x228B),
98            }
99        );
100    }
101}