weavatrix-worktree 0.2.1

Bounded, crash-recoverable multi-file worktree edits for source refactoring
Documentation
use std::{collections::BTreeMap, sync::Arc};

use crate::{
    WorktreeOperation, WorktreePlan,
    error::WorktreeError,
    filesystem::PresentEvidence,
    hash::Sha256Hash,
    report::{OperationChange, OperationKind},
};

use super::invalid_internal;

pub(super) fn changes(
    plan: &WorktreePlan,
    sources: &BTreeMap<String, (Arc<str>, PresentEvidence)>,
    outputs: &BTreeMap<String, (Sha256Hash, u64, usize)>,
) -> Result<Vec<OperationChange>, WorktreeError> {
    plan.operations
        .iter()
        .enumerate()
        .map(|(index, operation)| match operation {
            WorktreeOperation::Modify(file) => {
                let (_, before) = source(sources, &file.path, index)?;
                let (hash, bytes, edits) = output(outputs, &file.path, index)?;
                Ok(OperationChange::new(
                    OperationKind::Modify,
                    Some(file.path.clone()),
                    None,
                    Some(before.sha256),
                    Some(hash),
                    before.bytes,
                    bytes,
                    edits,
                ))
            }
            WorktreeOperation::Create(file) => {
                let (hash, bytes, edits) = output(outputs, &file.path, index)?;
                Ok(OperationChange::new(
                    OperationKind::Create,
                    None,
                    Some(file.path.clone()),
                    None,
                    Some(hash),
                    0,
                    bytes,
                    edits,
                ))
            }
            WorktreeOperation::Delete(file) => {
                let (_, before) = source(sources, &file.path, index)?;
                Ok(OperationChange::new(
                    OperationKind::Delete,
                    Some(file.path.clone()),
                    None,
                    Some(before.sha256),
                    None,
                    before.bytes,
                    0,
                    0,
                ))
            }
            WorktreeOperation::Rename(file) => {
                let (_, before) = source(sources, &file.from, index)?;
                let (hash, bytes, edits) = output(outputs, &file.to, index)?;
                Ok(OperationChange::new(
                    OperationKind::Rename,
                    Some(file.from.clone()),
                    Some(file.to.clone()),
                    Some(before.sha256),
                    Some(hash),
                    before.bytes,
                    bytes,
                    edits,
                ))
            }
        })
        .collect()
}

fn source<'a>(
    values: &'a BTreeMap<String, (Arc<str>, PresentEvidence)>,
    path: &str,
    index: usize,
) -> Result<&'a (Arc<str>, PresentEvidence), WorktreeError> {
    values
        .get(path)
        .ok_or_else(|| invalid_internal("logical operation has no projected source", index))
}

fn output(
    values: &BTreeMap<String, (Sha256Hash, u64, usize)>,
    path: &str,
    index: usize,
) -> Result<(Sha256Hash, u64, usize), WorktreeError> {
    values
        .get(path)
        .copied()
        .ok_or_else(|| invalid_internal("logical operation has no projected output", index))
}