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}
102