use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
use crate::BundleRelativePath;
use crate::transaction::SnapshotId;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ConflictPolicy {
Fail,
Replace,
Merge,
Rename,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ChangeKind {
Add,
Identical,
Merge,
Replace,
Rename,
Skip,
Conflict,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PlannedWrite {
pub path: BundleRelativePath,
pub content: Vec<u8>,
pub mode: u32,
}
impl PlannedWrite {
#[must_use]
pub const fn new(path: BundleRelativePath, content: Vec<u8>) -> Self {
Self {
path,
content,
mode: 0o600,
}
}
#[must_use]
pub const fn with_mode(mut self, mode: u32) -> Self {
self.mode = mode & 0o777;
self
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct WritePlan {
writes: BTreeMap<BundleRelativePath, PlannedWrite>,
}
impl WritePlan {
pub fn insert(&mut self, write: PlannedWrite) {
let _previous = self.writes.insert(write.path.clone(), write);
}
#[must_use]
pub fn get(&self, path: &BundleRelativePath) -> Option<&PlannedWrite> {
self.writes.get(path)
}
#[must_use]
pub fn writes(&self) -> impl ExactSizeIterator<Item = &PlannedWrite> {
self.writes.values()
}
#[must_use]
pub fn len(&self) -> usize {
self.writes.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.writes.is_empty()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TransactionOptions {
root: PathBuf,
state_root: PathBuf,
conflict_policy: ConflictPolicy,
dry_run: bool,
}
impl TransactionOptions {
#[must_use]
pub fn new(root: &Path, state_root: &Path) -> Self {
Self {
root: root.to_path_buf(),
state_root: state_root.to_path_buf(),
conflict_policy: ConflictPolicy::Fail,
dry_run: false,
}
}
#[must_use]
pub const fn with_conflict_policy(mut self, conflict_policy: ConflictPolicy) -> Self {
self.conflict_policy = conflict_policy;
self
}
#[must_use]
pub const fn dry_run(mut self) -> Self {
self.dry_run = true;
self
}
#[must_use]
pub fn root(&self) -> &Path {
&self.root
}
#[must_use]
pub fn state_root(&self) -> &Path {
&self.state_root
}
#[must_use]
pub const fn conflict_policy(&self) -> ConflictPolicy {
self.conflict_policy
}
#[must_use]
pub const fn is_dry_run(&self) -> bool {
self.dry_run
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TransactionResult {
pub snapshot_id: SnapshotId,
pub dry_run: bool,
pub writes: usize,
}