use crate::record::kind::Kind;
use crate::record::payloads::VerdictData;
use crate::record::record::{decode, Record};
use crate::record::refs::RecordId;
use crate::state::incremental::apply_record;
use crate::state::state::State;
use std::collections::BTreeMap;
pub fn build_state_unchecked(records: &[Record]) -> Result<State, serde_json::Error> {
let mut state = State::default();
if records.is_empty() {
return Ok(state);
}
let mut verdict_map: BTreeMap<RecordId, VerdictData> = BTreeMap::new();
for record in records {
if record.kind == Kind::Verdict {
if let Some(subject_id) = record
.refs
.iter()
.find(|r| r.type_ == crate::record::kind::RefType::Cause)
.map(|r| r.target)
{
let data: VerdictData = decode(&record.data)?;
verdict_map.insert(subject_id, data);
}
}
}
for record in records {
if record.kind == Kind::Verdict {
continue;
}
if let Some(verdict) = verdict_map.get(&record.id) {
apply_record(&mut state, record, verdict)?;
}
}
state.applied_up_to = records.last().map(|r| r.time).unwrap_or(0);
Ok(state)
}
pub fn verify_and_build_state(
records: &[Record],
rules: &crate::verify::rules::VerifierRules,
) -> Result<State, Box<crate::verify::verifier::LogVerdict>> {
let verdict = crate::verify::verifier::verify_log(records, rules, None);
if verdict.result != crate::record::kind::VerdictResult::Accept {
return Err(Box::new(verdict));
}
build_state_unchecked(records).map_err(|_| {
let mut v = verdict;
v.result = crate::record::kind::VerdictResult::Reject;
v.reason = Some(crate::record::kind::ReasonCode::InvalidPayload);
Box::new(v)
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_build_state_empty() {
let state = build_state_unchecked(&[]).unwrap();
assert_eq!(state.applied_up_to, 0);
assert!(state.accepted_records.is_empty());
}
}