1#![cfg_attr(__unstable_doc, feature(doc_auto_cfg, doc_notable_trait))]
2#![cfg_attr(not(feature = "std"), no_std)]
3extern crate alloc;
106
107pub mod error;
108pub use error::{ResolverError as Error, ResolverResult as Result};
109
110mod parsers;
111pub(crate) mod part;
112
113pub mod resolver;
114pub(crate) use resolver::MiniStr;
115pub use resolver::TemplateResolver;
116
117#[cfg(feature = "std")]
118pub type ContextMap<'a> = ahash::HashMap<&'a str, &'a str>;
119#[cfg(feature = "std")]
120pub type ContextMapBuf = ahash::HashMap<kstring::KString, MiniStr>;
121
122pub(crate) mod selector;
123pub(crate) mod template;
124pub use template::Template;
125
126#[cfg(test)]
127#[cfg(not(feature = "std"))]
128mod no_std_tests {
129 use testutils::simple_benchmark;
130
131 use super::*;
133 use crate::error::ResolverResult;
134
135 fn init_ast() -> ResolverResult<resolver::TemplateResolver> {
136 [("g", "Good"), ("greeting", "{g} {$period}! { $name }")]
137 .as_ref()
138 .try_into()
139 }
140
141 #[test]
142 fn get_text() -> ResolverResult<()> {
143 let text = init_ast()?
144 .get_with_context("greeting", &[("name", "Tom"), ("period", "Morning")])?;
145
146 assert_eq!(text, "Good Morning! Tom");
147 Ok(())
148 }
149
150 #[ignore]
153 #[test]
154 fn bench_no_std_get_text() {
155 let ast = init_ast().expect("Failed to init template resolver");
156
157 simple_benchmark(|| {
158 ast.get_with_context("greeting", &[("name", "Tom"), ("period", "Morning")])
159 });
160 }
161}
162
163#[cfg(all(feature = "std", feature = "serde"))]
164#[cfg(test)]
165mod tests {
166 use std::fs;
167
168 use ahash::HashMap;
169 use kstring::KString;
170 use testutils::simple_benchmark;
171
172 use super::*;
173 use crate::error::ResolverResult;
174 type TomlResult<T> = core::result::Result<T, toml::de::Error>;
175
176 fn raw_toml_to_hashmap() -> TomlResult<HashMap<KString, MiniStr>> {
177 let text = r##"
178g = "Good"
179time-period = """
180$period ->
181 [morning] {g} Morning
182 [evening] {g} evening
183 *[other] {g} {$period}
184"""
185
186href = """
187
188<a href=""></a>
189end
190
191"""
192
193gender = """
194
195$attr ->
196 [male] Mr.
197 *[female] Ms.
198"""
199greeting = "{ time-period }! { gender }{ $name }"
200 "##;
201
202 toml::from_str(text)
203 }
204
205 #[ignore]
206 #[test]
207 fn dbg_tomlmap() {
208 let _ = dbg!(raw_toml_to_hashmap());
209 }
210
211 #[test]
212 fn get_text() -> ResolverResult<()> {
213 let raw = raw_toml_to_hashmap().expect("Failed to deser toml");
214 let resolver = resolver::TemplateResolver::try_from_raw(raw)?;
215 let text = resolver.get_with_context(
216 "greeting",
217 &[
218 ("period", "evening"),
219 ("name", "Alice"),
220 ("attr", "unknown"),
221 ],
222 )?;
223 assert_eq!(text, "Good evening! Ms.Alice");
224
225 Ok(())
226 }
227
228 #[ignore]
229 fn encode_ast_to_json() -> anyhow::Result<String> {
230 let raw = raw_toml_to_hashmap()?;
231 let resolver = resolver::TemplateResolver::try_from_raw(raw)?;
232 let json_str = serde_json::to_string_pretty(&resolver)?;
233 Ok(json_str)
235 }
236
237 #[cfg(feature = "bincode")]
238 #[ignore]
239 #[test]
240 fn test_serde_bincode_from_json_str() -> anyhow::Result<()> {
241 let json_str = encode_ast_to_json()?;
242 let data = serde_json::from_str::<resolver::TemplateResolver>(&json_str)?;
243 let cfg = bincode::config::standard().with_no_limit();
244 let buf = bincode::serde::encode_to_vec(data, cfg)?;
245 fs::write("tmp.bincode", &buf)?;
246 let (data, n) = bincode::serde::borrow_decode_from_slice::<
247 resolver::TemplateResolver,
248 _,
249 >(&buf, cfg)?;
250 dbg!(data, n);
251 Ok(())
252 }
253
254 #[cfg(feature = "bincode")]
255 #[ignore]
256 #[test]
257 fn test_deser_bincode_from_file() -> anyhow::Result<()> {
258 let cfg = bincode::config::standard();
259
260 let buf = fs::read("tmp.bincode")?;
261 let now = std::time::Instant::now();
262 let (data, _u) =
263 bincode::serde::decode_from_slice::<resolver::TemplateResolver, _>(&buf, cfg)?;
264 let elapsed = now.elapsed();
265 dbg!(&data);
266 eprintln!("elapsed: {elapsed:?}");
267
268 Ok(())
269 }
270
271 #[test]
274 #[ignore]
275 fn bench_resolve() -> anyhow::Result<()> {
276 let raw = raw_toml_to_hashmap()?;
277 let resolver =
278 resolver::TemplateResolver::try_from_raw(raw).expect("Invalid template");
279 dbg!(&resolver);
280
281 simple_benchmark(|| {
282 resolver.get_with_context(
283 "greeting",
284 &[
285 ("attr", "unknown"),
286 ("period", "evening"),
287 ("name", "Alice"),
288 ],
292 )
293 });
294 Ok(())
295 }
296}