1use std::{collections::HashMap, str::FromStr};
2
3use crate::{Error, WithError as _};
4
5#[derive(Debug, Clone)]
6pub struct Reference {
7 pub hash: String,
8 pub name: String,
9 pub peeled: Option<String>,
10 pub symref_target: Option<String>,
11}
12
13impl Reference {
14 #[must_use]
15 pub fn target(&self) -> &str {
16 if let Some(ref peeled) = self.peeled {
17 peeled
18 } else {
19 &self.hash
20 }
21 }
22}
23
24impl FromStr for Reference {
25 type Err = Error;
26
27 fn from_str(s: &str) -> Result<Self, Self::Err> {
28 let mut parts = s.trim_end().split(' ');
29
30 let hash = parts.next().with_err_msg("hash not found")?;
31 let name = parts.next().with_err_msg("name not found")?;
32
33 let mut res = Self {
34 hash: hash.to_owned(),
35 name: name.to_owned(),
36 peeled: None,
37 symref_target: None,
38 };
39
40 let mut args = parts
41 .filter_map(|arg| arg.split_once(':'))
42 .collect::<HashMap<&str, &str>>();
43
44 if let Some(peeled) = args.remove("peeled") {
45 res.peeled.replace(peeled.to_owned());
46 }
47
48 if let Some(value) = args.remove("symref-target") {
49 res.symref_target.replace(value.to_owned());
50 }
51
52 assert!(args.is_empty(), "unparsed args: {args:?}");
53
54 Ok(res)
55 }
56}