unicode_locale_parser/extensions/
other.rs1use crate::constants::SEP;
2use crate::errors::ParserError;
3
4use std::fmt::{self, Write};
5use std::iter::Peekable;
6
7#[derive(Debug, PartialEq)]
8pub struct OtherExtensions {
9 pub values: Vec<String>,
10 pub extension: char,
11}
12
13impl fmt::Display for OtherExtensions {
14 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15 f.write_char(self.extension)?;
16 for value in &self.values {
17 f.write_char(SEP)?;
18 f.write_str(value)?;
19 }
20 Ok(())
21 }
22}
23
24pub fn parse_other_extensions<'a>(
25 iter: &mut Peekable<impl Iterator<Item = &'a str>>,
26 extension: char,
27) -> Result<OtherExtensions, ParserError> {
28 let mut values = vec![];
31
32 while let Some(subtag) = iter.peek() {
33 if subtag.len() == 1 {
34 break;
35 } else {
36 values.push(String::from(parse_value(subtag)?));
37 iter.next();
38 }
39 }
40
41 Ok(OtherExtensions { values, extension })
42}
43
44fn is_other_value_subtag(subtag: &[u8]) -> bool {
45 (2..=8).contains(&subtag.len()) && subtag.iter().all(|c| c.is_ascii_alphanumeric())
46}
47
48fn parse_value(subtag: &str) -> Result<&str, ParserError> {
49 if !is_other_value_subtag(subtag.as_bytes()) {
50 Err(ParserError::InvalidSubtag)
51 } else {
52 Ok(subtag)
53 }
54}
55
56#[allow(unused_imports)] use crate::shared::split_str;
62
63#[test]
64fn success_other_extensions() {
65 let mut iter = split_str("abc-123").peekable();
67 assert_eq!(
68 vec!["abc", "123"],
69 parse_other_extensions(&mut iter, 'a').unwrap().values
70 );
71
72 let mut iter = split_str("abc-123").peekable();
74 assert_eq!(
75 "b-abc-123",
76 format!("{}", parse_other_extensions(&mut iter, 'b').unwrap())
77 );
78}
79
80#[test]
81fn fail_pu_extensions() {
82 let mut iter = split_str("abc-123456789").peekable();
84 assert_eq!(
85 ParserError::InvalidSubtag,
86 parse_other_extensions(&mut iter, '1').unwrap_err()
87 );
88}