rsonpath/result/
approx_span.rs

1//! [`Recorder`] implementation finding the starts and approximate ends of all matches.
2//!
3//! Faster than a full [`NodesRecorder`](super::nodes::NodesRecorder), but the span
4//! may include trailing whitespace after the actual matched value.
5use super::{output_queue::OutputQueue, *};
6use std::cell::RefCell;
7
8/// Recorder that finds approximate [`MatchSpans`](`MatchSpan`),
9/// possibly including trailing whitespace after the actual match.
10pub struct ApproxSpanRecorder<'s, S> {
11    internal: RefCell<InternalRecorder<'s, S>>,
12}
13
14struct InternalRecorder<'s, S> {
15    sink: &'s mut S,
16    leading_padding_len: usize,
17    match_count: usize,
18    stack: Vec<PartialNode>,
19    output_queue: OutputQueue<MatchSpan>,
20}
21
22struct PartialNode {
23    id: usize,
24    start_idx: MatchIndex,
25    start_depth: Depth,
26    ty: MatchedNodeType,
27}
28
29impl<'s, S> ApproxSpanRecorder<'s, S> {
30    #[inline]
31    pub(crate) fn new(sink: &'s mut S, leading_padding_len: usize) -> Self {
32        Self {
33            internal: RefCell::new(InternalRecorder::new(sink, leading_padding_len)),
34        }
35    }
36}
37
38impl<B: Deref<Target = [u8]>, S> InputRecorder<B> for ApproxSpanRecorder<'_, S>
39where
40    S: Sink<MatchSpan>,
41{
42    #[inline(always)]
43    fn record_block_start(&self, _new_block: B) {
44        // Intentionally left empty.
45    }
46}
47
48impl<B: Deref<Target = [u8]>, S> Recorder<B> for ApproxSpanRecorder<'_, S>
49where
50    S: Sink<MatchSpan>,
51{
52    #[inline]
53    fn record_match(&self, idx: usize, depth: Depth, ty: MatchedNodeType) -> Result<(), EngineError> {
54        self.internal.borrow_mut().record_start(idx, depth, ty);
55        Ok(())
56    }
57
58    #[inline]
59    fn record_value_terminator(&self, idx: usize, depth: Depth) -> Result<(), EngineError> {
60        self.internal.borrow_mut().record_end(idx, depth)
61    }
62}
63
64impl<'s, S> InternalRecorder<'s, S> {
65    fn new(sink: &'s mut S, leading_padding_len: usize) -> Self {
66        Self {
67            sink,
68            leading_padding_len,
69            stack: vec![],
70            match_count: 0,
71            output_queue: OutputQueue::new(),
72        }
73    }
74}
75
76impl<S> InternalRecorder<'_, S>
77where
78    S: Sink<MatchSpan>,
79{
80    fn record_start(&mut self, start_idx: usize, start_depth: Depth, ty: MatchedNodeType) {
81        self.stack.push(PartialNode {
82            id: self.match_count,
83            start_idx,
84            start_depth,
85            ty,
86        });
87        self.match_count += 1;
88    }
89
90    fn record_end(&mut self, idx: usize, depth: Depth) -> Result<(), EngineError> {
91        while let Some(node) = self.stack.last() {
92            if node.start_depth >= depth {
93                let node = self.stack.pop().expect("last was Some, pop must succeed");
94                let end_idx = if node.ty == MatchedNodeType::Complex {
95                    idx + 1
96                } else {
97                    idx
98                };
99                let span = MatchSpan {
100                    start_idx: node.start_idx - self.leading_padding_len,
101                    len: end_idx - node.start_idx,
102                };
103                self.output_queue.insert(node.id, span);
104            } else {
105                break;
106            }
107        }
108
109        if self.stack.is_empty() {
110            self.output_queue
111                .output_to(self.sink)
112                .map_err(|err| EngineError::SinkError(Box::new(err)))?;
113        }
114
115        Ok(())
116    }
117}