ucd_parse/
word_break.rs

1use std::path::Path;
2
3use crate::{
4    common::{
5        parse_break_test, parse_codepoint_association, CodepointIter,
6        Codepoints, UcdFile, UcdFileByCodepoint,
7    },
8    error::Error,
9};
10
11/// A single row in the `auxiliary/WordBreakProperty.txt` file.
12#[derive(Clone, Debug, Default, Eq, PartialEq)]
13pub struct WordBreak {
14    /// The codepoint or codepoint range for this entry.
15    pub codepoints: Codepoints,
16    /// The property value assigned to the codepoints in this entry.
17    pub value: String,
18}
19
20impl UcdFile for WordBreak {
21    fn relative_file_path() -> &'static Path {
22        Path::new("auxiliary/WordBreakProperty.txt")
23    }
24}
25
26impl UcdFileByCodepoint for WordBreak {
27    fn codepoints(&self) -> CodepointIter {
28        self.codepoints.into_iter()
29    }
30}
31
32impl std::str::FromStr for WordBreak {
33    type Err = Error;
34
35    fn from_str(line: &str) -> Result<WordBreak, Error> {
36        let (codepoints, value) = parse_codepoint_association(line)?;
37        Ok(WordBreak { codepoints, value: value.to_string() })
38    }
39}
40
41/// A single row in the `auxiliary/WordBreakTest.txt` file.
42///
43/// This file defines tests for the word break algorithm.
44#[derive(Clone, Debug, Default, Eq, PartialEq)]
45pub struct WordBreakTest {
46    /// Each string is a UTF-8 encoded group of codepoints that make up a
47    /// single word.
48    pub words: Vec<String>,
49    /// A human readable description of this test.
50    pub comment: String,
51}
52
53impl UcdFile for WordBreakTest {
54    fn relative_file_path() -> &'static Path {
55        Path::new("auxiliary/WordBreakTest.txt")
56    }
57}
58
59impl std::str::FromStr for WordBreakTest {
60    type Err = Error;
61
62    fn from_str(line: &str) -> Result<WordBreakTest, Error> {
63        let (groups, comment) = parse_break_test(line)?;
64        Ok(WordBreakTest { words: groups, comment })
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::{WordBreak, WordBreakTest};
71
72    #[test]
73    fn parse_single() {
74        let line = "0A83          ; Extend # Mc       GUJARATI SIGN VISARGA\n";
75        let row: WordBreak = line.parse().unwrap();
76        assert_eq!(row.codepoints, 0x0A83);
77        assert_eq!(row.value, "Extend");
78    }
79
80    #[test]
81    fn parse_range() {
82        let line = "104A0..104A9  ; Numeric # Nd  [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE\n";
83        let row: WordBreak = line.parse().unwrap();
84        assert_eq!(row.codepoints, (0x104A0, 0x104A9));
85        assert_eq!(row.value, "Numeric");
86    }
87
88    #[test]
89    fn parse_test() {
90        let line = "÷ 0031 ÷ 0027 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷	#  ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3]";
91
92        let row: WordBreakTest = line.parse().unwrap();
93        assert_eq!(
94            row.words,
95            vec![
96                "\u{0031}",
97                "\u{0027}\u{0308}",
98                "\u{0061}",
99                "\u{0027}\u{2060}",
100            ]
101        );
102        assert!(row.comment.contains("[4.0] COMBINING DIAERESIS (Extend_FE)"));
103    }
104}