1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use crate::parser::errors::ParserError;

pub fn parse_language_subtag(subtag: &str) -> Result<Option<String>, ParserError> {
    let slen = subtag.len();

    if slen < 2 || slen > 8 || slen == 4 || subtag.contains(|c: char| !c.is_ascii_alphabetic()) {
        return Err(ParserError::InvalidLanguage);
    }

    let value = subtag.to_ascii_lowercase();

    if value == "und" {
        Ok(None)
    } else {
        Ok(Some(value))
    }
}

pub fn parse_script_subtag(subtag: &str) -> Result<String, ParserError> {
    let slen = subtag.len();

    if slen != 4 || subtag.contains(|c: char| !c.is_ascii_alphabetic()) {
        return Err(ParserError::InvalidSubtag);
    }
    let mut result = subtag.to_ascii_lowercase();
    result[0..1].make_ascii_uppercase();
    Ok(result)
}

pub fn parse_region_subtag(subtag: &str) -> Result<String, ParserError> {
    let slen = subtag.len();

    if slen == 2 && !subtag.contains(|c: char| !c.is_ascii_alphabetic())
        || slen == 3 && !subtag.contains(|c: char| !c.is_ascii_digit())
    {
        Ok(subtag.to_ascii_uppercase())
    } else {
        Err(ParserError::InvalidSubtag)
    }
}

pub fn parse_variant_subtag(subtag: &str) -> Result<String, ParserError> {
    let slen = subtag.len();

    if slen < 4 || slen > 8 {
        return Err(ParserError::InvalidSubtag);
    }

    if slen >= 5 && subtag.contains(|c: char| !c.is_ascii_alphanumeric()) {
        return Err(ParserError::InvalidSubtag);
    }

    if slen == 4
        && !subtag.as_bytes()[0].is_ascii_digit()
        && subtag[1..].contains(|c: char| !c.is_ascii_alphanumeric())
    {
        return Err(ParserError::InvalidSubtag);
    }

    Ok(subtag.to_ascii_lowercase())
}