glossa_shared/
load_bincode.rs

1use std::{
2  ffi::OsStr,
3  path::{Path, PathBuf},
4  sync::OnceLock,
5};
6
7use compact_str::ToCompactString;
8use glossa_dsl::error::ResolverResult;
9use lang_id::LangID;
10use log::debug;
11use rayon::iter::{IntoParallelRefIterator, ParallelBridge, ParallelIterator};
12use tap::Pipe;
13
14use crate::{
15  decode::file::{
16    decode_file_to_dsl_maps, decode_file_to_maps, decode_single_file_to_dsl_map,
17    decode_single_file_to_flatten_map,
18  },
19  type_aliases::{DSLMaps, L10nMaps},
20};
21
22// pub trait LoadBincode {
23//   fn get_bincode_dir() -> Option<PathBuf>;
24
25pub fn list_bincode_files(bincode_dir: Option<&Path>) -> Option<Vec<PathBuf>> {
26  bincode_dir?
27    .read_dir()
28    .ok()?
29    .par_bridge()
30    .flatten()
31    .map(|x| x.path())
32    .filter(|x| !x.is_dir())
33    .collect::<Vec<_>>()
34    .pipe(|x| (!x.is_empty()).then_some(x))
35}
36
37pub fn list_static_bincode_files(
38  bincode_dir: Option<&Path>,
39) -> Option<&'static [PathBuf]> {
40  static V: OnceLock<Option<Vec<PathBuf>>> = OnceLock::new();
41  V.get_or_init(|| list_bincode_files(bincode_dir))
42    .as_deref()
43}
44
45pub fn try_load_files<P: AsRef<Path>>(files: &[P]) -> ResolverResult<L10nMaps> {
46  let all = OsStr::new("all");
47  log::debug!("Loading bincode data ...");
48
49  let iter = files.iter().map(AsRef::as_ref);
50
51  match iter
52    .clone()
53    .find(|x| x.file_stem() == Some(all))
54  {
55    Some(p) => {
56      debug!("load: all.bincode");
57      decode_file_to_maps(p)
58    }
59    _ => {
60      // use `.collect().par_iter()` instead of `iter.par_bridge()`
61      iter
62        .collect::<Vec<_>>()
63        .par_iter()
64        .filter_map(|file| {
65          decode_single_file_to_flatten_map(file)
66            .ok()
67            .and_then(|data| {
68              file
69                .file_stem()
70                .inspect(|s| debug!("file-stem: {s:?}"))
71                .and_then(|s| s.to_str())
72                .map(|lang| (lang.to_compact_string(), data))
73            })
74        })
75        .collect::<L10nMaps>()
76        .pipe(Ok)
77    }
78  }
79}
80
81pub fn try_load_dsl_files<P: AsRef<Path>>(files: &[P]) -> ResolverResult<DSLMaps> {
82  let all = OsStr::new("all");
83  log::debug!("Loading bincode data ...");
84
85  let iter = files.iter().map(AsRef::as_ref);
86
87  match iter
88    .clone()
89    .find(|x| x.file_stem() == Some(all))
90  {
91    Some(p) => {
92      debug!("load DSL: all.bincode");
93      decode_file_to_dsl_maps(p)
94    }
95    _ => iter
96      .collect::<Vec<_>>()
97      .par_iter()
98      // .par_bridge()
99      .filter_map(|file| {
100        decode_single_file_to_dsl_map(file)
101          .ok()
102          .and_then(|data| {
103            file
104              .file_stem()
105              .inspect(|s| debug!("file-stem: {s:?}"))
106              .and_then(|s| s.to_str())
107              .map(|lang| (lang.to_compact_string(), data))
108          })
109      })
110      .collect::<DSLMaps>()
111      .pipe(Ok),
112  }
113}
114
115pub fn merge_locales(
116  lhs: Option<&L10nMaps>,
117  rhs: Option<&[LangID]>,
118) -> Option<Box<[LangID]>> {
119  let builtin = rhs
120    .into_iter()
121    .flatten()
122    .cloned();
123
124  let locales = lhs?
125    .keys()
126    .inspect(|x| debug!("language: {x}"))
127    .filter_map(|x| x.parse::<LangID>().ok())
128    .chain(builtin)
129    .collect::<ahash::HashSet<_>>() // dedup
130    .into_iter()
131    .collect();
132
133  Some(locales)
134}