use crate::SearchControl;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SearchStatus {
Complete,
Partial,
Cancelled,
Infeasible,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SearchReceipt {
pub status: SearchStatus,
pub reason: Option<String>,
pub work_used: u64,
pub expanded: u64,
pub scored: u64,
pub propagated: u64,
pub emitted: u64,
pub pruned: u64,
pub max_frontier: usize,
pub result_count: usize,
pub seed: u64,
pub policy_digest: String,
pub digest: String,
}
impl SearchReceipt {
pub(crate) fn invalid(control: &SearchControl, reason: String) -> Self {
Self::finalize(
SearchStatus::Partial,
Some(format!("invalid control: {reason}")),
Metrics::default(),
control,
&[],
)
}
pub(crate) fn finalize(
status: SearchStatus,
reason: Option<String>,
metrics: Metrics,
control: &SearchControl,
output_material: &[String],
) -> Self {
let policy_material = control.policy_material();
let policy_digest = stable_digest(&[policy_material.as_str()]);
let status_material = format!("{status:?}");
let reason_material = reason.clone().unwrap_or_default();
let metrics_material = format!(
"work={};expanded={};scored={};propagated={};emitted={};pruned={};max_frontier={};result_count={}",
metrics.work_used,
metrics.expanded,
metrics.scored,
metrics.propagated,
metrics.emitted,
metrics.pruned,
metrics.max_frontier,
metrics.result_count,
);
let mut parts = vec![
policy_material.as_str(),
status_material.as_str(),
reason_material.as_str(),
metrics_material.as_str(),
];
parts.extend(output_material.iter().map(String::as_str));
let digest = stable_digest(&parts);
Self {
status,
reason,
work_used: metrics.work_used,
expanded: metrics.expanded,
scored: metrics.scored,
propagated: metrics.propagated,
emitted: metrics.emitted,
pruned: metrics.pruned,
max_frontier: metrics.max_frontier,
result_count: metrics.result_count,
seed: control.seed,
policy_digest,
digest,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SearchRun<Output> {
pub outputs: Vec<Output>,
pub receipt: SearchReceipt,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub(crate) struct Metrics {
pub(crate) work_used: u64,
pub(crate) expanded: u64,
pub(crate) scored: u64,
pub(crate) propagated: u64,
pub(crate) emitted: u64,
pub(crate) pruned: u64,
pub(crate) max_frontier: usize,
pub(crate) result_count: usize,
}
pub(crate) fn stable_digest(parts: &[&str]) -> String {
let mut hash = 0xcbf29ce484222325u64;
for part in parts {
for byte in part.as_bytes() {
hash ^= u64::from(*byte);
hash = hash.wrapping_mul(0x100000001b3);
}
hash ^= 0xff;
hash = hash.wrapping_mul(0x100000001b3);
}
format!("{hash:016x}")
}