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: Codepoints, value: &str) = 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: Vec, comment: String) = 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}
105