use gix_hash::ObjectId;use gix_object::{tree, tree::EntryMode}; /// A way to recognize and associate different [`Change`] instances.////// These are unique only within one diff operation.pub type ChangeId = u32; /// Identifies a relationship between this instance and another one.#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Ord, Eq, Hash)]pub enum Relation { /// This is a parent with the given ID, which will always have at least one child /// assuming that empty directories are not allowed in valid trees. /// It's also always a tree which is the start of a recursive deletion or addition. /// /// The change with this relation is always emitted first. Parent(ChangeId), /// This is a direct or indirect child, tree or not tree, of the parent with the given ID. ChildOfParent(ChangeId),} /// Represents any possible change in order to turn one tree into another.#[derive(Debug, Clone, PartialOrd, PartialEq, Ord, Eq, Hash)]pub enum Change { /// An entry was added, like the addition of a file or directory. Addition { /// The mode of the added entry. entry_mode: tree::EntryMode, /// The object id of the added entry. oid: ObjectId, /// Possibly associate this change with another for hierarchical rename tracking. relation: Option<Relation>, }, /// An entry was deleted, like the deletion of a file or directory. Deletion { /// The mode of the deleted entry. entry_mode: tree::EntryMode, /// The object id of the deleted entry. oid: ObjectId, /// Possibly associate this change with another for hierarchical rename tracking. relation: Option<Relation>, }, /// An entry was modified, e.g. changing the contents of a file adjusts its object id and turning /// a file into a symbolic link adjusts its mode. Modification { /// The mode of the entry before the modification. previous_entry_mode: tree::EntryMode, /// The object id of the entry before the modification. previous_oid: ObjectId, /// The mode of the entry after the modification. entry_mode: tree::EntryMode, /// The object id after the modification. oid: ObjectId, },} impl Change { /// Return the current object id. pub fn oid(&self) -> &gix_hash::oid { match self { Change::Addition { oid, .. } | Change::Deletion { oid, .. } | Change::Modification { oid, .. } => oid, } } /// Return the current tree entry mode. pub fn entry_mode(&self) -> EntryMode { match self { Change::Addition { entry_mode, .. } | Change::Deletion { entry_mode, .. } | Change::Modification { entry_mode, .. } => *entry_mode, } } /// Return the current object id and tree entry mode of a change. pub fn oid_and_entry_mode(&self) -> (&gix_hash::oid, EntryMode) { match self { Change::Addition { oid, entry_mode, relation: _, } | Change::Deletion { oid, entry_mode, relation: _, } | Change::Modification { oid, entry_mode, .. } => (oid, *entry_mode), } }} /// What to do after a [Change] was [recorded](super::Visit::visit()).#[derive(Default, Clone, Copy, PartialOrd, PartialEq, Ord, Eq, Hash)]pub enum Action { /// Continue the traversal of changes. #[default] Continue, /// Stop the traversal of changes, making this the last call to [visit(…)](super::Visit::visit()). Cancel,} impl Action { /// Returns true if this action means to stop the traversal. pub fn cancelled(&self) -> bool { matches!(self, Action::Cancel) }} #[cfg(feature = "blob")]mod change_impls { use gix_hash::oid; use gix_object::tree::EntryMode; use crate::{ rewrites::tracker::ChangeKind, tree::visit::{Change, Relation}, }; impl crate::rewrites::tracker::Change for crate::tree::visit::Change { fn id(&self) -> &oid { match self { Change::Addition { oid, .. } | Change::Deletion { oid, .. } | Change::Modification { oid, .. } => oid, } } fn relation(&self) -> Option<Relation> { match self { Change::Addition { relation, .. } | Change::Deletion { relation, .. } => *relation, Change::Modification { .. } => None, } } fn kind(&self) -> ChangeKind { match self { Change::Addition { .. } => ChangeKind::Addition, Change::Deletion { .. } => ChangeKind::Deletion, Change::Modification { .. } => ChangeKind::Modification, } } fn entry_mode(&self) -> EntryMode { match self { Change::Addition { entry_mode, .. } | Change::Deletion { entry_mode, .. } | Change::Modification { entry_mode, .. } => *entry_mode, } } fn id_and_entry_mode(&self) -> (&oid, EntryMode) { match self { Change::Addition { entry_mode, oid, .. } | Change::Deletion { entry_mode, oid, .. } | Change::Modification { entry_mode, oid, .. } => (oid, *entry_mode), } } }} #[cfg(test)]mod tests { use super::*; #[test] fn size_of_change() { let actual = std::mem::size_of::<Change>(); assert!( actual <= 48, "{actual} <= 48: this type shouldn't grow without us knowing" ); }}
use gix_hash::ObjectId;
use gix_object::{tree, tree::EntryMode};
/// A way to recognize and associate different [`Change`] instances.
///
/// These are unique only within one diff operation.
pub type ChangeId = u32;
/// Identifies a relationship between this instance and another one.
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Ord, Eq, Hash)]
pub enum Relation {
/// This is a parent with the given ID, which will always have at least one child
/// assuming that empty directories are not allowed in valid trees.
/// It's also always a tree which is the start of a recursive deletion or addition.
///
/// The change with this relation is always emitted first.
Parent(ChangeId),
/// This is a direct or indirect child, tree or not tree, of the parent with the given ID.
ChildOfParent(ChangeId),
}
/// Represents any possible change in order to turn one tree into another.
#[derive(Debug, Clone, PartialOrd, PartialEq, Ord, Eq, Hash)]
pub enum Change {
/// An entry was added, like the addition of a file or directory.
Addition {
/// The mode of the added entry.
entry_mode: tree::EntryMode,
/// The object id of the added entry.
oid: ObjectId,
/// Possibly associate this change with another for hierarchical rename tracking.
relation: Option<Relation>,
},
/// An entry was deleted, like the deletion of a file or directory.
Deletion {
/// The mode of the deleted entry.
entry_mode: tree::EntryMode,
/// The object id of the deleted entry.
oid: ObjectId,
/// Possibly associate this change with another for hierarchical rename tracking.
relation: Option<Relation>,
},
/// An entry was modified, e.g. changing the contents of a file adjusts its object id and turning
/// a file into a symbolic link adjusts its mode.
Modification {
/// The mode of the entry before the modification.
previous_entry_mode: tree::EntryMode,
/// The object id of the entry before the modification.
previous_oid: ObjectId,
/// The mode of the entry after the modification.
entry_mode: tree::EntryMode,
/// The object id after the modification.
oid: ObjectId,
},
}
impl Change {
/// Return the current object id.
pub fn oid(&self) -> &gix_hash::oid {
match self {
Change::Addition { oid, .. } | Change::Deletion { oid, .. } | Change::Modification { oid, .. } => oid,
}
}
/// Return the current tree entry mode.
pub fn entry_mode(&self) -> EntryMode {
match self {
Change::Addition { entry_mode, .. }
| Change::Deletion { entry_mode, .. }
| Change::Modification { entry_mode, .. } => *entry_mode,
}
}
/// Return the current object id and tree entry mode of a change.
pub fn oid_and_entry_mode(&self) -> (&gix_hash::oid, EntryMode) {
match self {
Change::Addition {
oid,
entry_mode,
relation: _,
}
| Change::Deletion {
oid,
entry_mode,
relation: _,
}
| Change::Modification { oid, entry_mode, .. } => (oid, *entry_mode),
}
}
}
/// What to do after a [Change] was [recorded](super::Visit::visit()).
#[derive(Default, Clone, Copy, PartialOrd, PartialEq, Ord, Eq, Hash)]
pub enum Action {
/// Continue the traversal of changes.
#[default]
Continue,
/// Stop the traversal of changes, making this the last call to [visit(…)](super::Visit::visit()).
Cancel,
}
impl Action {
/// Returns true if this action means to stop the traversal.
pub fn cancelled(&self) -> bool {
matches!(self, Action::Cancel)
}
}
#[cfg(feature = "blob")]
mod change_impls {
use gix_hash::oid;
use gix_object::tree::EntryMode;
use crate::{
rewrites::tracker::ChangeKind,
tree::visit::{Change, Relation},
};
impl crate::rewrites::tracker::Change for crate::tree::visit::Change {
fn id(&self) -> &oid {
match self {
Change::Addition { oid, .. } | Change::Deletion { oid, .. } | Change::Modification { oid, .. } => oid,
}
}
fn relation(&self) -> Option<Relation> {
match self {
Change::Addition { relation, .. } | Change::Deletion { relation, .. } => *relation,
Change::Modification { .. } => None,
}
}
fn kind(&self) -> ChangeKind {
match self {
Change::Addition { .. } => ChangeKind::Addition,
Change::Deletion { .. } => ChangeKind::Deletion,
Change::Modification { .. } => ChangeKind::Modification,
}
}
fn entry_mode(&self) -> EntryMode {
match self {
Change::Addition { entry_mode, .. }
| Change::Deletion { entry_mode, .. }
| Change::Modification { entry_mode, .. } => *entry_mode,
}
}
fn id_and_entry_mode(&self) -> (&oid, EntryMode) {
match self {
Change::Addition { entry_mode, oid, .. }
| Change::Deletion { entry_mode, oid, .. }
| Change::Modification { entry_mode, oid, .. } => (oid, *entry_mode),
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn size_of_change() {
let actual = std::mem::size_of::<Change>();
assert!(
actual <= 48,
"{actual} <= 48: this type shouldn't grow without us knowing"
);
}
}