use super::{AnnotationBuilder, Annotations};
use crate::provenance::Exactness;
use std::collections::BTreeSet;
#[derive(Debug)]
pub struct SparseAnnotationTransaction<'base> {
base: &'base Annotations,
changes: Annotations,
selected: BTreeSet<String>,
}
#[derive(Debug)]
pub struct PreparedAnnotationDelta {
changes: Annotations,
selected: BTreeSet<String>,
}
impl Annotations {
pub fn sparse_transaction(&self) -> SparseAnnotationTransaction<'_> {
SparseAnnotationTransaction {
base: self,
changes: Annotations::default(),
selected: BTreeSet::new(),
}
}
pub fn prepare_overlay(&self, changes: Annotations) -> PreparedAnnotationDelta {
let mut transaction = self.sparse_transaction();
for id in changes.provenance.keys().chain(changes.exactness.keys()) {
transaction.selected.insert(id.to_owned());
}
transaction.changes = changes;
transaction.prepare()
}
}
impl<'base> SparseAnnotationTransaction<'base> {
pub fn base(&self) -> &'base Annotations {
self.base
}
pub fn annotations(&self) -> &Annotations {
&self.changes
}
fn edit<T>(&mut self, id: &str, apply: impl FnOnce(&mut Annotations) -> T) -> T {
if self.selected.insert(id.to_owned()) {
copy_identity(self.base, &mut self.changes, id);
}
apply(&mut self.changes)
}
pub(crate) fn select(&mut self, id: &str) {
self.edit(id, |_| ());
}
pub(crate) fn selected(&self, id: &str) -> bool {
self.selected.contains(id)
}
pub fn field_exactness(
&mut self,
id: &str,
field: &str,
exactness: Exactness,
) -> Result<(), super::AnnotationFieldError> {
self.edit(id, |annotations| {
let mut builder = AnnotationBuilder::resume(std::mem::take(annotations));
let result = builder.field_exactness(id, field, exactness).map(|_| ());
*annotations = builder.build();
result
})
}
pub fn note(&mut self, id: &str, stream: &super::StreamHandle, offset: u64, tag: Option<&str>) {
self.edit(id, |annotations| {
let mut builder = AnnotationBuilder::resume(std::mem::take(annotations));
builder.note(id, stream, offset, tag);
*annotations = builder.build();
});
}
pub fn remove_entity(&mut self, id: &str) {
self.edit(id, |annotations| {
annotations.provenance.remove(id);
annotations.exactness.remove(id);
});
}
pub fn exactness(&mut self, id: &str, exactness: Exactness) {
self.edit(id, |annotations| {
let mut builder = AnnotationBuilder::resume(std::mem::take(annotations));
builder.exactness(id, exactness);
*annotations = builder.build();
});
}
pub fn prepare(self) -> PreparedAnnotationDelta {
PreparedAnnotationDelta {
changes: self.changes,
selected: self.selected,
}
}
}
impl PreparedAnnotationDelta {
pub fn apply(mut self, annotations: &mut Annotations) {
for id in self.selected {
if let Some((key, value)) = self.changes.provenance.remove_entry(&id) {
annotations.provenance.insert(key, value);
} else {
annotations.provenance.remove(&id);
}
if let Some((key, value)) = self.changes.exactness.remove_entry(&id) {
annotations.exactness.insert(key, value);
} else {
annotations.exactness.remove(&id);
}
}
}
}
fn copy_identity(base: &Annotations, changes: &mut Annotations, id: &str) {
if let Some(source) = base.provenance.get(id) {
changes.provenance.insert(id.to_owned(), source.clone());
}
if let Some(note) = base.exactness.get(id) {
changes.exactness.insert(id.to_owned(), note.clone());
}
}
#[cfg(test)]
mod tests;