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