use std::{
any::Any,
ops,
sync::{Arc, Mutex},
};
use crate::{error, path::Path, streamer::Token};
use super::Handler;
#[derive(Default, Clone)]
pub struct Group {
handlers: Vec<Arc<Mutex<dyn Handler>>>,
}
impl Group {
pub fn new() -> Self {
Default::default()
}
pub fn add_handler(mut self, handler: Arc<Mutex<dyn Handler>>) -> Self {
self.handlers.push(handler);
self
}
pub fn add_handler_mut(&mut self, handler: Arc<Mutex<dyn Handler>>) {
self.handlers.push(handler);
}
pub fn subhandlers(&self) -> &[Arc<Mutex<dyn Handler>>] {
&self.handlers
}
}
impl Handler for Group {
fn start(
&mut self,
path: &Path,
matcher_idx: usize,
token: Token,
) -> Result<Option<Vec<u8>>, error::Handler> {
let mut result = None;
for handler in self.handlers.iter() {
let mut guard = handler.lock().unwrap();
if guard.is_converter() {
let orig_result = result.take();
result = guard.start(path, matcher_idx, token.clone())?;
if let Some(orig_data) = orig_result {
let feed_output = guard.feed(&orig_data, matcher_idx)?;
if let Some(mut data) = result.take() {
if let Some(feed_data) = feed_output {
data.extend(feed_data);
result = Some(data);
}
} else {
result = feed_output;
}
}
} else {
guard.start(path, matcher_idx, token.clone())?;
if let Some(data) = result.as_ref() {
guard.feed(data, matcher_idx)?;
}
}
}
Ok(result)
}
fn feed(&mut self, data: &[u8], matcher_idx: usize) -> Result<Option<Vec<u8>>, error::Handler> {
let mut result = Some(data.to_vec());
for handler in self.handlers.iter() {
let mut guard = handler.lock().unwrap();
if let Some(data) = result.take() {
if guard.is_converter() {
result = guard.feed(&data, matcher_idx)?;
} else {
guard.feed(&data, matcher_idx)?;
result = Some(data)
}
} else {
break;
}
}
Ok(result)
}
fn end(
&mut self,
path: &Path,
matcher_idx: usize,
token: Token,
) -> Result<Option<Vec<u8>>, error::Handler> {
let mut result: Option<Vec<u8>> = None;
for handler in self.handlers.iter() {
let mut guard = handler.lock().unwrap();
if guard.is_converter() {
if let Some(data) = result.take() {
result = guard.feed(&data, matcher_idx)?;
}
if let Some(data) = guard.end(path, matcher_idx, token.clone())? {
if let Some(mut result_data) = result.take() {
result_data.extend(data);
result = Some(result_data);
} else {
result = Some(data);
}
}
} else {
if let Some(data) = result.as_ref() {
guard.feed(data, matcher_idx)?;
}
guard.end(path, matcher_idx, token.clone())?;
}
}
Ok(result)
}
fn is_converter(&self) -> bool {
self.handlers
.iter()
.any(|e| e.lock().unwrap().is_converter())
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl ops::Add for Group {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
let mut joined = Self::new();
self.subhandlers()
.iter()
.for_each(|h| joined.add_handler_mut(h.clone()));
rhs.subhandlers()
.iter()
.for_each(|h| joined.add_handler_mut(h.clone()));
joined
}
}
#[cfg(test)]
mod tests {
use super::Group;
use crate::{
handler::{Buffer, Replace, Shorten},
matcher::Simple,
strategy::{Convert, Extract, Filter, OutputConverter, Strategy, Trigger},
};
use std::sync::{Arc, Mutex};
fn prepare_handlers() -> (
Arc<Mutex<Buffer>>,
Arc<Mutex<Buffer>>,
Arc<Mutex<Buffer>>,
Arc<Mutex<Replace>>,
Arc<Mutex<Shorten>>,
) {
(
Arc::new(Mutex::new(Buffer::new())),
Arc::new(Mutex::new(Buffer::new())),
Arc::new(Mutex::new(Buffer::new())),
Arc::new(Mutex::new(Replace::new(br#""ccccc""#.to_vec()))),
Arc::new(Mutex::new(Shorten::new(3, r#"..""#.into()))),
)
}
#[test]
fn test_convert() {
let mut convert = Convert::new();
let (buffer1, buffer2, buffer3, replace, shorten) = prepare_handlers();
let matcher = Simple::new(r#"[]{"desc"}"#).unwrap();
let group = Group::new()
.add_handler(buffer1.clone())
.add_handler(replace.clone())
.add_handler(buffer2.clone())
.add_handler(shorten.clone())
.add_handler(buffer3.clone());
convert.add_matcher(Box::new(matcher), Arc::new(Mutex::new(group)));
let output = OutputConverter::new()
.convert(
&convert
.process(br#"[{"desc": "aa"}, {"desc": "bbbbbb"}]"#)
.unwrap(),
)
.into_iter()
.map(|e| e.1)
.collect::<Vec<Vec<u8>>>();
assert_eq!(
String::from_utf8(output.into_iter().flatten().collect()).unwrap(),
r#"[{"desc": "ccc.."}, {"desc": "ccc.."}]"#
);
assert_eq!(
String::from_utf8(buffer1.lock().unwrap().pop().unwrap().1).unwrap(),
r#""aa""#
);
assert_eq!(
String::from_utf8(buffer1.lock().unwrap().pop().unwrap().1).unwrap(),
r#""bbbbbb""#
);
assert!(buffer1.lock().unwrap().pop().is_none());
assert_eq!(
String::from_utf8(buffer2.lock().unwrap().pop().unwrap().1).unwrap(),
r#""ccccc""#
);
assert_eq!(
String::from_utf8(buffer2.lock().unwrap().pop().unwrap().1).unwrap(),
r#""ccccc""#
);
assert!(buffer2.lock().unwrap().pop().is_none());
assert_eq!(
String::from_utf8(buffer3.lock().unwrap().pop().unwrap().1).unwrap(),
r#""ccc..""#
);
assert_eq!(
String::from_utf8(buffer3.lock().unwrap().pop().unwrap().1).unwrap(),
r#""ccc..""#
);
assert!(buffer3.lock().unwrap().pop().is_none());
}
#[test]
fn test_trigger() {
let mut trigger = Trigger::new();
let (buffer1, buffer2, buffer3, replace, shorten) = prepare_handlers();
let matcher = Simple::new(r#"[]{"desc"}"#).unwrap();
let group = Group::new()
.add_handler(buffer1.clone())
.add_handler(replace.clone())
.add_handler(buffer2.clone())
.add_handler(shorten.clone())
.add_handler(buffer3.clone());
trigger.add_matcher(Box::new(matcher), Arc::new(Mutex::new(group)));
trigger
.process(br#"[{"desc": "aa"}, {"desc": "bbbbbb"}]"#)
.unwrap();
assert_eq!(
String::from_utf8(buffer1.lock().unwrap().pop().unwrap().1).unwrap(),
r#""aa""#
);
assert_eq!(
String::from_utf8(buffer1.lock().unwrap().pop().unwrap().1).unwrap(),
r#""bbbbbb""#
);
assert!(buffer1.lock().unwrap().pop().is_none());
assert_eq!(
String::from_utf8(buffer2.lock().unwrap().pop().unwrap().1).unwrap(),
r#""ccccc""#
);
assert_eq!(
String::from_utf8(buffer2.lock().unwrap().pop().unwrap().1).unwrap(),
r#""ccccc""#
);
assert!(buffer2.lock().unwrap().pop().is_none());
assert_eq!(
String::from_utf8(buffer3.lock().unwrap().pop().unwrap().1).unwrap(),
r#""ccc..""#
);
assert_eq!(
String::from_utf8(buffer3.lock().unwrap().pop().unwrap().1).unwrap(),
r#""ccc..""#
);
assert!(buffer3.lock().unwrap().pop().is_none());
}
#[test]
fn test_filter() {
let mut filter = Filter::new();
let (buffer1, buffer2, buffer3, replace, shorten) = prepare_handlers();
let matcher = Simple::new(r#"[]{"desc"}"#).unwrap();
let group = Group::new()
.add_handler(buffer1.clone())
.add_handler(replace.clone())
.add_handler(buffer2.clone())
.add_handler(shorten.clone())
.add_handler(buffer3.clone());
filter.add_matcher(Box::new(matcher), Some(Arc::new(Mutex::new(group))));
let output: Vec<u8> = OutputConverter::new()
.convert(
&filter
.process(br#"[{"desc": "aa"}, {"desc": "bbbbbb"}]"#)
.unwrap(),
)
.into_iter()
.map(|e| e.1)
.flatten()
.collect();
assert_eq!(String::from_utf8(output).unwrap(), r#"[{}, {}]"#);
assert_eq!(
String::from_utf8(buffer1.lock().unwrap().pop().unwrap().1).unwrap(),
r#""aa""#
);
assert_eq!(
String::from_utf8(buffer1.lock().unwrap().pop().unwrap().1).unwrap(),
r#""bbbbbb""#
);
assert!(buffer1.lock().unwrap().pop().is_none());
assert_eq!(
String::from_utf8(buffer2.lock().unwrap().pop().unwrap().1).unwrap(),
r#""ccccc""#
);
assert_eq!(
String::from_utf8(buffer2.lock().unwrap().pop().unwrap().1).unwrap(),
r#""ccccc""#
);
assert!(buffer2.lock().unwrap().pop().is_none());
assert_eq!(
String::from_utf8(buffer3.lock().unwrap().pop().unwrap().1).unwrap(),
r#""ccc..""#
);
assert_eq!(
String::from_utf8(buffer3.lock().unwrap().pop().unwrap().1).unwrap(),
r#""ccc..""#
);
assert!(buffer3.lock().unwrap().pop().is_none());
}
#[test]
fn test_extract() {
let mut extract = Extract::new();
let (buffer1, buffer2, buffer3, replace, shorten) = prepare_handlers();
let matcher = Simple::new(r#"[]{"desc"}"#).unwrap();
let group = Group::new()
.add_handler(buffer1.clone())
.add_handler(replace.clone())
.add_handler(buffer2.clone())
.add_handler(shorten.clone())
.add_handler(buffer3.clone());
extract.add_matcher(Box::new(matcher), Some(Arc::new(Mutex::new(group))));
let output: Vec<u8> = OutputConverter::new()
.convert(
&extract
.process(br#"[{"desc": "aa"}, {"desc": "bbbbbb"}]"#)
.unwrap(),
)
.into_iter()
.map(|e| e.1)
.flatten()
.collect();
assert_eq!(String::from_utf8(output).unwrap(), r#""aa""bbbbbb""#);
assert_eq!(
String::from_utf8(buffer1.lock().unwrap().pop().unwrap().1).unwrap(),
r#""aa""#
);
assert_eq!(
String::from_utf8(buffer1.lock().unwrap().pop().unwrap().1).unwrap(),
r#""bbbbbb""#
);
assert!(buffer1.lock().unwrap().pop().is_none());
assert_eq!(
String::from_utf8(buffer2.lock().unwrap().pop().unwrap().1).unwrap(),
r#""ccccc""#
);
assert_eq!(
String::from_utf8(buffer2.lock().unwrap().pop().unwrap().1).unwrap(),
r#""ccccc""#
);
assert!(buffer2.lock().unwrap().pop().is_none());
assert_eq!(
String::from_utf8(buffer3.lock().unwrap().pop().unwrap().1).unwrap(),
r#""ccc..""#
);
assert_eq!(
String::from_utf8(buffer3.lock().unwrap().pop().unwrap().1).unwrap(),
r#""ccc..""#
);
assert!(buffer3.lock().unwrap().pop().is_none());
}
}