zng_ext_l10n/sources/
swap.rs1use std::{collections::HashMap, path::PathBuf, sync::Arc};
2
3use zng_var::{ArcEq, Var, VarHandle, WeakVar, var, weak_var};
4
5use crate::{L10nSource, Lang, LangFilePath, LangMap, LangResourceStatus};
6
7use super::NilL10nSource;
8
9pub struct SwapL10nSource {
16 actual: Box<dyn L10nSource>,
17
18 available_langs: Var<Arc<LangMap<HashMap<LangFilePath, PathBuf>>>>,
19 available_langs_status: Var<LangResourceStatus>,
20
21 res: HashMap<(Lang, LangFilePath), SwapFile>,
22}
23impl SwapL10nSource {
24 pub fn new() -> Self {
26 Self {
27 actual: Box::new(NilL10nSource),
28 available_langs: var(Arc::default()),
29 available_langs_status: var(LangResourceStatus::NotAvailable),
30 res: HashMap::new(),
31 }
32 }
33
34 pub fn load(&mut self, source: impl L10nSource) {
36 self.swap_source(Box::new(source))
37 }
38 fn swap_source(&mut self, new: Box<dyn L10nSource>) {
39 self.actual = new;
40
41 let actual_langs = self.actual.available_langs();
42 self.available_langs.set_from(&actual_langs);
43 actual_langs.bind(&self.available_langs).perm();
44
45 let actual_status = self.actual.available_langs_status();
46 self.available_langs_status.set_from(&actual_status);
47 actual_status.bind(&self.available_langs_status).perm();
48
49 for ((lang, file), f) in &mut self.res {
50 if let Some(res) = f.res.upgrade() {
51 let actual_f = self.actual.lang_resource(lang.clone(), file.clone());
52 f.actual_weak_res = actual_f.bind(&res); f.res_strong_actual = res.hold(actual_f); let actual_s = self.actual.lang_resource_status(lang.clone(), file.clone());
56 f.status.set_from(&actual_s);
57 f.actual_weak_status = actual_s.bind(&f.status);
58 } else {
59 f.status.set(LangResourceStatus::NotAvailable);
60 }
61 }
62 }
63}
64impl Default for SwapL10nSource {
65 fn default() -> Self {
66 Self::new()
67 }
68}
69impl L10nSource for SwapL10nSource {
70 fn available_langs(&mut self) -> Var<Arc<LangMap<HashMap<LangFilePath, PathBuf>>>> {
71 self.available_langs.read_only()
72 }
73
74 fn available_langs_status(&mut self) -> Var<LangResourceStatus> {
75 self.available_langs_status.read_only()
76 }
77
78 fn lang_resource(&mut self, lang: Lang, file: LangFilePath) -> Var<Option<ArcEq<fluent::FluentResource>>> {
79 match self.res.entry((lang, file)) {
80 std::collections::hash_map::Entry::Occupied(mut e) => {
81 if let Some(res) = e.get().res.upgrade() {
82 res
83 } else {
84 let (lang, file) = e.key();
85 let actual_f = self.actual.lang_resource(lang.clone(), file.clone());
86 let actual_s = self.actual.lang_resource_status(lang.clone(), file.clone());
87
88 let f = e.get_mut();
89
90 let res = var(actual_f.get());
91 f.actual_weak_res = actual_f.bind(&res); f.res_strong_actual = res.hold(actual_f); let res = res;
94 f.res = res.downgrade();
95
96 f.status.set_from(&actual_s);
97 f.actual_weak_status = actual_s.bind(&f.status);
98
99 res
100 }
101 }
102 std::collections::hash_map::Entry::Vacant(e) => {
103 let mut f = SwapFile::new();
104 let (lang, file) = e.key();
105 let actual_f = self.actual.lang_resource(lang.clone(), file.clone());
106 let actual_s = self.actual.lang_resource_status(lang.clone(), file.clone());
107
108 let res = var(actual_f.get());
109 f.actual_weak_res = actual_f.bind(&res); f.res_strong_actual = res.hold(actual_f); let res = res;
112 f.res = res.downgrade();
113
114 f.status.set_from(&actual_s);
115 f.actual_weak_status = actual_s.bind(&f.status);
116
117 e.insert(f);
118
119 res
120 }
121 }
122 }
123
124 fn lang_resource_status(&mut self, lang: Lang, file: LangFilePath) -> Var<LangResourceStatus> {
125 self.res.entry((lang, file)).or_insert_with(SwapFile::new).status.read_only()
126 }
127}
128struct SwapFile {
129 res: WeakVar<Option<ArcEq<fluent::FluentResource>>>,
130 status: Var<LangResourceStatus>,
131 actual_weak_res: VarHandle,
132 res_strong_actual: VarHandle,
133 actual_weak_status: VarHandle,
134}
135impl SwapFile {
136 fn new() -> Self {
137 Self {
138 res: weak_var(),
139 status: var(LangResourceStatus::Loading),
140 actual_weak_res: VarHandle::dummy(),
141 res_strong_actual: VarHandle::dummy(),
142 actual_weak_status: VarHandle::dummy(),
143 }
144 }
145}