use crate::handler::{Handler, TextBlockEvent, TextBlockKind};
use std::sync::{Arc, Mutex};
#[derive(Debug, Default)]
pub struct TextCollectorState {
buffer: String,
}
#[derive(Clone)]
pub struct TextBlockCollector {
collected: Arc<Mutex<Vec<String>>>,
}
impl TextBlockCollector {
pub fn new() -> Self {
Self {
collected: Arc::new(Mutex::new(Vec::new())),
}
}
pub fn take_collected(&self) -> Vec<String> {
let mut guard = self.collected.lock().unwrap();
std::mem::take(&mut *guard)
}
pub fn collected(&self) -> Vec<String> {
self.collected.lock().unwrap().clone()
}
pub fn has_content(&self) -> bool {
!self.collected.lock().unwrap().is_empty()
}
pub fn clear(&self) {
self.collected.lock().unwrap().clear();
}
}
impl Default for TextBlockCollector {
fn default() -> Self {
Self::new()
}
}
impl Handler<TextBlockKind> for TextBlockCollector {
type Scope = TextCollectorState;
fn on_event(&mut self, scope: &mut Self::Scope, event: &TextBlockEvent) {
match event {
TextBlockEvent::Start(_) => {
scope.buffer.clear();
}
TextBlockEvent::Delta(text) => {
scope.buffer.push_str(text);
}
TextBlockEvent::Stop(_) => {
if !scope.buffer.is_empty() {
let text = std::mem::take(&mut scope.buffer);
self.collected.lock().unwrap().push(text);
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::timeline::Timeline;
use crate::timeline::event::Event;
#[test]
fn test_collect_single_text_block() {
let collector = TextBlockCollector::new();
let mut timeline = Timeline::new();
timeline.on_text_block(collector.clone());
timeline.dispatch(&Event::text_block_start(0));
timeline.dispatch(&Event::text_delta(0, "Hello, "));
timeline.dispatch(&Event::text_delta(0, "World!"));
timeline.dispatch(&Event::text_block_stop(0, None));
let texts = collector.take_collected();
assert_eq!(texts.len(), 1);
assert_eq!(texts[0], "Hello, World!");
}
#[test]
fn test_collect_multiple_text_blocks() {
let collector = TextBlockCollector::new();
let mut timeline = Timeline::new();
timeline.on_text_block(collector.clone());
timeline.dispatch(&Event::text_block_start(0));
timeline.dispatch(&Event::text_delta(0, "First"));
timeline.dispatch(&Event::text_block_stop(0, None));
timeline.dispatch(&Event::text_block_start(1));
timeline.dispatch(&Event::text_delta(1, "Second"));
timeline.dispatch(&Event::text_block_stop(1, None));
let texts = collector.take_collected();
assert_eq!(texts.len(), 2);
assert_eq!(texts[0], "First");
assert_eq!(texts[1], "Second");
}
}