agtrace_types/domain/
project.rs

1use serde::{Deserialize, Serialize};
2use std::fmt;
3use std::path::{Path, PathBuf};
4
5/// Project identifier computed from canonical project root path via SHA256
6#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
7#[serde(transparent)]
8pub struct ProjectHash(String);
9
10impl ProjectHash {
11    /// Create a new ProjectHash from a string (typically hex digest)
12    pub fn new(hash: impl Into<String>) -> Self {
13        Self(hash.into())
14    }
15
16    /// Get the hash as a string slice
17    pub fn as_str(&self) -> &str {
18        &self.0
19    }
20}
21
22impl fmt::Display for ProjectHash {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        write!(f, "{}", self.0)
25    }
26}
27
28impl From<String> for ProjectHash {
29    fn from(s: String) -> Self {
30        Self(s)
31    }
32}
33
34impl From<&str> for ProjectHash {
35    fn from(s: &str) -> Self {
36        Self(s.to_string())
37    }
38}
39
40impl AsRef<str> for ProjectHash {
41    fn as_ref(&self) -> &str {
42        &self.0
43    }
44}
45
46/// Canonical project root path
47#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
48#[serde(transparent)]
49pub struct ProjectRoot(PathBuf);
50
51impl ProjectRoot {
52    /// Create a new ProjectRoot from a path
53    pub fn new(path: impl Into<PathBuf>) -> Self {
54        Self(path.into())
55    }
56
57    /// Get the root path as a Path reference
58    pub fn as_path(&self) -> &Path {
59        &self.0
60    }
61
62    /// Get the path as a string (lossy UTF-8 conversion)
63    pub fn to_string_lossy(&self) -> String {
64        self.0.to_string_lossy().to_string()
65    }
66}
67
68impl fmt::Display for ProjectRoot {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        write!(f, "{}", self.0.display())
71    }
72}
73
74impl From<PathBuf> for ProjectRoot {
75    fn from(path: PathBuf) -> Self {
76        Self(path)
77    }
78}
79
80impl From<&Path> for ProjectRoot {
81    fn from(path: &Path) -> Self {
82        Self(path.to_path_buf())
83    }
84}
85
86impl AsRef<Path> for ProjectRoot {
87    fn as_ref(&self) -> &Path {
88        &self.0
89    }
90}
91
92/// Project scope for indexing and filtering sessions
93#[derive(Debug, Clone, PartialEq, Eq)]
94pub enum ProjectScope {
95    /// Scan all projects without filtering
96    All,
97    /// Scan specific project by hash
98    Specific(ProjectHash),
99}
100
101impl ProjectScope {
102    /// Get optional project hash for filtering
103    pub fn hash(&self) -> Option<&ProjectHash> {
104        match self {
105            ProjectScope::All => None,
106            ProjectScope::Specific(hash) => Some(hash),
107        }
108    }
109}