use er7::Separators;
use er7::escape::{Escape, decode_hex, escape, escapes, unescape};
fn main() {
let separators = Separators::default();
assert_eq!(unescape(r"Smith \T\ Jones", &separators), "Smith & Jones");
assert_eq!(unescape(r"a\F\b", &separators), "a|b");
assert_eq!(unescape(r"a\S\b", &separators), "a^b");
assert_eq!(unescape(r"a\R\b", &separators), "a~b");
assert_eq!(unescape(r"a\E\b", &separators), r"a\b");
assert_eq!(unescape(r"\X0D\", &separators), "\r");
assert_eq!(unescape(r"\X4142\", &separators), "AB");
println!("decoded: {}", unescape(r"Smith \T\ Jones", &separators));
assert_eq!(unescape(r"line\.br\next", &separators), r"line\.br\next");
assert_eq!(unescape(r"\H\loud\N\", &separators), r"\H\loud\N\");
assert_eq!(unescape(r"\Z0102\", &separators), r"\Z0102\");
assert_eq!(unescape(r"\C2842\", &separators), r"\C2842\");
assert_eq!(unescape(r"\XZZ\", &separators), r"\XZZ\");
assert_eq!(unescape(r"a\Fb", &separators), r"a\Fb");
println!("preserved: {}", unescape(r"line\.br\next", &separators));
assert_eq!(escape("Smith & Jones", &separators), r"Smith \T\ Jones");
assert_eq!(escape("a|b^c~d&e", &separators), r"a\F\b\S\c\R\d\T\e");
assert_eq!(escape(r"a\b", &separators), r"a\E\b");
assert_eq!(escape("line\r\nnext", &separators), r"line\X0D\\X0A\next");
for value in ["plain", r"a|b^c~d&e\f", "with\rcr", "Smith & Jones"] {
assert_eq!(unescape(&escape(value, &separators), &separators), value);
}
println!("escape/unescape round trip holds");
assert_eq!(decode_hex("0D0A"), Some("\r\n".to_string()));
assert_eq!(decode_hex("4142"), Some("AB".to_string()));
assert_eq!(decode_hex("A"), None); assert_eq!(decode_hex("GG"), None);
let tokens: Vec<_> = escapes(r"Dr\S\Who\.br\", &separators).collect();
assert_eq!(
tokens,
vec![
Escape::Text("Dr"),
Escape::Component,
Escape::Text("Who"),
Escape::Formatting("br"),
]
);
let source = r"a\F\b\.sp 2\c\Q\d";
let mut rebuilt = String::new();
for token in escapes(source, &separators) {
token.write_er7(&mut rebuilt, &separators);
}
assert_eq!(rebuilt, source);
println!("tokenizing is lossless");
let note = r"Line one\.br\Line two \S\ more";
assert_eq!(
to_plain_text(note, &separators),
"Line one\nLine two ^ more"
);
println!("--- rendered note ---");
println!("{}", to_plain_text(note, &separators));
let custom = Separators {
field: '#',
component: '*',
repetition: '!',
escape: '?',
subcomponent: '@',
truncation: None,
};
assert_eq!(unescape("a?F?b", &custom), "a#b");
assert_eq!(escape("a#b", &custom), "a?F?b");
println!("ok");
}
fn to_plain_text(value: &str, separators: &Separators) -> String {
let mut out = String::new();
for token in escapes(value, separators) {
match token {
Escape::Text(run) => out.push_str(run),
Escape::Formatting("br") => out.push('\n'),
Escape::Field => out.push(separators.field),
Escape::Component => out.push(separators.component),
Escape::Subcomponent => out.push(separators.subcomponent),
Escape::Repetition => out.push(separators.repetition),
Escape::EscapeCharacter => out.push(separators.escape),
Escape::Hex(body) => out.push_str(&decode_hex(body).unwrap_or_default()),
_ => {}
}
}
out
}