use crate::ast::{self, AstFailure};
use crate::error::{Error, Result};
use crate::hashing;
use crate::json;
use super::{Probe, ProbeFailure};
pub(super) fn hash_raw(name: &str, probe: &Probe, bytes: &[u8]) -> Result<String> {
if !probe.allow_empty && bytes.iter().all(u8::is_ascii_whitespace) {
return Err(ProbeFailure::Empty {
run: probe.run.clone().unwrap_or_default(),
}
.named(name));
}
Ok(hashing::hash_bytes(bytes))
}
pub(super) fn hash_selection(
name: &str,
probe: &Probe,
program: &str,
bytes: &[u8],
) -> Result<String> {
let selected = json::select(program, bytes).map_err(|failure| {
match failure {
json::Failure::Input(reason) => ProbeFailure::JsonInput {
origin: probe.origin(),
reason,
},
json::Failure::Program(reason) | json::Failure::Run(reason) => {
ProbeFailure::JsonFailed {
program: program.to_owned(),
origin: probe.origin(),
reason,
}
}
}
.named(name)
})?;
if !probe.allow_empty && selected_nothing(&selected) {
return Err(ProbeFailure::JsonEmpty {
program: program.to_owned(),
origin: probe.origin(),
}
.named(name));
}
Ok(hash_joined(&selected))
}
pub(super) fn hash_matches(
name: &str,
probe: &Probe,
pattern: &str,
bytes: &[u8],
) -> Result<String> {
let origin = probe.origin();
let lang = ast::resolve_lang(probe.lang.as_deref(), probe.file.as_deref(), &origin)
.map_err(|failure| ast_error(name, failure))?;
let matched = ast::select(lang, pattern, probe.capture.as_deref(), bytes, &origin)
.map_err(|failure| ast_error(name, failure))?;
if !probe.allow_empty && matched.is_empty() {
return Err(ast_error(
name,
AstFailure::Empty {
pattern: pattern.to_owned(),
origin,
},
));
}
Ok(hash_joined(&matched))
}
fn ast_error(name: &str, failure: AstFailure) -> Error {
ProbeFailure::Ast(Box::new(failure)).named(name)
}
fn hash_joined(values: &[Vec<u8>]) -> String {
let mut joined = Vec::new();
for value in values {
joined.extend_from_slice(value);
joined.push(b'\n');
}
hashing::hash_bytes(&joined)
}
fn selected_nothing(selected: &[Vec<u8>]) -> bool {
match selected {
[] => true,
[only] => only.as_slice() == b"null",
_ => false,
}
}