heddle_object_model/
refs.rs1use std::collections::HashMap;
5
6use crate::object::StateId;
7
8const THREADS_PREFIX: &str = "refs/threads/";
9const MARKERS_PREFIX: &str = "refs/markers/";
10
11#[derive(Clone, Debug)]
12pub struct PackedRefsModel {
13 threads: HashMap<String, StateId>,
14 markers: HashMap<String, StateId>,
15}
16
17impl PackedRefsModel {
18 pub fn new() -> Self {
19 Self {
20 threads: HashMap::new(),
21 markers: HashMap::new(),
22 }
23 }
24
25 pub fn parse(contents: &str) -> Self {
26 let mut packed = Self::new();
27 for line in contents.lines() {
28 let line = line.trim();
29 if line.is_empty() || line.starts_with('#') {
30 continue;
31 }
32 let mut parts = line.splitn(2, ' ');
33 let (Some(id_str), Some(refname)) = (parts.next(), parts.next()) else {
34 continue;
35 };
36 let id = match StateId::parse(id_str) {
37 Ok(id) => id,
38 Err(_) => continue,
39 };
40 if let Some(name) = refname.strip_prefix(THREADS_PREFIX) {
41 packed.threads.insert(name.to_string(), id);
42 } else if let Some(name) = refname.strip_prefix(MARKERS_PREFIX) {
43 packed.markers.insert(name.to_string(), id);
44 }
45 }
46 packed
47 }
48
49 pub fn to_text(&self) -> String {
50 let mut lines: Vec<String> =
51 vec!["# packed-refs with: peeled fully-peeled sorted".to_string()];
52 for (name, id) in &self.threads {
53 lines.push(format!(
54 "{} {}{}",
55 id.to_string_full(),
56 THREADS_PREFIX,
57 name
58 ));
59 }
60 for (name, id) in &self.markers {
61 lines.push(format!(
62 "{} {}{}",
63 id.to_string_full(),
64 MARKERS_PREFIX,
65 name
66 ));
67 }
68 lines.sort();
69 lines.join("\n") + "\n"
70 }
71
72 pub fn get_thread(&self, name: &str) -> Option<StateId> {
73 self.threads.get(name).copied()
74 }
75 pub fn get_marker(&self, name: &str) -> Option<StateId> {
76 self.markers.get(name).copied()
77 }
78 pub fn set_thread(&mut self, name: &str, id: StateId) {
79 self.threads.insert(name.to_string(), id);
80 }
81 pub fn set_marker(&mut self, name: &str, id: StateId) {
82 self.markers.insert(name.to_string(), id);
83 }
84 pub fn remove_track(&mut self, name: &str) {
85 self.threads.remove(name);
86 }
87 pub fn remove_marker(&mut self, name: &str) {
88 self.markers.remove(name);
89 }
90 pub fn list_threads(&self) -> Vec<String> {
91 self.threads.keys().cloned().collect()
92 }
93 pub fn list_markers(&self) -> Vec<String> {
94 self.markers.keys().cloned().collect()
95 }
96 pub fn is_empty(&self) -> bool {
97 self.threads.is_empty() && self.markers.is_empty()
98 }
99}
100
101impl Default for PackedRefsModel {
102 fn default() -> Self {
103 Self::new()
104 }
105}