differential_engine/model.rs
1//! Data model for the canonical diff view.
2//!
3//! Paths are raw bytes throughout the engine; they become UTF-8 strings only at
4//! JSON serialisation time, where a non-UTF-8 path is a hard error naming the
5//! file (deferred support, never silent).
6
7/// One line's content, without its newline. `Vec<Vec<u8>>` splits preserve the
8/// trailing empty element that encodes "ends with a newline".
9pub type Line = Vec<u8>;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum Disposition {
13 Added,
14 Deleted,
15 Modified,
16}
17
18impl Disposition {
19 pub fn letter(self) -> u8 {
20 match self {
21 Disposition::Added => b'A',
22 Disposition::Deleted => b'D',
23 Disposition::Modified => b'M',
24 }
25 }
26}
27
28/// One changed file in the canonical (`--no-renames`) view. Exists independently
29/// of hunks: empty-file adds/deletes, mode-only changes and binary files carry
30/// zero hunks but are still real changes.
31#[derive(Debug, Clone)]
32pub struct FileChange {
33 pub path: Vec<u8>,
34 pub disposition: Disposition,
35 /// "100644" etc. New-side mode; `None` for deletions.
36 pub new_mode: Option<String>,
37 /// Old-side mode when it differs, and for deletions.
38 pub old_mode: Option<String>,
39 pub binary: bool,
40 /// `Some((old, new))` commit ids for gitlink (mode 160000) changes.
41 pub submodule: Option<(Option<String>, Option<String>)>,
42 /// Full blob oids from the `--raw --full-index` record. `new_oid` is used to
43 /// stage BINARY files only — for text files the tree is always built from
44 /// applied hunks, or the tree assertion would be tautological.
45 pub old_oid: Option<String>,
46 pub new_oid: Option<String>,
47 /// Indices into the canonical hunk vector, in file order.
48 pub hunks: Vec<usize>,
49 // Annotations merged in from the rename-detected view:
50 pub rename_similarity: Option<u8>,
51 /// A side of a rename: where the content came from.
52 pub rename_from: Option<Vec<u8>>,
53 /// D side of a rename: where the content went.
54 pub rename_to: Option<Vec<u8>>,
55 /// Generated-file hint (never affects enumeration).
56 pub generated: Option<GeneratedBy>,
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub enum GeneratedBy {
61 Builtin,
62 Attr,
63 Config,
64}
65
66/// One canonical hunk from `git diff -U0 --no-renames`.
67#[derive(Debug, Clone)]
68pub struct Hunk {
69 /// Index into the canonical file vector.
70 pub file: usize,
71 pub old_start: u32,
72 pub old_count: u32,
73 pub new_start: u32,
74 pub new_count: u32,
75 /// Removed lines, without prefix or newline.
76 pub removed: Vec<Line>,
77 /// Added lines, without prefix or newline.
78 pub added: Vec<Line>,
79 /// `\ No newline at end of file` on the old side.
80 pub nonl_old: bool,
81 /// `\ No newline at end of file` on the new side.
82 pub nonl_new: bool,
83}
84
85/// The canonical enumeration: every file, every hunk, no exclusions.
86#[derive(Debug, Clone, Default)]
87pub struct DiffView {
88 pub files: Vec<FileChange>,
89 /// Canonical order: file order in the diff, hunk order within each file.
90 /// A hunk's id `hN` is its index here.
91 pub hunks: Vec<Hunk>,
92}
93
94impl DiffView {
95 pub fn file_of(&self, hunk: &Hunk) -> &FileChange {
96 &self.files[hunk.file]
97 }
98}