kutil_http/headers/
language.rs

1use super::super::cache::*;
2
3use {
4    http::header::*,
5    kutil_std::{collections::*, foster::*, *},
6    std::{convert::*, fmt, str::*},
7};
8
9//
10// Language
11//
12
13/// Language tag value in HTTP headers.
14///
15/// See [IETF RFC 5646 section 2.1](https://datatracker.ietf.org/doc/html/rfc5646#section-2.1).
16///
17/// Stored as a sequence of subtags.
18///
19/// Note that even though ISO recommends cased representations, they are case-insensitive in HTTP.
20/// Thus we convert all subtags to lowercase for comparison efficiency.
21#[derive(Clone, Debug)]
22pub struct Language(pub FosterByteStringVector);
23
24delegate_newtype_of_foster_byte_string_vector!(Language);
25
26impl Language {
27    /// Parse list.
28    pub fn parse_list(representation: &str) -> Option<FastHashSet<Self>> {
29        let languages: FastHashSet<_> = representation.split(",").map(|language| language.trim().into()).collect();
30        if !languages.is_empty() { Some(languages) } else { None }
31    }
32}
33
34impl CacheWeight for Language {
35    fn cache_weight(&self) -> usize {
36        const SELF_SIZE: usize = size_of::<Language>();
37        let mut size = SELF_SIZE;
38        for subtag in &self.0 {
39            size += subtag.len();
40        }
41        size
42    }
43}
44
45impl Into<HeaderValue> for Language {
46    fn into(self) -> HeaderValue {
47        HeaderValue::from_str(&self.to_string()).expect("should be safe")
48    }
49}
50
51impl From<&str> for Language {
52    fn from(representation: &str) -> Self {
53        Self::new_owned(representation.split("-").map(|subtag| subtag.to_lowercase().into()).collect())
54    }
55}
56
57impl FromStr for Language {
58    type Err = Infallible;
59
60    fn from_str(representation: &str) -> Result<Self, Self::Err> {
61        Ok(representation.into())
62    }
63}
64
65impl fmt::Display for Language {
66    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
67        match &self.0 {
68            Foster::Owned(subtags) => fmt::Display::fmt(&subtags.join("-"), formatter),
69            Foster::Fostered(subtags) => fmt::Display::fmt(&subtags.join("-"), formatter),
70        }
71    }
72}