1use std::fmt::{Display, Formatter, Write};
2
3use sha1::{Digest, Sha1};
4
5#[derive(Clone)]
7pub struct Path {
8 segments: Vec<String>,
9}
10
11impl Path {
12 pub fn name(&self) -> &str {
14 self.segments
15 .iter()
16 .last()
17 .expect("Path expects at least one element")
18 }
19
20 pub fn id(&self) -> String {
22 let name = self.name();
23 let mut hasher = Sha1::default();
24 for segment in &self.segments {
25 hasher.update(segment);
26 }
27 let hash: String = hasher
28 .finalize()
29 .as_slice()
30 .iter()
31 .map(|by| format!("{by:x}"))
32 .collect();
33 format!("{name}-{hash}")
34 }
35
36 pub fn push(&mut self, identifier: impl Into<String>) {
38 self.segments.push(identifier.into())
39 }
40}
41
42impl From<String> for Path {
43 fn from(segment: String) -> Self {
44 Path {
45 segments: vec![segment],
46 }
47 }
48}
49
50impl From<Vec<String>> for Path {
51 fn from(segments: Vec<String>) -> Self {
52 Path { segments }
53 }
54}
55
56impl Display for Path {
57 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
58 if let Some(first) = self.segments.first() {
59 f.write_str(first)?;
60 }
61 for segment in self.segments.iter().skip(1) {
62 f.write_char('/')?;
63 f.write_str(segment)?;
64 }
65 Ok(())
66 }
67}