use std::{
fs::File,
io::{self, BufWriter},
path::Path,
};
use glossa_shared::{MiniStr, fmt_compact, tap::Pipe};
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use crate::{
AnyResult,
generator::{Generator, MapType},
resources::L10nResMap,
};
impl<'h> Generator<'h> {
pub(crate) fn get_l10n_res_map(&self) -> &L10nResMap {
self
.get_resources()
.get_or_init_data()
}
fn encode_bincode<T, D>(&self, lang_id: D, data: T) -> AnyResult<()>
where
T: serde::Serialize,
D: core::fmt::Display,
{
bincode::serde::encode_into_std_write(
data,
&mut self.create_bincode_file(lang_id)?,
bincode::config::standard(),
)?;
Ok(())
}
pub fn output_bincode_all_in_one(&'h self, map_type: MapType) -> AnyResult<()> {
let all = "all";
if map_type.is_dsl() {
return match self.get_or_init_dsl_maps() {
x if x.is_empty() => Ok(()),
data => self.encode_bincode(all, data),
};
}
let data = map_type.get_non_dsl_maps(self)?;
self.encode_bincode(all, data)
}
pub fn output_bincode(&'h self, map_type: MapType) -> AnyResult<()> {
if map_type.is_dsl() {
return match self.get_or_init_dsl_maps() {
x if x.is_empty() => Ok(()),
iter => iter
.par_iter()
.try_for_each(|(lang, data)| self.encode_bincode(lang, data)),
};
}
map_type
.get_non_dsl_maps(self)?
.par_iter()
.try_for_each(|(lang, data)| self.encode_bincode(lang, data))
}
pub(crate) fn create_bincode_file<D: core::fmt::Display>(
&self,
language: D,
) -> io::Result<BufWriter<File>> {
let suffix = self.get_bincode_suffix();
let bincode_name = fmt_compact!("{language}{suffix}");
let out_dir = self.get_outdir().as_deref();
create_buf_writer(out_dir, bincode_name)
}
}
pub(crate) fn create_buf_writer(
out_dir: Option<&Path>,
bincode_name: MiniStr,
) -> io::Result<BufWriter<File>> {
out_dir
.ok_or_else(|| io::Error::other("Invalid outdir"))?
.join(bincode_name)
.pipe(File::create)?
.pipe(BufWriter::new)
.pipe(Ok)
}
#[cfg(test)]
mod tests {
use testutils::simple_benchmark;
use super::*;
use crate::generator::dbg_generator::{en_gb_generator, new_generator};
#[ignore]
#[test]
fn test_output_tmpl_maps_to_bincode_files() -> AnyResult<()> {
new_generator()
.with_bincode_suffix(".tmpl.bincode".into())
.output_bincode(MapType::DSL)
}
#[ignore]
#[test]
fn doc_test_encode_and_decode_tmpl_bincode() -> AnyResult<()> {
let resources = crate::L10nResources::new("../../locales/");
Generator::default()
.with_resources(resources)
.with_outdir("tmp")
.with_bincode_suffix("_dsl.bincode".into())
.output_bincode(MapType::DSL)?;
let file = Path::new("tmp").join("en_dsl.bincode");
let dsl_maps = glossa_shared::decode::file::decode_single_file_to_dsl_map(file)?;
let unread_resolver = dsl_maps
.get("unread")
.expect("Failed to get DSL-AST (map_name: unread)");
let get_text = |num_str| {
unread_resolver
.get_with_context("show-unread-messages-count", &[("num", num_str)])
};
let one = get_text("1")?;
assert_eq!(one, "You have one unread message.");
let zero = get_text("0")?;
assert_eq!(zero, "No unread messages.");
Ok(())
}
#[ignore]
#[test]
fn test_encode_regular_aio_bincode() -> AnyResult<()> {
new_generator()
.with_bincode_suffix("_regular.bincode".into())
.output_bincode_all_in_one(MapType::Regular)
}
#[ignore]
#[test]
fn test_encode_regular_en_gb_bincode() -> AnyResult<()> {
en_gb_generator()
.with_bincode_suffix(".regular.bincode".into())
.output_bincode(MapType::Regular)
}
#[ignore]
#[test]
#[cfg(feature = "highlight")]
fn test_encode_highlight_aio_bincode() -> AnyResult<()> {
use crate::generator::dbg_generator;
dbg_generator::highlight_generator()
.with_bincode_suffix(".highlight.bincode".into())
.output_bincode_all_in_one(MapType::Highlight)
}
#[ignore]
#[test]
#[cfg(feature = "highlight")]
fn test_decode_highlight_aio() -> glossa_shared::decode::ResolverResult<()> {
let data =
glossa_shared::decode::file::decode_file_to_maps("tmp/all.highlight.bincode")?;
let en_maps = data.get("en").unwrap();
let value = en_maps
.get(&("md_md".into(), "pwsh".into()))
.unwrap();
println!("{value}");
Ok(())
}
#[ignore]
#[test]
fn test_encode_tmpl_aio_bincode() -> AnyResult<()> {
new_generator()
.with_bincode_suffix("_tmpl.bincode".into())
.output_bincode_all_in_one(MapType::DSL)
}
#[ignore]
#[test]
fn test_decode_tmpl_aio_bincode() -> AnyResult<()> {
let raw_map =
glossa_shared::decode::file::decode_file_to_dsl_maps("tmp/all_tmpl.bincode")?;
let zh_maps = raw_map.get("zh").unwrap();
let zh_unread_map = zh_maps.get("unread").unwrap();
let text = zh_unread_map
.get_with_context("show-unread-messages-count", &[("num", "2")])?;
dbg!(text);
Ok(())
}
#[ignore]
#[test]
fn bench_decode_regular_file() -> AnyResult<()> {
let file = Path::new("tmp").join("all_regular.bincode");
eprintln!("decode from file");
simple_benchmark(|| {
let _ = glossa_shared::decode::file::decode_file_to_maps(&file);
});
let bytes = std::fs::read(&file)?;
let decode_slice = || glossa_shared::decode::slice::decode_to_maps(&bytes);
eprintln!("decode from slice");
simple_benchmark(|| {
let _ = decode_slice();
});
Ok(())
}
}