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))
    }
}