use super::domain::{read_evidence, write_evidence};
use super::io::{Reader, Writer, codec};
use crate::{
error::Result,
id::FactId,
projection::memory::state::{Retraction, RetractionHistory},
time::Timestamp,
};
use std::collections::BTreeMap;
#[cfg(test)]
pub(super) fn write_v1(
writer: &mut Writer,
retractions: &BTreeMap<FactId, RetractionHistory>,
) -> Result<()> {
writer.usize(retractions.len())?;
for (fact, history) in retractions {
let change = history
.last()
.ok_or_else(|| codec("retraction history must not be empty"))?;
writer.string(fact.as_str())?;
writer.signed(change.valid_until.as_unix_micros());
writer.signed(change.recorded_at.as_unix_micros());
}
Ok(())
}
pub(super) fn write(
writer: &mut Writer,
retractions: &BTreeMap<FactId, RetractionHistory>,
) -> Result<()> {
writer.usize(retractions.len())?;
for (fact, history) in retractions {
writer.string(fact.as_str())?;
writer.usize(history.len())?;
for change in history {
write_change(writer, change)?;
}
}
Ok(())
}
pub(super) fn read_v2(reader: &mut Reader<'_>) -> Result<BTreeMap<FactId, RetractionHistory>> {
let count = reader.count()?;
let mut changes = BTreeMap::new();
for _ in 0..count {
let fact = FactId::new(reader.string()?)?;
let versions = reader.count()?;
if versions == 0 {
return Err(codec("retraction history must not be empty"));
}
let mut history = Vec::with_capacity(versions);
for _ in 0..versions {
history.push(read_change(reader)?);
}
if changes.insert(fact, history).is_some() {
return Err(codec("duplicate retraction"));
}
}
Ok(changes)
}
pub(super) fn read_v1(reader: &mut Reader<'_>) -> Result<BTreeMap<FactId, RetractionHistory>> {
let count = reader.count()?;
let mut changes = BTreeMap::new();
for _ in 0..count {
let fact = FactId::new(reader.string()?)?;
let change = Retraction {
valid_until: Timestamp::from_unix_micros(reader.signed()?),
recorded_at: Timestamp::from_unix_micros(reader.signed()?),
position: 0,
evidence: Vec::new(),
};
if changes.insert(fact, vec![change]).is_some() {
return Err(codec("duplicate retraction"));
}
}
Ok(changes)
}
fn write_change(writer: &mut Writer, change: &Retraction) -> Result<()> {
writer.signed(change.valid_until.as_unix_micros());
writer.signed(change.recorded_at.as_unix_micros());
writer.varint(change.position);
writer.usize(change.evidence.len())?;
for evidence in &change.evidence {
write_evidence(writer, evidence)?;
}
Ok(())
}
fn read_change(reader: &mut Reader<'_>) -> Result<Retraction> {
let valid_until = Timestamp::from_unix_micros(reader.signed()?);
let recorded_at = Timestamp::from_unix_micros(reader.signed()?);
let position = reader.varint()?;
let count = reader.count()?;
let mut evidence = Vec::with_capacity(count);
for _ in 0..count {
evidence.push(read_evidence(reader)?);
}
Ok(Retraction {
valid_until,
recorded_at,
position,
evidence,
})
}