json_gettext/key_string/
json_gettext.rs

1use std::collections::HashMap;
2
3use regex::Regex;
4
5use super::{Context, JSONGetTextBuilder};
6use crate::{JSONGetTextBuildError, JSONGetTextValue};
7
8/// A wrapper for context and a default key. **Keys** are usually considered as locales.
9#[derive(Debug)]
10pub struct JSONGetText<'a> {
11    default_key: String,
12    context:     Context<'a>,
13}
14
15impl<'a> JSONGetText<'a> {
16    /// Create a new `JSONGetTextBuilder` instance. You need to decide your default key at the stage.
17    #[inline]
18    pub fn build<S: Into<String>>(default_key: S) -> JSONGetTextBuilder<'a> {
19        JSONGetTextBuilder::new(default_key)
20    }
21
22    /// Create a new JSONGetText instance with context and a default key.
23    pub(crate) fn from_context_with_default_key<S: AsRef<str> + Into<String>>(
24        default_key: S,
25        mut context: Context<'a>,
26    ) -> Result<JSONGetText<'a>, JSONGetTextBuildError> {
27        if !context.contains_key(default_key.as_ref()) {
28            return Err(JSONGetTextBuildError::DefaultKeyNotFound);
29        }
30
31        let default_key = default_key.into();
32
33        let default_map = context.remove(&default_key).unwrap();
34
35        let mut inner_context = HashMap::new();
36
37        {
38            for (key, mut map) in context {
39                {
40                    for map_key in map.keys() {
41                        if !default_map.contains_key(map_key) {
42                            return Err(JSONGetTextBuildError::TextInKeyNotInDefaultKey {
43                                key,
44                                text: map_key.clone(),
45                            });
46                        }
47                    }
48                }
49
50                {
51                    for map_key in default_map.keys() {
52                        if !map.contains_key(map_key) {
53                            map.insert(map_key.clone(), default_map.get(map_key).unwrap().clone());
54                        }
55                    }
56                }
57
58                inner_context.insert(key, map);
59            }
60
61            inner_context.insert(default_key.clone().into(), default_map);
62        }
63
64        Ok(JSONGetText {
65            default_key,
66            context: inner_context,
67        })
68    }
69
70    /// Get all keys in context.
71    pub fn get_keys(&self) -> Vec<&str> {
72        self.context.keys().map(|key| key.as_str()).collect()
73    }
74
75    /// Returns `true` if the context contains a value for the specified key.
76    #[inline]
77    pub fn contains_key<K: AsRef<str>>(&self, key: K) -> bool {
78        self.context.contains_key(key.as_ref())
79    }
80
81    /// Get the default key.
82    #[inline]
83    pub fn get_default_key(&self) -> &str {
84        &self.default_key
85    }
86
87    /// Get a string map from context by a key.
88    #[inline]
89    pub fn get<K: AsRef<str>>(&self, key: K) -> &HashMap<String, JSONGetTextValue<'a>> {
90        match self.context.get(key.as_ref()) {
91            Some(m) => m,
92            None => self.context.get(&self.default_key).unwrap(),
93        }
94    }
95
96    /// Get text from context.
97    #[inline]
98    pub fn get_text<T: AsRef<str>>(&'a self, text: T) -> Option<JSONGetTextValue<'a>> {
99        let map = self.context.get(&self.default_key).unwrap();
100
101        map.get(text.as_ref()).map(|v| v.clone_borrowed())
102    }
103
104    /// Get text from context with a specific key.
105    #[inline]
106    pub fn get_text_with_key<K: AsRef<str>, T: AsRef<str>>(
107        &'a self,
108        key: K,
109        text: T,
110    ) -> Option<JSONGetTextValue<'a>> {
111        let map = self
112            .context
113            .get(key.as_ref())
114            .unwrap_or_else(|| self.context.get(&self.default_key).unwrap());
115
116        map.get(text.as_ref()).map(|v| v.clone_borrowed())
117    }
118
119    /// Get multiple text from context. The output map is usually used for serialization.
120    pub fn get_multiple_text<'b, T: AsRef<str> + ?Sized>(
121        &self,
122        text_array: &[&'b T],
123    ) -> Option<HashMap<&'b str, JSONGetTextValue>> {
124        let map = self.context.get(&self.default_key).unwrap();
125
126        let mut new_map = HashMap::new();
127
128        for &text in text_array.iter() {
129            let text = text.as_ref();
130            let value = map.get(text)?;
131            new_map.insert(text, value.clone_borrowed());
132        }
133
134        Some(new_map)
135    }
136
137    /// Get multiple text from context with a specific key. The output map is usually used for serialization.
138    pub fn get_multiple_text_with_key<'b, K: AsRef<str>, T: AsRef<str> + ?Sized>(
139        &'a self,
140        key: K,
141        text_array: &[&'b T],
142    ) -> Option<HashMap<&'b str, JSONGetTextValue<'a>>> {
143        let map = self
144            .context
145            .get(key.as_ref())
146            .unwrap_or_else(|| self.context.get(&self.default_key).unwrap());
147
148        let mut new_map = HashMap::new();
149
150        for &text in text_array.iter() {
151            let text = text.as_ref();
152            let value = map.get(text)?;
153            new_map.insert(text, value.clone_borrowed());
154        }
155
156        Some(new_map)
157    }
158
159    /// Get filtered text from context by a Regex instance. The output map is usually used for serialization.
160    pub fn get_filtered_text(
161        &'a self,
162        regex: &Regex,
163    ) -> Option<HashMap<&'a str, JSONGetTextValue<'a>>> {
164        let map = self.context.get(&self.default_key).unwrap();
165
166        let mut new_map = HashMap::new();
167
168        for (key, value) in map.iter() {
169            if !regex.is_match(key) {
170                continue;
171            }
172            new_map.insert(key.as_str(), value.clone_borrowed());
173        }
174
175        Some(new_map)
176    }
177
178    /// Get filtered text from context with a specific key by a Regex instance. The output map is usually used for serialization.
179    pub fn get_filtered_text_with_key<K: AsRef<str>>(
180        &'a self,
181        key: K,
182        regex: &Regex,
183    ) -> Option<HashMap<&'a str, JSONGetTextValue<'a>>> {
184        let map = self
185            .context
186            .get(key.as_ref())
187            .unwrap_or_else(|| self.context.get(&self.default_key).unwrap());
188
189        let mut new_map = HashMap::new();
190
191        for (key, value) in map.iter() {
192            if !regex.is_match(key) {
193                continue;
194            }
195            new_map.insert(key.as_str(), value.clone_borrowed());
196        }
197
198        Some(new_map)
199    }
200}