Skip to main content

ferroui_base/utilities/
text_info.rs

1//! A minimal counterpart of .NET's `System.Globalization.TextInfo`: the
2//! text conventions of a culture the framework reads (the list separator).
3
4use super::i_culture_data_provider::find_culture_data;
5use super::CultureInfo;
6use std::rc::Rc;
7
8crate::ferro_thread_local! {
9    static INVARIANT: Rc<TextInfo> = Rc::new(TextInfo::new());
10}
11
12/// The text conventions of a culture (C# `TextInfo`).
13///
14/// Only the conventions of the invariant culture are built in: those of
15/// other cultures come from the provider registered with the locator (see
16/// [`ICultureDataProvider`](super::ICultureDataProvider)); a culture without
17/// data gets the conventions of its nearest parent that has data and finally
18/// the invariant ones.
19#[derive(Clone, Debug, PartialEq, Eq)]
20pub struct TextInfo {
21    list_separator: String,
22}
23
24impl TextInfo {
25    /// The conventions of the invariant culture, to be changed with the
26    /// setters.
27    pub fn new() -> TextInfo {
28        TextInfo { list_separator: ",".to_owned() }
29    }
30
31    /// The conventions of `culture`: the data the registered provider has
32    /// for the culture or the nearest of its parents, else the invariant
33    /// data.
34    pub(crate) fn for_culture(culture: &CultureInfo) -> Rc<TextInfo> {
35        find_culture_data(culture, |provider, name| provider.get_text_info(name)).unwrap_or_else(Self::invariant_info)
36    }
37
38    /// The conventions of the invariant culture.
39    pub fn invariant_info() -> Rc<TextInfo> {
40        INVARIANT.with(Rc::clone)
41    }
42
43    /// The conventions of the current culture.
44    pub fn current_info() -> Rc<TextInfo> {
45        CultureInfo::current_culture().text_info()
46    }
47
48    /// Gets the string that separates items in a list (C# `ListSeparator`).
49    pub fn list_separator(&self) -> &str {
50        &self.list_separator
51    }
52
53    /// Sets the string that separates items in a list.
54    pub fn set_list_separator(&mut self, value: impl Into<String>) {
55        self.list_separator = value.into();
56    }
57
58    /// The conventions with the given list separator.
59    pub fn with_list_separator(mut self, value: impl Into<String>) -> Self {
60        self.set_list_separator(value);
61        self
62    }
63}
64
65impl Default for TextInfo {
66    fn default() -> Self {
67        Self::new()
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn invariant_list_separator_is_a_comma() {
77        assert_eq!(",", CultureInfo::invariant_culture().text_info().list_separator());
78        assert_eq!(",", TextInfo::invariant_info().list_separator());
79    }
80
81    #[test]
82    fn culture_without_data_uses_the_invariant_list_separator() {
83        assert_eq!(",", CultureInfo::get_culture_info("pl-PL").text_info().list_separator());
84    }
85
86    #[test]
87    fn list_separator_can_be_changed() {
88        let info = TextInfo::new().with_list_separator(";");
89        assert_eq!(";", info.list_separator());
90    }
91}