kernel/capabilities/
stop_matcher.rs1use crate::capabilities::held_suffix_len;
6use crate::records::JsonValue;
7
8#[derive(Debug, Clone)]
10pub struct StopMatcher {
11 stops: Vec<String>,
12 buffer: String,
13 stopped: bool,
14}
15
16impl StopMatcher {
17 pub fn new(stops: Vec<String>) -> Self {
19 Self {
20 stops: stops.into_iter().filter(|stop| !stop.is_empty()).collect(),
21 buffer: String::new(),
22 stopped: false,
23 }
24 }
25
26 pub fn is_active(&self) -> bool {
28 !self.stops.is_empty()
29 }
30
31 pub fn is_stopped(&self) -> bool {
33 self.stopped
34 }
35
36 pub fn feed(&mut self, chunk: &str) -> String {
41 if !self.is_active() {
42 return chunk.to_owned();
43 }
44 if self.stopped {
45 return String::new();
46 }
47 self.buffer.push_str(chunk);
48 if let Some(position) = self.earliest_stop() {
49 let emit = self.buffer[..position].to_owned();
50 self.buffer.clear();
51 self.stopped = true;
52 return emit;
53 }
54 let held = held_suffix_len(&self.buffer, &self.stops);
55 let split = self.buffer.len() - held;
56 let emit = self.buffer[..split].to_owned();
57 self.buffer.drain(..split);
58 emit
59 }
60
61 pub fn flush(&mut self) -> String {
63 if self.stopped {
64 return String::new();
65 }
66 std::mem::take(&mut self.buffer)
67 }
68
69 fn earliest_stop(&self) -> Option<usize> {
70 self.stops
71 .iter()
72 .filter_map(|stop| self.buffer.find(stop.as_str()))
73 .min()
74 }
75}
76
77pub fn stop_strings(value: Option<&JsonValue>) -> Vec<String> {
80 match value {
81 Some(JsonValue::String(single)) => vec![single.clone()],
82 Some(JsonValue::Array(items)) => items
83 .iter()
84 .filter_map(|item| item.as_str().map(str::to_owned))
85 .collect(),
86 _ => Vec::new(),
87 }
88}