fhttp_core/preprocessing/
evaluation.rs

1use std::ops::Range;
2
3use anyhow::Result;
4
5pub trait Evaluation {
6    fn backslashes(&self) -> &Range<usize>;
7
8    fn range(&self) -> &Range<usize>;
9
10    fn is_escaped(&self) -> bool {
11        self.backslashes().len() % 2 != 0
12    }
13
14    fn replace<S: Into<String>, F: FnOnce() -> Result<S>>(
15        &self,
16        target: &mut String,
17        producer: F,
18    ) -> Result<()> {
19        if !self.is_escaped() {
20            let text = producer()?.into();
21            let end_index = match text.chars().last() {
22                Some('\n') => text.len() - 1,
23                _ => text.len(),
24            };
25            target.replace_range(self.range().clone(), &text[0..end_index]);
26        }
27        escape_backslashes(target, self.backslashes());
28
29        Ok(())
30    }
31}
32
33fn escape_backslashes(target: &mut String, backslashes: &Range<usize>) {
34    if backslashes.is_empty() {
35        return;
36    }
37
38    let num_backslaches_to_remove = backslashes.len() / 2;
39    let new_end = backslashes.end - num_backslaches_to_remove;
40
41    target.replace_range(backslashes.start..new_end, "");
42}
43
44#[derive(Debug)]
45pub struct BaseEvaluation {
46    pub backslashes: Range<usize>,
47    pub range: Range<usize>,
48}
49
50impl BaseEvaluation {
51    pub fn new(range: Range<usize>, backslashes: Range<usize>) -> Self {
52        BaseEvaluation { range, backslashes }
53    }
54}
55
56impl AsRef<BaseEvaluation> for BaseEvaluation {
57    fn as_ref(&self) -> &BaseEvaluation {
58        self
59    }
60}
61
62impl<T: AsRef<BaseEvaluation>> Evaluation for T {
63    fn backslashes(&self) -> &Range<usize> {
64        &self.as_ref().backslashes
65    }
66
67    fn range(&self) -> &Range<usize> {
68        &self.as_ref().range
69    }
70}