use std::path::PathBuf;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub enum BackendKind {
Git,
Jj,
}
impl BackendKind {
pub fn as_str(self) -> &'static str {
match self {
BackendKind::Git => "git",
BackendKind::Jj => "jj",
}
}
}
pub use vcs_diff::ChangeKind;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct FileChange {
pub path: String,
pub old_path: Option<String>,
pub kind: ChangeKind,
}
pub use vcs_diff::DiffStat;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct WorktreeInfo {
pub path: PathBuf,
pub branch: Option<String>,
pub commit: Option<String>,
pub is_bare: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub enum OperationState {
Clear,
Merge,
Rebase,
Conflict,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct RepoSnapshot {
pub head: Option<String>,
pub branch: Option<String>,
pub upstream: Option<String>,
pub ahead: Option<usize>,
pub behind: Option<usize>,
pub dirty: bool,
pub change_count: usize,
pub conflicted: bool,
pub operation: OperationState,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", serde(tag = "outcome", content = "files"))]
#[non_exhaustive]
pub enum MergeProbe {
Clean,
Conflicts(Vec<String>),
}
impl MergeProbe {
pub fn is_clean(&self) -> bool {
matches!(self, MergeProbe::Clean)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub enum CreateOutcome {
Plain,
CowCloned,
}
#[cfg(all(test, feature = "serde"))]
mod serde_tests {
use super::*;
#[test]
fn snapshot_and_file_change_serialize_to_clean_json() {
let snap = RepoSnapshot {
head: Some("abc".into()),
branch: Some("main".into()),
upstream: None,
ahead: Some(1),
behind: Some(0),
dirty: true,
change_count: 2,
conflicted: false,
operation: OperationState::Merge,
};
let v = serde_json::to_value(&snap).unwrap();
assert_eq!(v["branch"], "main");
assert_eq!(v["operation"], "Merge"); assert_eq!(v["change_count"], 2);
let fc = FileChange {
path: "a.rs".into(),
old_path: None,
kind: ChangeKind::Added, };
let v = serde_json::to_value(fc).unwrap();
assert_eq!(v["path"], "a.rs");
assert_eq!(v["kind"], "Added");
}
#[test]
fn merge_probe_serializes_to_a_type_stable_object() {
let clean = serde_json::to_value(MergeProbe::Clean).unwrap();
assert_eq!(clean["outcome"], "Clean");
assert!(clean.get("files").is_none(), "{clean}");
let conflicts =
serde_json::to_value(MergeProbe::Conflicts(vec!["a.rs".into(), "b.rs".into()]))
.unwrap();
assert_eq!(conflicts["outcome"], "Conflicts");
assert_eq!(conflicts["files"][0], "a.rs");
assert_eq!(conflicts["files"][1], "b.rs");
}
}