glossa_codegen/
generator.rs1pub(crate) mod flattening;
2mod init_lazy_data;
3pub(crate) mod locales;
4mod router;
5
6pub(crate) mod output_bincode;
7pub(crate) mod output_match;
8pub(crate) mod output_phf;
9
10use std::{io, path::PathBuf, sync::OnceLock};
11
12use getset::{Getters, MutGetters, WithSetters};
13use glossa_shared::{fmt_compact, tap::Pipe};
14pub use output_phf::to_lower_snake_case;
15
16use crate::{
17 L10nResources, MiniStr, Visibility,
18 generator::flattening::{L10nDSLMaps, L10nMaps},
19 internal_aliases::HighlightCfgMap,
20};
21
22#[derive(Getters, WithSetters, MutGetters, Debug, Clone)]
23#[getset(get = "pub with_prefix", set_with = "pub", get_mut = "pub with_prefix")]
24pub struct Generator<'h> {
25 #[getset(skip)]
26 #[getset(get = "pub")]
27 resources: Box<L10nResources>,
28
29 #[getset(get_mut)]
30 visibility: Visibility,
32
33 mod_visibility: Visibility,
34
35 #[getset(skip)]
36 #[getset(get = "pub", get_mut = "pub")]
37 outdir: Option<PathBuf>,
38
39 bincode_suffix: MiniStr,
40 mod_prefix: MiniStr,
41 feature_prefix: MiniStr,
42
43 #[getset(skip)]
44 #[getset(get = "pub")]
45 highlight: Option<Box<HighlightCfgMap<'h>>>,
46
47 #[getset(skip)]
48 lazy_maps: Box<LazyMaps>,
50}
51
52#[cfg(feature = "highlight")]
53impl<'h> Generator<'h> {
54 pub fn with_highlight(mut self, highlight: HighlightCfgMap<'h>) -> Self {
55 self.highlight = Some(highlight.into());
56 self.clear_highlight_cache();
57 self
58 }
59
60 pub fn set_highlight(&mut self, highlight: Option<HighlightCfgMap<'h>>) {
61 self.highlight = highlight.map(|data| data.into());
62 self.clear_highlight_cache();
63 }
64 fn clear_highlight_cache(&mut self) {
65 self.lazy_maps.highlight.take();
66 self.lazy_maps.merged.take();
67 }
68}
69
70impl Generator<'_> {
71 pub fn with_outdir<P: Into<PathBuf>>(mut self, outdir: P) -> Self {
72 self.outdir = Some(outdir.into());
73 self
74 }
75}
76
77impl Generator<'_> {
78 pub fn with_resources(mut self, resources: L10nResources) -> Self {
105 self.resources = resources.into();
106 self.lazy_maps = Default::default();
107 self
108 }
109}
110
111#[derive(Default, Debug, Clone)]
112struct LazyMaps {
113 regular: OnceLock<L10nMaps>,
115
116 highlight: OnceLock<Option<L10nMaps>>,
118
119 dsl: OnceLock<L10nDSLMaps>,
121
122 merged: OnceLock<L10nMaps>,
124}
125
126impl Default for Generator<'_> {
127 fn default() -> Self {
139 Self {
140 bincode_suffix: MiniStr::const_new(".bincode"),
141 outdir: Default::default(),
142 resources: Default::default(),
143 mod_prefix: MiniStr::const_new("l10n_"),
146 feature_prefix: MiniStr::const_new("l10n-"),
147 visibility: Default::default(),
150 mod_visibility: Visibility::Private,
151 highlight: Default::default(),
152 lazy_maps: Default::default(),
153 }
154 }
155}
156
157#[derive(Debug, Clone, Copy)]
158pub enum MapType {
159 Regular,
160 Highlight,
161 RegularAndHighlight,
162 DSL,
163}
164
165impl core::str::FromStr for MapType {
166 type Err = io::Error;
167
168 fn from_str(s: &str) -> Result<Self, Self::Err> {
169 use MapType::*;
170 match s {
171 "regular" | "r" => Regular,
172 "highlight" | "h" => Highlight,
173 "dsl" | "tmpl" => DSL,
174 "regular-and-highlight" | "regularandhighlight" | "_" => RegularAndHighlight,
175 other => Err(io::Error::new(
176 io::ErrorKind::InvalidInput,
177 fmt_compact!(
178 r#"
179 Expected: "regular" | "highlight" | "dsl" | "_"
180 Actual: "{other}""#
181 ),
182 ))?,
183 }
184 .pipe(Ok)
185 }
186}
187
188impl MapType {
189 pub fn get_non_dsl_maps<'a>(
190 &self,
191 generator: &'a Generator<'a>,
192 ) -> io::Result<&'a L10nMaps> {
193 use MapType::*;
194 match self {
195 Regular => generator.get_or_init_maps(),
196 Highlight => generator
197 .get_or_init_highlight_maps()
198 .ok_or_else(|| io::Error::other("Failed to get highlight maps"))?,
199 RegularAndHighlight => generator.get_or_init_merged_maps(),
200 _ => return io::Error::other("DSL Maps are not supported.").pipe(Err),
201 }
202 .pipe(Ok)
203 }
204
205 #[cfg(feature = "ron")]
206 pub fn output_ron<'a>(
207 &self,
208 generator: &'a Generator<'a>,
209 ) -> crate::AnyResult<String> {
210 use ron::ser::PrettyConfig;
211
212 let cfg = PrettyConfig::new()
213 .depth_limit(5)
214 .separate_tuple_members(false);
215
216 match self.is_dsl() {
217 true => ron::ser::to_string_pretty(generator.get_or_init_dsl_maps(), cfg)?,
218 _ => ron::ser::to_string_pretty(self.get_non_dsl_maps(generator)?, cfg)?,
219 }
220 .pipe(Ok)
221 }
222
223 #[must_use]
227 pub fn is_dsl(&self) -> bool {
228 matches!(self, Self::DSL)
229 }
230}
231
232impl Default for MapType {
233 fn default() -> Self {
234 Self::DSL
235 }
236}
237
238#[cfg(test)]
239pub(crate) mod dbg_generator {
240 use super::*;
241 use crate::resources::dbg_shared;
242
243 pub(crate) fn new_generator<'h>() -> Generator<'h> {
244 let data = dbg_shared::new_resources();
245 Generator::default()
246 .with_resources(data)
247 .with_outdir("tmp")
248 }
249
250 #[cfg(feature = "highlight")]
251 pub(crate) fn highlight_generator<'h>() -> Generator<'h> {
252 let hmap = crate::highlight::dbg_shared::new_highlight_map();
253 new_generator().with_highlight(hmap)
254 }
255
256 pub(crate) fn en_generator<'h>() -> Generator<'h> {
257 let data = dbg_shared::new_resources().with_include_languages(["en"]);
258 new_generator().with_resources(data)
259 }
260
261 pub(crate) fn en_gb_generator<'h>() -> Generator<'h> {
262 let data = dbg_shared::new_resources().with_include_languages(["en-GB"]);
263 new_generator().with_resources(data)
264 }
265
266 pub(crate) fn es_generator<'h>() -> Generator<'h> {
267 let data = dbg_shared::new_resources().with_include_languages(["es"]);
269 new_generator().with_resources(data)
270 }
271
272 pub(crate) fn de_en_fr_pt_zh_generator<'h>() -> Generator<'h> {
273 let data = dbg_shared::new_resources()
274 .with_include_languages([
275 "de", "zh", "pt", "fr", "en", "en-GB",
277 ])
278 .with_include_map_names(["yes-no"]);
279 new_generator().with_resources(data)
280 }
281}