use super::Handler;
use crate::{error, path::Path, streamer::Token};
use std::{any::Any, str, str::FromStr};
#[derive(Default)]
pub struct Regex {
replacements: Vec<String>,
buffer: Vec<u8>,
}
impl Handler for Regex {
fn feed(
&mut self,
data: &[u8],
_matcher_idx: usize,
) -> Result<Option<Vec<u8>>, error::Handler> {
self.buffer.extend(data);
Ok(None)
}
fn end(
&mut self,
_path: &Path,
_matcher_idx: usize,
_token: Token,
) -> Result<Option<Vec<u8>>, error::Handler> {
let mut output: String = str::from_utf8(&self.buffer)
.map_err(|e| error::Handler::new(e.to_string()))?
.to_string();
output = sedregex::find_and_replace(&output, &self.replacements)
.map_err(error::Handler::new)?
.to_string();
self.buffer.clear();
Ok(Some(output.as_bytes().to_vec()))
}
fn is_converter(&self) -> bool {
true
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl FromStr for Regex {
type Err = error::Handler;
fn from_str(input: &str) -> Result<Self, Self::Err> {
sedregex::ReplaceCommand::new(input).map_err(error::Handler::new)?;
let mut new = Regex::new();
new = new.add_regex(input.to_string());
Ok(new)
}
}
impl Regex {
pub fn new() -> Self {
Self::default()
}
pub fn add_regex(mut self, sedregex: String) -> Self {
self.replacements.push(sedregex);
self
}
}
#[cfg(test)]
mod tests {
use crate::{
handler,
matcher::Simple,
strategy::{Convert, OutputConverter, Strategy},
};
use std::sync::{Arc, Mutex};
#[test]
fn regex_converter() {
let mut convert = Convert::new();
let regex_converter =
handler::Regex::new().add_regex("s/[Uu]ser([0-9]+)/user$1/".to_string());
let matcher = Simple::new(r#"[]{"name"}"#).unwrap();
convert.add_matcher(Box::new(matcher), Arc::new(Mutex::new(regex_converter)));
let output: Vec<u8> = OutputConverter::new()
.convert(
&convert
.process(br#"[{"name": "User1 User1"}, {"name": "user2"}]"#)
.unwrap(),
)
.into_iter()
.map(|e| e.1)
.flatten()
.collect();
assert_eq!(
String::from_utf8(output).unwrap(),
r#"[{"name": "user1 User1"}, {"name": "user2"}]"#
);
}
}