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::Resolver;
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::Resolver> {
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::Resolver::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::Resolver::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::Resolver>(&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) =
247 bincode::serde::borrow_decode_from_slice::<resolver::Resolver, _>(&buf, cfg)?;
248 dbg!(data, n);
249 Ok(())
250 }
251
252 #[cfg(feature = "bincode")]
253 #[ignore]
254 #[test]
255 fn test_deser_bincode_from_file() -> anyhow::Result<()> {
256 let cfg = bincode::config::standard();
257
258 let buf = fs::read("tmp.bincode")?;
259 let now = std::time::Instant::now();
260 let (data, _u) =
261 bincode::serde::decode_from_slice::<resolver::Resolver, _>(&buf, cfg)?;
262 let elapsed = now.elapsed();
263 dbg!(&data);
264 eprintln!("elapsed: {elapsed:?}");
265
266 Ok(())
267 }
268
269 #[test]
272 #[ignore]
273 fn bench_resolve() -> anyhow::Result<()> {
274 let raw = raw_toml_to_hashmap()?;
275 let resolver = resolver::Resolver::try_from_raw(raw).expect("Invalid template");
276 dbg!(&resolver);
277
278 simple_benchmark(|| {
279 resolver.get_with_context(
280 "greeting",
281 &[
282 ("attr", "unknown"),
283 ("period", "evening"),
284 ("name", "Alice"),
285 ],
289 )
290 });
291 Ok(())
292 }
293}