use std::num::NonZeroUsize;
use haematite::db::{ObservedChange, ReadOnlyDatabase};
use serde::Serialize;
use super::super::{Captured, Catalogue, Failure, ForkProvenance};
use super::{compare, movement, values};
use crate::serve::protocol::ReviewPage;
#[derive(Serialize)]
pub(in crate::serve) struct Partial {
changes: u64,
conflicts: u64,
dangling: Option<()>,
}
pub(in crate::serve) struct Page {
pub(in crate::serve) selection: Captured,
pub(in crate::serve) from: ForkProvenance,
pub(in crate::serve) parent: Captured,
pub(in crate::serve) partial: Partial,
pub(in crate::serve) base_moved: u64,
pub(in crate::serve) next_after: Option<String>,
}
pub(in crate::serve) fn page(
reader: &ReadOnlyDatabase,
catalogue: &Catalogue,
request: &ReviewPage,
limit: NonZeroUsize,
) -> Result<Page, Failure> {
let result = compare::page(reader, catalogue, request, limit)?;
let base_moved = movement(&result.from, &result.parent)?;
let partial = count(&result.source, &result.target)?;
Ok(Page {
selection: result.selection,
from: result.from,
parent: result.parent,
partial,
base_moved,
next_after: result.next_after,
})
}
fn count(source: &[ObservedChange], target: &[ObservedChange]) -> Result<Partial, Failure> {
let mut result = Partial {
changes: 0,
conflicts: 0,
dangling: None,
};
for change in source {
let (ancestor, here) = compare::sides(change);
if ancestor == here || !values::is_owner(change.key())? {
continue;
}
result.changes = increment(result.changes)?;
let there = compare::target_value(change, target)?;
if there != ancestor && there != here {
result.conflicts = increment(result.conflicts)?;
}
}
Ok(result)
}
fn increment(value: u64) -> Result<u64, Failure> {
value
.checked_add(1)
.ok_or_else(|| Failure::new("count_overflow", "review total exceeds u64"))
}