1#![cfg_attr(test, allow(clippy::expect_used, clippy::unwrap_used))]
2
3use std::path::Path;
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19pub struct SessionId(String);
20
21impl SessionId {
22 pub fn new() -> Self {
24 Self(ulid::Ulid::new().to_string())
25 }
26
27 pub fn from_string(s: String) -> Self {
31 Self(s)
32 }
33
34 pub fn as_str(&self) -> &str {
35 &self.0
36 }
37
38 pub fn into_string(self) -> String {
39 self.0
40 }
41}
42
43impl Default for SessionId {
44 fn default() -> Self {
45 Self::new()
46 }
47}
48
49impl std::fmt::Display for SessionId {
50 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51 write!(f, "{}", self.0)
52 }
53}
54
55pub fn encode_cwd(cwd: &Path) -> String {
62 let s = cwd.to_string_lossy();
63 let stripped = s.trim_start_matches(['/', '\\']);
64 let replaced: String = stripped
65 .chars()
66 .map(|c| match c {
67 '/' | '\\' | ':' => '-',
68 other => other,
69 })
70 .collect();
71 format!("--{replaced}--")
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77 use std::path::PathBuf;
78
79 #[test]
80 fn encode_cwd_matches_pi_examples() {
81 assert_eq!(
82 encode_cwd(&PathBuf::from("/Users/wade/proj/capo")),
83 "--Users-wade-proj-capo--"
84 );
85 }
86
87 #[test]
88 fn encode_cwd_handles_windows_drive() {
89 assert_eq!(
92 encode_cwd(&PathBuf::from("C:\\Users\\wade\\proj")),
93 "--C--Users-wade-proj--"
94 );
95 }
96
97 #[test]
98 fn encode_cwd_handles_root() {
99 assert_eq!(encode_cwd(&PathBuf::from("/")), "----");
100 }
101
102 #[test]
103 fn session_id_new_is_26_chars_and_unique() {
104 let a = SessionId::new();
105 let b = SessionId::new();
106 assert_eq!(a.as_str().len(), 26);
107 assert_eq!(b.as_str().len(), 26);
108 assert_ne!(a, b);
109 }
110}