Skip to main content

heddle_object_model/
refs.rs

1// SPDX-License-Identifier: Apache-2.0
2//! In-memory packed refs model and text format.
3
4use 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}