#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc = include_str!("../README.md")]
#[cfg(any(
all(feature = "real", feature = "mock"),
not(any(feature = "real", feature = "mock"))
))]
compile_error!("One of the two features 'real' or 'mock' must be enabled");
use melodium_core::*;
use melodium_macro::{check, mel_function, mel_package, mel_treatment};
use regex::Regex;
use std::collections::HashMap;
use std::sync::Arc;
use std_mel::data::string_map::*;
#[mel_treatment(
input text Stream<string>
output matches Stream<bool>
output error Block<string>
)]
pub async fn matches(#[mel(content(regex))] regex: string) {
match Regex::new(®ex) {
Ok(regex) => {
error.close().await;
while let Ok(text) = text
.recv_many()
.await
.map(|values| TryInto::<Vec<string>>::try_into(values).unwrap())
{
check!(
matches
.send_many(
text.into_iter()
.map(|txt| regex.is_match(&txt))
.collect::<VecDeque<_>>()
.into()
)
.await
);
}
}
Err(err) => {
let _ = error.send_one(err.to_string().into()).await;
}
}
}
#[mel_function]
pub fn matches(text: string, #[mel(content(regex))] regex: string) -> bool {
match Regex::new(®ex) {
Ok(regex) => regex.is_match(&text),
Err(_) => false,
}
}
#[mel_treatment(
input text Stream<string>
output found Stream<Option<string>>
output error Block<string>
)]
pub async fn find(#[mel(content(regex))] regex: string) {
match Regex::new(®ex) {
Ok(regex) => {
error.close().await;
while let Ok(text) = text
.recv_many()
.await
.map(|values| TryInto::<Vec<string>>::try_into(values).unwrap())
{
let mut vec_found = VecDeque::with_capacity(text.len());
for text in text {
match regex.find(&text) {
Some(m) => {
vec_found.push_back(Some(m.as_str().to_string()).into());
}
None => {
vec_found.push_back(Value::Option(None));
}
}
}
check!(found.send_many(TransmissionValue::Other(vec_found)).await)
}
}
Err(err) => {
let _ = error.send_one(err.to_string().into()).await;
}
}
}
#[mel_function]
pub fn find(text: string, #[mel(content(regex))] regex: string) -> Option<string> {
match Regex::new(®ex) {
Ok(regex) => regex.find(&text).map(|m| m.as_str().to_string()),
Err(_) => None,
}
}
#[mel_treatment(
input text Stream<string>
output captured Stream<Option<StringMap>>
output error Block<string>
)]
pub async fn capture(#[mel(content(regex))] regex: string) {
match Regex::new(®ex) {
Ok(regex) => {
error.close().await;
while let Ok(text) = text
.recv_many()
.await
.map(|values| TryInto::<Vec<string>>::try_into(values).unwrap())
{
let mut vec_captured = VecDeque::with_capacity(text.len());
for text in text {
match regex.captures(&text) {
Some(captures) => {
let mut map_captured = HashMap::new();
for name in regex.capture_names() {
if let Some(name) = name {
if let Some(cap) = captures.name(name) {
map_captured
.insert(name.to_string(), cap.as_str().to_string());
}
}
}
vec_captured.push_back(Value::Option(Some(Box::new(Value::Data(
Arc::new(StringMap::new_with(map_captured)),
)))));
}
None => {
vec_captured.push_back(Value::Option(None));
}
}
}
check!(
captured
.send_many(TransmissionValue::Other(vec_captured))
.await
)
}
}
Err(err) => {
let _ = error.send_one(err.to_string().into()).await;
}
}
}
#[mel_function]
pub fn capture(text: string, #[mel(content(regex))] regex: string) -> Option<StringMap> {
match Regex::new(®ex) {
Ok(regex) => match regex.captures(&text) {
Some(captures) => {
let mut map_captured = HashMap::new();
for name in regex.capture_names() {
if let Some(name) = name {
if let Some(cap) = captures.name(name) {
map_captured.insert(name.to_string(), cap.as_str().to_string());
}
}
}
Some(StringMap::new_with(map_captured))
}
None => None,
},
Err(_) => None,
}
}
#[mel_treatment(
input text Stream<string>
output replaced Stream<string>
output error Block<string>
)]
pub async fn replace(#[mel(content(regex))] regex: string, replacer: string) {
match Regex::new(®ex) {
Ok(regex) => {
error.close().await;
while let Ok(text) = text
.recv_many()
.await
.map(|values| TryInto::<Vec<string>>::try_into(values).unwrap())
{
let mut vec_replaced = Vec::with_capacity(text.len());
for text in text {
vec_replaced.push(regex.replace(&text, &replacer).to_string());
}
check!(replaced.send_many(vec_replaced.into()).await);
}
}
Err(err) => {
let _ = error.send_one(err.to_string().into()).await;
}
}
}
#[mel_function]
pub fn replace(
text: string,
#[mel(content(regex))] regex: string,
replacer: string,
) -> Option<string> {
match Regex::new(®ex) {
Ok(regex) => Some(regex.replace(&text, &replacer).to_string()),
Err(_) => None,
}
}
mel_package!();