use panproto_inst::WInstance;
use panproto_schema::{Protocol, Schema};
use crate::data_mig::migrate_backward;
use crate::error::VcsError;
use crate::hash::ObjectId;
use crate::object::{CommitObject, Object};
use crate::store::Store;
pub fn verify_lifted_squares(
store: &mut dyn Store,
commit: &CommitObject,
lifted_data_ids: &[ObjectId],
lifted_complement_ids: &[ObjectId],
src_schema: &Schema,
tgt_schema: &Schema,
) -> Result<(), VcsError> {
let existing = commit.complement_ids.len();
if lifted_complement_ids.len() != existing + lifted_data_ids.len() {
return Ok(());
}
let protocol = crate::data_mig::protocol_for_schema(src_schema);
for (i, (&base_id, &replayed_id)) in commit.data_ids.iter().zip(lifted_data_ids).enumerate() {
verify_square(
store,
base_id,
replayed_id,
lifted_complement_ids[existing + i],
src_schema,
tgt_schema,
&protocol,
)?;
}
Ok(())
}
pub fn verify_square(
store: &mut dyn Store,
base: ObjectId,
replayed: ObjectId,
complement: ObjectId,
src_schema: &Schema,
tgt_schema: &Schema,
protocol: &Protocol,
) -> Result<(), VcsError> {
let roundtrip = migrate_backward(
store, replayed, complement, src_schema, tgt_schema, protocol,
)?;
let base_instances = load_instances(store, base)?;
let roundtrip_instances = load_instances(store, roundtrip)?;
if base_instances.len() != roundtrip_instances.len() {
return Err(VcsError::SquareNonCommuting {
detail: format!(
"data set count changed under round-trip: {} then {}",
base_instances.len(),
roundtrip_instances.len()
),
});
}
for (i, (before, after)) in base_instances.iter().zip(&roundtrip_instances).enumerate() {
if !panproto_lens::instances_equivalent(before, after) {
return Err(VcsError::SquareNonCommuting {
detail: format!("data set {i} diverges from its forward-then-back image"),
});
}
}
Ok(())
}
fn load_instances(store: &dyn Store, id: ObjectId) -> Result<Vec<WInstance>, VcsError> {
match store.get(&id)? {
Object::DataSet(ds) => {
rmp_serde::from_slice(&ds.data).map_err(|e| VcsError::DataMigrationFailed {
reason: format!("deserialize data set: {e}"),
})
}
other => Err(VcsError::TypeMismatch {
expected: "DataSet".into(),
got: other.type_name().into(),
}),
}
}