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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! [`Recorder`] implementation finding the starts and approximate ends of all matches.
//! Faster than a full [`NodesRecorder`](super::nodes::NodesRecorder), but the span
//! may include trailing whitespace after the actual matched value.
use super::{output_queue::OutputQueue, *};
use std::cell::RefCell;

/// Recorder that finds approximate [`MatchSpans`](`MatchSpan`),
/// possibly including trailing whitespace after the actual match.
pub struct ApproxSpanRecorder<'s, S> {
    internal: RefCell<InternalRecorder<'s, S>>,
}

struct InternalRecorder<'s, S> {
    sink: &'s mut S,
    match_count: usize,
    stack: Vec<PartialNode>,
    output_queue: OutputQueue<MatchSpan>,
}

struct PartialNode {
    id: usize,
    start_idx: MatchIndex,
    start_depth: Depth,
    ty: MatchedNodeType,
}

impl<'s, S> ApproxSpanRecorder<'s, S> {
    #[inline]
    pub(crate) fn new(sink: &'s mut S) -> Self {
        Self {
            internal: RefCell::new(InternalRecorder::new(sink)),
        }
    }
}

impl<'s, B: Deref<Target = [u8]>, S> InputRecorder<B> for ApproxSpanRecorder<'s, S>
where
    S: Sink<MatchSpan>,
{
    #[inline(always)]
    fn record_block_start(&self, _new_block: B) {
        // Intentionally left empty.
    }
}

impl<'s, B: Deref<Target = [u8]>, S> Recorder<B> for ApproxSpanRecorder<'s, S>
where
    S: Sink<MatchSpan>,
{
    #[inline]
    fn record_match(&self, idx: usize, depth: Depth, ty: MatchedNodeType) -> Result<(), EngineError> {
        self.internal.borrow_mut().record_start(idx, depth, ty);
        Ok(())
    }

    #[inline]
    fn record_value_terminator(&self, idx: usize, depth: Depth) -> Result<(), EngineError> {
        self.internal.borrow_mut().record_end(idx, depth)
    }
}

impl<'s, S> InternalRecorder<'s, S> {
    fn new(sink: &'s mut S) -> Self {
        Self {
            sink,
            stack: vec![],
            match_count: 0,
            output_queue: OutputQueue::new(),
        }
    }
}

impl<'s, S> InternalRecorder<'s, S>
where
    S: Sink<MatchSpan>,
{
    fn record_start(&mut self, start_idx: usize, start_depth: Depth, ty: MatchedNodeType) {
        self.stack.push(PartialNode {
            id: self.match_count,
            start_idx,
            start_depth,
            ty,
        });
        self.match_count += 1;
    }

    fn record_end(&mut self, idx: usize, depth: Depth) -> Result<(), EngineError> {
        while let Some(node) = self.stack.last() {
            if node.start_depth >= depth {
                let node = self.stack.pop().expect("last was Some, pop must succeed");
                let end_idx = if node.ty == MatchedNodeType::Complex {
                    idx + 1
                } else {
                    idx
                };
                let span = MatchSpan {
                    start_idx: node.start_idx,
                    len: end_idx - node.start_idx,
                };
                self.output_queue.insert(node.id, span);
            } else {
                break;
            }
        }

        if self.stack.is_empty() {
            self.output_queue
                .output_to(self.sink)
                .map_err(|err| EngineError::SinkError(Box::new(err)))?;
        }

        Ok(())
    }
}