glossa_codegen/generator/
router.rs

1use std::io;
2
3use glossa_shared::{
4  fmt_compact,
5  tap::{Pipe, Tap},
6};
7
8use crate::{
9  Generator,
10  generator::{MapType, locales::ensure_length_equal},
11};
12
13impl Generator<'_> {
14  /// Generates a function that routes to the appropriate module and extracts
15  /// the corresponding value.
16  ///
17  /// Example: `self.output_router_for_match_fns(MapType::Regular, false)?`
18  ///
19  /// Output String Sample:
20  ///
21  /// ```ignore
22  /// pub const fn map(language: &[u8], key: &[u8]) -> &'static str {
23  ///   use super::*;
24  ///   match language {
25  ///     #[cfg(feature = "l10n-de")]
26  ///     b"de" => l10n_de::map(key),
27  ///     #[cfg(feature = "l10n-en-GB")]
28  ///     b"en-GB" => l10n_en_gb::map(key),
29  ///     _ => "",
30  ///   }
31  /// }
32  /// ```
33  pub fn output_router_for_match_fns(
34    &self,
35    map_type: MapType,
36    contains_map_name: bool,
37  ) -> io::Result<String> {
38    let header = format!(
39      "const fn map(language: &[u8], {opt_parm}key: &[u8]) -> &'static str {{
40      use super::*;
41      match language {{
42    ",
43      opt_parm = if contains_map_name { "map_name: &[u8], " } else { "" }
44    );
45
46    let new_header = || self.new_fn_header(&header);
47
48    let locales = self.collect_raw_locales(map_type)?;
49    let features = self.collect_cargo_feature_names(map_type)?;
50    let modules = self.collect_rs_mod_names(map_type)?;
51    ensure_length_equal(features.len(), modules.len())?;
52
53    features
54      .iter()
55      .zip(modules)
56      .zip(locales)
57      .fold(
58        new_header(), //
59        |mut acc, ((feat, mod_name), locale)| {
60          let cfg_line = fmt_compact!("  #[cfg(feature = \"{feat}\")]\n  ");
61          let match_line = match contains_map_name {
62            true => {
63              fmt_compact!(r##"b"{locale}" => {mod_name}::map(map_name, key),"##)
64            }
65            _ => fmt_compact!(r##"b"{locale}" => {mod_name}::map(key),"##),
66          };
67          [cfg_line, match_line]
68            .iter()
69            .for_each(|s| acc.push_str(s));
70          acc.push('\n');
71          acc
72        },
73      )
74      .tap_mut(|buf| buf.push_str("  _ => \"\",\n}}"))
75      .pipe(Ok)
76  }
77
78  /// Generates a function that routes to the appropriate phf map.
79  ///
80  /// Example: `self.output_router_for_phf_maps(MapType::Regular, true)?`
81  ///
82  /// Output String Sample:
83  ///
84  /// ```ignore
85  /// // super: use glossa_shared::PhfL10nOrderedMap;
86  /// pub(crate) const fn map(language: &[u8]) -> super::PhfL10nOrderedMap {
87  ///   use super::*;
88  ///   match language {
89  ///     #[cfg(feature = "l10n-ar")]
90  ///     b"ar" => l10n_ar::map(),
91  ///     #[cfg(feature = "l10n-as")]
92  ///     b"as" => l10n_as::map(),
93  ///     _ => "",
94  ///   }
95  /// }
96  /// ```
97  pub fn output_router_for_phf_maps(
98    &self,
99    map_type: MapType,
100    contains_map_name: bool,
101  ) -> io::Result<String> {
102    let header = format!(
103      "const fn map(language: &[u8]) -> super::{phf_type} {{
104      use super::*;
105      match language {{
106    ",
107      phf_type = if contains_map_name { "PhfL10nOrderedMap" } else { "PhfStrMap" }
108    );
109
110    let new_header = || self.new_fn_header(&header);
111
112    let locales = self.collect_raw_locales(map_type)?;
113    let features = self.collect_cargo_feature_names(map_type)?;
114    let modules = self.collect_rs_mod_names(map_type)?;
115    ensure_length_equal(features.len(), modules.len())?;
116
117    features
118      .iter()
119      .zip(modules)
120      .zip(locales)
121      .fold(
122        new_header(), //
123        |mut acc, ((feat, mod_name), locale)| {
124          let cfg_line = fmt_compact!("  #[cfg(feature = \"{feat}\")]\n  ");
125          let match_line = fmt_compact!(r##"b"{locale}" => {mod_name}::map(),"##);
126          [cfg_line, match_line]
127            .iter()
128            .for_each(|s| acc.push_str(s));
129          acc.push('\n');
130          acc
131        },
132      )
133      .tap_mut(|buf| buf.push_str("  _ => \"\",\n}}"))
134      .pipe(Ok)
135  }
136}
137
138#[cfg(test)]
139mod tests {
140  use glossa_shared::display::puts;
141
142  use super::*;
143  use crate::{Visibility, generator::dbg_generator::new_generator};
144
145  #[ignore]
146  #[test]
147  fn test_output_router_map() -> io::Result<()> {
148    new_generator()
149      .with_visibility(Visibility::Pub)
150      .output_router_for_match_fns(MapType::Regular, false)?
151      .pipe_ref(puts)
152      .pipe(Ok)
153  }
154}