summaryrefslogtreecommitdiff
path: root/crates/vcs_data/src/data/local/align.rs
blob: 715c785abfcbfa425e9d70a9a41a55cf87274e18 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use std::{
    collections::{HashMap, HashSet},
    path::PathBuf,
};

use data_struct::dada_sort::quick_sort_with_cmp;

use crate::data::local::file_status::AnalyzeResult;

pub type AlignTasksName = String;
pub type AlignPathBuf = PathBuf;
pub type AlignLostPathBuf = PathBuf;
pub type AlignCreatedPathBuf = PathBuf;

pub struct AlignTasks {
    pub created: Vec<(AlignTasksName, AlignPathBuf)>,
    pub lost: Vec<(AlignTasksName, AlignPathBuf)>,
    pub moved: Vec<(AlignTasksName, (AlignLostPathBuf, AlignCreatedPathBuf))>,
    pub erased: Vec<(AlignTasksName, AlignPathBuf)>,
}

impl AlignTasks {
    pub fn clone_from_analyze_result(result: &AnalyzeResult) -> Self {
        AlignTasks {
            created: path_hash_set_sort_helper(result.created.clone(), "created"),
            lost: path_hash_set_sort_helper(result.lost.clone(), "lost"),
            moved: path_hash_map_sort_helper(result.moved.clone(), "moved"),
            erased: path_hash_set_sort_helper(result.erased.clone(), "erased"),
        }
    }

    pub fn from_analyze_result(result: AnalyzeResult) -> Self {
        AlignTasks {
            created: path_hash_set_sort_helper(result.created, "created"),
            lost: path_hash_set_sort_helper(result.lost, "lost"),
            moved: path_hash_map_sort_helper(result.moved, "moved"),
            erased: path_hash_set_sort_helper(result.erased, "erased"),
        }
    }
}

fn path_hash_set_sort_helper(
    hash_set: HashSet<PathBuf>,
    prefix: impl Into<String>,
) -> Vec<(String, PathBuf)> {
    let prefix_str = prefix.into();
    let mut vec: Vec<(String, PathBuf)> = hash_set
        .into_iter()
        .map(|path| {
            let hash = sha1_hash::calc_sha1_string(path.to_string_lossy());
            let hash_prefix: String = hash.chars().take(8).collect();
            let name = format!("{}:{}", prefix_str, hash_prefix);
            (name, path)
        })
        .collect();

    quick_sort_with_cmp(&mut vec, false, |a, b| {
        // Compare by path depth first
        let a_depth = a.1.components().count();
        let b_depth = b.1.components().count();

        if a_depth != b_depth {
            return if a_depth < b_depth { -1 } else { 1 };
        }

        // If same depth, compare lexicographically
        match a.1.cmp(&b.1) {
            std::cmp::Ordering::Less => -1,
            std::cmp::Ordering::Equal => 0,
            std::cmp::Ordering::Greater => 1,
        }
    });

    vec
}

fn path_hash_map_sort_helper(
    hash_map: HashMap<String, (PathBuf, PathBuf)>,
    prefix: impl Into<String>,
) -> Vec<(String, (PathBuf, PathBuf))> {
    let prefix_str = prefix.into();
    let mut vec: Vec<(String, (PathBuf, PathBuf))> = hash_map
        .into_values()
        .map(|(path1, path2)| {
            let hash = sha1_hash::calc_sha1_string(path1.to_string_lossy());
            let hash_prefix: String = hash.chars().take(8).collect();
            let name = format!("{}:{}", prefix_str, hash_prefix);
            (name, (path1, path2))
        })
        .collect();

    quick_sort_with_cmp(&mut vec, false, |a, b| {
        // Compare by first PathBuf's path depth first
        let a_depth = a.1.0.components().count();
        let b_depth = b.1.0.components().count();

        if a_depth != b_depth {
            return if a_depth < b_depth { -1 } else { 1 };
        }

        // If same depth, compare lexicographically by first PathBuf
        match a.1.0.cmp(&b.1.0) {
            std::cmp::Ordering::Less => -1,
            std::cmp::Ordering::Equal => 0,
            std::cmp::Ordering::Greater => 1,
        }
    });

    vec
}