#![cfg_attr(__unstable_doc, feature(doc_auto_cfg, doc_notable_trait))]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
pub mod error;
pub use error::{ResolverError as Error, ResolverResult as Result};
mod parsers;
pub(crate) mod part;
pub mod resolver;
pub(crate) use resolver::MiniStr;
pub use resolver::TemplateResolver;
#[cfg(feature = "std")]
pub type ContextMap<'a> = ahash::HashMap<&'a str, &'a str>;
#[cfg(feature = "std")]
pub type ContextMapBuf = ahash::HashMap<kstring::KString, MiniStr>;
pub(crate) mod selector;
pub(crate) mod template;
pub use template::Template;
#[cfg(test)]
#[cfg(not(feature = "std"))]
mod no_std_tests {
use testutils::simple_benchmark;
use super::*;
use crate::error::ResolverResult;
fn init_ast() -> ResolverResult<resolver::TemplateResolver> {
[("g", "Good"), ("greeting", "{g} {$period}! { $name }")]
.as_ref()
.try_into()
}
#[test]
fn get_text() -> ResolverResult<()> {
let text = init_ast()?
.get_with_context("greeting", &[("name", "Tom"), ("period", "Morning")])?;
assert_eq!(text, "Good Morning! Tom");
Ok(())
}
#[ignore]
#[test]
fn bench_no_std_get_text() {
let ast = init_ast().expect("Failed to init template resolver");
simple_benchmark(|| {
ast.get_with_context("greeting", &[("name", "Tom"), ("period", "Morning")])
});
}
}
#[cfg(all(feature = "std", feature = "serde"))]
#[cfg(test)]
mod tests {
use std::fs;
use ahash::HashMap;
use kstring::KString;
use testutils::simple_benchmark;
use super::*;
use crate::error::ResolverResult;
type TomlResult<T> = core::result::Result<T, toml::de::Error>;
fn raw_toml_to_hashmap() -> TomlResult<HashMap<KString, MiniStr>> {
let text = r##"
g = "Good"
time-period = """
$period ->
[morning] {g} Morning
[evening] {g} evening
*[other] {g} {$period}
"""
href = """
<a href=""></a>
end
"""
gender = """
$attr ->
[male] Mr.
*[female] Ms.
"""
greeting = "{ time-period }! { gender }{ $name }"
"##;
toml::from_str(text)
}
#[ignore]
#[test]
fn dbg_tomlmap() {
let _ = dbg!(raw_toml_to_hashmap());
}
#[test]
fn get_text() -> ResolverResult<()> {
let raw = raw_toml_to_hashmap().expect("Failed to deser toml");
let resolver = resolver::TemplateResolver::try_from_raw(raw)?;
let text = resolver.get_with_context(
"greeting",
&[
("period", "evening"),
("name", "Alice"),
("attr", "unknown"),
],
)?;
assert_eq!(text, "Good evening! Ms.Alice");
Ok(())
}
#[ignore]
fn encode_ast_to_json() -> anyhow::Result<String> {
let raw = raw_toml_to_hashmap()?;
let resolver = resolver::TemplateResolver::try_from_raw(raw)?;
let json_str = serde_json::to_string_pretty(&resolver)?;
Ok(json_str)
}
#[cfg(feature = "bincode")]
#[ignore]
#[test]
fn test_serde_bincode_from_json_str() -> anyhow::Result<()> {
let json_str = encode_ast_to_json()?;
let data = serde_json::from_str::<resolver::TemplateResolver>(&json_str)?;
let cfg = bincode::config::standard().with_no_limit();
let buf = bincode::serde::encode_to_vec(data, cfg)?;
fs::write("tmp.bincode", &buf)?;
let (data, n) = bincode::serde::borrow_decode_from_slice::<
resolver::TemplateResolver,
_,
>(&buf, cfg)?;
dbg!(data, n);
Ok(())
}
#[cfg(feature = "bincode")]
#[ignore]
#[test]
fn test_deser_bincode_from_file() -> anyhow::Result<()> {
let cfg = bincode::config::standard();
let buf = fs::read("tmp.bincode")?;
let now = std::time::Instant::now();
let (data, _u) =
bincode::serde::decode_from_slice::<resolver::TemplateResolver, _>(&buf, cfg)?;
let elapsed = now.elapsed();
dbg!(&data);
eprintln!("elapsed: {elapsed:?}");
Ok(())
}
#[test]
#[ignore]
fn bench_resolve() -> anyhow::Result<()> {
let raw = raw_toml_to_hashmap()?;
let resolver =
resolver::TemplateResolver::try_from_raw(raw).expect("Invalid template");
dbg!(&resolver);
simple_benchmark(|| {
resolver.get_with_context(
"greeting",
&[
("attr", "unknown"),
("period", "evening"),
("name", "Alice"),
],
)
});
Ok(())
}
}