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].map(|s| acc.push_str(&s));
68          acc.push('\n');
69          acc
70        },
71      )
72      .tap_mut(|buf| buf.push_str("  _ => \"\",\n}}"))
73      .pipe(Ok)
74  }
75
76  /// Generates a function that routes to the appropriate phf map.
77  ///
78  /// Example: `self.output_router_for_phf_maps(MapType::Regular, true)?`
79  ///
80  /// Output String Sample:
81  ///
82  /// ```ignore
83  /// // super: use glossa_shared::PhfL10nOrderedMap;
84  /// pub(crate) const fn map(language: &[u8]) -> super::PhfL10nOrderedMap {
85  ///   use super::*;
86  ///   match language {
87  ///     #[cfg(feature = "l10n-ar")]
88  ///     b"ar" => l10n_ar::map(),
89  ///     #[cfg(feature = "l10n-as")]
90  ///     b"as" => l10n_as::map(),
91  ///     _ => "",
92  ///   }
93  /// }
94  /// ```
95  pub fn output_router_for_phf_maps(
96    &self,
97    map_type: MapType,
98    contains_map_name: bool,
99  ) -> io::Result<String> {
100    let header = format!(
101      "const fn map(language: &[u8]) -> super::{phf_type} {{
102      use super::*;
103      match language {{
104    ",
105      phf_type = if contains_map_name { "PhfL10nOrderedMap" } else { "PhfStrMap" }
106    );
107
108    let new_header = || self.new_fn_header(&header);
109
110    let locales = self.collect_raw_locales(map_type)?;
111    let features = self.collect_cargo_feature_names(map_type)?;
112    let modules = self.collect_rs_mod_names(map_type)?;
113    ensure_length_equal(features.len(), modules.len())?;
114
115    features
116      .iter()
117      .zip(modules)
118      .zip(locales)
119      .fold(
120        new_header(), //
121        |mut acc, ((feat, mod_name), locale)| {
122          let cfg_line = fmt_compact!("  #[cfg(feature = \"{feat}\")]\n  ");
123          let match_line = fmt_compact!(r##"b"{locale}" => {mod_name}::map(),"##);
124          [cfg_line, match_line].map(|s| acc.push_str(&s));
125          acc.push('\n');
126          acc
127        },
128      )
129      .tap_mut(|buf| buf.push_str("  _ => \"\",\n}}"))
130      .pipe(Ok)
131  }
132}
133
134#[cfg(test)]
135mod tests {
136  use glossa_shared::display::puts;
137
138  use super::*;
139  use crate::{Visibility, generator::dbg_generator::new_generator};
140
141  #[ignore]
142  #[test]
143  fn test_output_router_map() -> io::Result<()> {
144    new_generator()
145      .with_visibility(Visibility::Pub)
146      .output_router_for_match_fns(MapType::Regular, false)?
147      .pipe_ref(puts)
148      .pipe(Ok)
149  }
150}