globetrotter_model/
lib.rs1#![allow(warnings)]
2
3pub mod diagnostics;
4pub mod ext;
5pub mod json;
6pub mod language;
7pub mod toml;
8pub mod validation;
9
10use diagnostics::{DisplayRepr, FileId, Spanned};
11pub use indexmap::IndexMap;
12pub use language::Language;
13
14use serde::{Deserialize, Serialize};
15
16#[derive(
17 Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, strum::Display,
18)]
19pub enum TemplateEngine {
20 #[serde(rename = "handlebars")]
21 Handlebars,
22 #[serde(rename = "golang", alias = "go")]
23 Golang,
24 #[serde(rename = "mustache")]
25 Mustache,
26 #[serde(rename = "jinja2")]
27 Jinja2,
28 Other(String),
29}
30
31impl std::str::FromStr for TemplateEngine {
32 type Err = ::strum::ParseError;
33
34 fn from_str(s: &str) -> Result<Self, Self::Err> {
35 s.parse()
36 }
37}
38
39#[derive(
40 Copy,
41 Clone,
42 Debug,
43 PartialEq,
44 Eq,
45 PartialOrd,
46 Ord,
47 Hash,
48 strum::Display,
49 strum::EnumString,
50 strum::VariantNames,
51 strum::IntoStaticStr,
52 strum::EnumCount,
53 strum::EnumIter,
54 Serialize,
55 Deserialize,
56)]
57pub enum ArgumentType {
58 #[serde(rename = "any")]
59 #[strum(to_string = "any", serialize = "any")]
60 Any,
61 #[serde(rename = "string")]
62 #[strum(to_string = "string", serialize = "string")]
63 String,
64 #[serde(rename = "number")]
65 #[strum(to_string = "number", serialize = "number")]
66 Number,
67 #[serde(rename = "isodatetime")]
68 #[strum(to_string = "isodatetime", serialize = "isodatetime")]
69 Iso8601DateTimeString,
70 }
83
84impl ArgumentType {
85 #[must_use]
86 pub fn display(&self) -> DisplayRepr<'_, Self> {
87 DisplayRepr(self)
88 }
89}
90
91pub type Arguments = IndexMap<String, ArgumentType>;
92pub type LanguageTranslations = IndexMap<Language, Spanned<String>>;
93
94#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
95pub struct Translation {
96 #[serde(flatten)]
97 pub language: LanguageTranslations,
98 #[serde(skip_serializing_if = "Arguments::is_empty")]
99 pub arguments: Arguments,
100 #[serde(skip)]
101 pub file_id: FileId,
102}
103
104impl std::fmt::Display for Translation {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 f.debug_struct("Translation")
107 .field(
108 "arguments",
109 &self
110 .arguments
111 .iter()
112 .map(|(k, v)| (k, v.display()))
113 .collect::<IndexMap<_, _>>(),
114 )
115 .field(
116 "language",
117 &self
118 .language
119 .iter()
120 .map(|(k, v)| (k, v.display()))
121 .collect::<IndexMap<_, _>>(),
122 )
123 .field("file_id", &self.file_id)
124 .finish()
125 }
126}
127
128impl Translation {
129 #[must_use]
130 pub fn is_empty(&self) -> bool {
131 self.arguments.is_empty() && self.language.is_empty()
132 }
133
134 #[must_use]
135 pub fn is_template(&self) -> bool {
136 !self.arguments.is_empty()
137 }
138}
139
140#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
141pub struct Translations(pub IndexMap<Spanned<String>, Translation>);
142
143impl Translations {
144 #[cfg(not(feature = "rayon"))]
145 pub fn sort(&mut self) {
146 self.0.sort_keys();
147 for (_key, translation) in self.0.iter_mut() {
148 translation.arguments.sort_keys();
149 translation.language.sort_keys();
150 }
151 }
152
153 #[cfg(feature = "rayon")]
154 pub fn sort(&mut self) {
155 use rayon::prelude::*;
156 self.0.par_sort_keys();
157 for translation in self.0.values_mut() {
158 translation.arguments.par_sort_keys();
159 translation.language.par_sort_keys();
160 }
161 }
162
163 #[must_use]
164 pub fn iter(&self) -> indexmap::map::Iter<'_, Spanned<String>, Translation> {
165 self.0.iter()
166 }
167
168 #[must_use]
169 pub fn len(&self) -> usize {
170 self.0.len()
171 }
172
173 #[must_use]
174 pub fn is_empty(&self) -> bool {
175 self.0.is_empty()
176 }
177}
178
179impl FromIterator<(Spanned<String>, Translation)> for Translations {
180 fn from_iter<T: IntoIterator<Item = (Spanned<String>, Translation)>>(iter: T) -> Self {
181 Self(iter.into_iter().collect())
182 }
183}
184
185impl<'a> IntoIterator for &'a Translations {
186 type Item = (&'a Spanned<String>, &'a Translation);
187 type IntoIter = indexmap::map::Iter<'a, Spanned<String>, Translation>;
188
189 fn into_iter(self) -> Self::IntoIter {
190 self.0.iter()
191 }
192}
193
194impl IntoIterator for Translations {
195 type Item = (Spanned<String>, Translation);
196 type IntoIter = indexmap::map::IntoIter<Spanned<String>, Translation>;
197
198 fn into_iter(self) -> Self::IntoIter {
199 self.0.into_iter()
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 static INIT: std::sync::Once = std::sync::Once::new();
206
207 pub fn init() {
211 INIT.call_once(|| {
212 color_eyre::install().ok();
213 });
214 }
215}