use crate::context::EvalError;
use crate::value::Val;
use std::sync::Arc;
fn compile_regex_eval(pat: &str) -> Result<Arc<regex::Regex>, EvalError> {
crate::builtin_helpers::compile_regex(pat).map_err(EvalError)
}
#[inline]
pub fn re_match_apply(recv: &Val, pat: &str) -> Option<Val> {
try_re_match_apply(recv, pat).ok().flatten()
}
#[inline]
pub fn try_re_match_apply(recv: &Val, pat: &str) -> Result<Option<Val>, EvalError> {
let Some(s) = recv.as_str_ref() else {
return Ok(None);
};
let re = compile_regex_eval(pat)?;
Ok(Some(Val::Bool(re.is_match(s))))
}
#[inline]
pub fn re_match_first_apply(recv: &Val, pat: &str) -> Option<Val> {
try_re_match_first_apply(recv, pat).ok().flatten()
}
#[inline]
pub fn try_re_match_first_apply(recv: &Val, pat: &str) -> Result<Option<Val>, EvalError> {
let Some(s) = recv.as_str_ref() else {
return Ok(None);
};
let re = compile_regex_eval(pat)?;
Ok(Some(
re.find(s)
.map(|m| Val::Str(Arc::from(m.as_str())))
.unwrap_or(Val::Null),
))
}
#[inline]
pub fn re_match_all_apply(recv: &Val, pat: &str) -> Option<Val> {
try_re_match_all_apply(recv, pat).ok().flatten()
}
#[inline]
pub fn try_re_match_all_apply(recv: &Val, pat: &str) -> Result<Option<Val>, EvalError> {
let Some(s) = recv.as_str_ref() else {
return Ok(None);
};
let re = compile_regex_eval(pat)?;
let out: Vec<Arc<str>> = re
.find_iter(s)
.map(|m| Arc::<str>::from(m.as_str()))
.collect();
Ok(Some(Val::str_vec(out)))
}
#[inline]
pub fn re_captures_apply(recv: &Val, pat: &str) -> Option<Val> {
try_re_captures_apply(recv, pat).ok().flatten()
}
#[inline]
pub fn try_re_captures_apply(recv: &Val, pat: &str) -> Result<Option<Val>, EvalError> {
let Some(s) = recv.as_str_ref() else {
return Ok(None);
};
let re = compile_regex_eval(pat)?;
Ok(Some(match re.captures(s) {
Some(c) => {
let mut out: Vec<Val> = Vec::with_capacity(c.len());
for i in 0..c.len() {
out.push(
c.get(i)
.map(|m| Val::Str(Arc::from(m.as_str())))
.unwrap_or(Val::Null),
);
}
Val::arr(out)
}
None => Val::Null,
}))
}
#[inline]
pub fn re_captures_all_apply(recv: &Val, pat: &str) -> Option<Val> {
try_re_captures_all_apply(recv, pat).ok().flatten()
}
#[inline]
pub fn try_re_captures_all_apply(recv: &Val, pat: &str) -> Result<Option<Val>, EvalError> {
let Some(s) = recv.as_str_ref() else {
return Ok(None);
};
let re = compile_regex_eval(pat)?;
let mut all: Vec<Val> = Vec::new();
for c in re.captures_iter(s) {
let mut row: Vec<Val> = Vec::with_capacity(c.len());
for i in 0..c.len() {
row.push(
c.get(i)
.map(|m| Val::Str(Arc::from(m.as_str())))
.unwrap_or(Val::Null),
);
}
all.push(Val::arr(row));
}
Ok(Some(Val::arr(all)))
}
#[inline]
pub fn re_replace_apply(recv: &Val, pat: &str, with: &str) -> Option<Val> {
try_re_replace_apply(recv, pat, with).ok().flatten()
}
#[inline]
pub fn try_re_replace_apply(recv: &Val, pat: &str, with: &str) -> Result<Option<Val>, EvalError> {
let Some(s) = recv.as_str_ref() else {
return Ok(None);
};
let re = compile_regex_eval(pat)?;
let out = re.replace(s, with);
Ok(Some(Val::Str(Arc::from(out.as_ref()))))
}
#[inline]
pub fn re_replace_all_apply(recv: &Val, pat: &str, with: &str) -> Option<Val> {
try_re_replace_all_apply(recv, pat, with).ok().flatten()
}
#[inline]
pub fn try_re_replace_all_apply(
recv: &Val,
pat: &str,
with: &str,
) -> Result<Option<Val>, EvalError> {
let Some(s) = recv.as_str_ref() else {
return Ok(None);
};
let re = compile_regex_eval(pat)?;
let out = re.replace_all(s, with);
Ok(Some(Val::Str(Arc::from(out.as_ref()))))
}
#[inline]
pub fn re_split_apply(recv: &Val, pat: &str) -> Option<Val> {
try_re_split_apply(recv, pat).ok().flatten()
}
#[inline]
pub fn try_re_split_apply(recv: &Val, pat: &str) -> Result<Option<Val>, EvalError> {
let Some(s) = recv.as_str_ref() else {
return Ok(None);
};
let re = compile_regex_eval(pat)?;
let out: Vec<Arc<str>> = re.split(s).map(Arc::<str>::from).collect();
Ok(Some(Val::str_vec(out)))
}
#[inline]
pub fn contains_any_apply(recv: &Val, needles: &[Arc<str>]) -> Option<Val> {
let s = recv.as_str_ref()?;
Some(Val::Bool(needles.iter().any(|n| s.contains(n.as_ref()))))
}
#[inline]
pub fn contains_all_apply(recv: &Val, needles: &[Arc<str>]) -> Option<Val> {
let s = recv.as_str_ref()?;
Some(Val::Bool(needles.iter().all(|n| s.contains(n.as_ref()))))
}