1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use crate::template::{Buffer, Parse, ParseError, Render, TemplateFns};
pub(crate) trait StringPartBreakers {
const BREAKERS: &'static [&'static str];
}
#[derive(Debug, PartialEq)]
pub(crate) struct StringPart<T> {
pub(crate) string: String,
phantom: std::marker::PhantomData<T>,
}
impl<T> StringPart<T> {
pub(crate) fn new<S>(string: S) -> Self
where
S: Into<String>,
{
Self {
string: string.into(),
phantom: std::marker::PhantomData,
}
}
}
impl<Breakers> Parse for StringPart<Breakers>
where
Breakers: StringPartBreakers,
{
fn parse(buffer: &mut Buffer) -> Result<Self, ParseError> {
let mut string = String::from("");
while !buffer.is_eof() {
let chunk = buffer.take(1).expect("bug: can't be EOF");
string += &chunk;
let mut abort = false;
for breaker in Breakers::BREAKERS {
if buffer.is(*breaker) {
abort = true;
break;
}
}
if abort {
break;
}
}
let string = string.replace("<dnl>\n", "");
Ok(Self::new(string))
}
}
impl<T> Render<()> for StringPart<T> {
fn render(&self, _ctx: &(), _fns: &TemplateFns) -> String {
self.string.clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, PartialEq)]
struct Breakers;
impl StringPartBreakers for Breakers {
const BREAKERS: &'static [&'static str] = &["STOP HERE"];
}
#[test]
fn test_parse() {
let mut buffer = Buffer::new("a string STOP HERE".as_bytes().to_vec());
let parsed = StringPart::<Breakers>::parse(&mut buffer).unwrap();
assert_eq!(parsed, StringPart::new("a string "))
}
#[test]
fn test_render() {
let string = StringPart::<Breakers>::new("a string");
let fns = TemplateFns::new();
assert_eq!("a string", string.render(&(), &fns))
}
}