1use crate::error::Result;
2use tower_lsp_server::ls_types::{Range, Uri};
3
4pub trait ManifestParser: Send + Sync {
14 type Dependency: DependencyInfo + Clone + Send + Sync;
16
17 type ParseResult: ParseResultInfo<Dependency = Self::Dependency> + Send;
19
20 fn parse(&self, content: &str, doc_uri: &Uri) -> Result<Self::ParseResult>;
28}
29
30pub trait DependencyInfo {
39 fn name(&self) -> &str;
41
42 fn name_range(&self) -> Range;
44
45 fn version_requirement(&self) -> Option<&str>;
47
48 fn version_range(&self) -> Option<Range>;
50
51 fn source(&self) -> DependencySource;
53
54 fn features(&self) -> &[String] {
56 &[]
57 }
58}
59
60pub trait ParseResultInfo {
67 type Dependency: DependencyInfo;
68
69 fn dependencies(&self) -> &[Self::Dependency];
71
72 fn workspace_root(&self) -> Option<&std::path::Path>;
74}
75
76#[derive(Debug, Clone, PartialEq)]
78pub enum DependencySource {
79 Registry,
81 Git { url: String, rev: Option<String> },
83 Path { path: String },
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn test_dependency_source_registry() {
93 let source = DependencySource::Registry;
94 assert_eq!(source, DependencySource::Registry);
95 }
96
97 #[test]
98 fn test_dependency_source_git() {
99 let source = DependencySource::Git {
100 url: "https://github.com/user/repo".into(),
101 rev: Some("main".into()),
102 };
103
104 match source {
105 DependencySource::Git { url, rev } => {
106 assert_eq!(url, "https://github.com/user/repo");
107 assert_eq!(rev, Some("main".into()));
108 }
109 _ => panic!("Expected Git source"),
110 }
111 }
112
113 #[test]
114 fn test_dependency_source_git_no_rev() {
115 let source = DependencySource::Git {
116 url: "https://github.com/user/repo".into(),
117 rev: None,
118 };
119
120 match source {
121 DependencySource::Git { url, rev } => {
122 assert_eq!(url, "https://github.com/user/repo");
123 assert!(rev.is_none());
124 }
125 _ => panic!("Expected Git source"),
126 }
127 }
128
129 #[test]
130 fn test_dependency_source_path() {
131 let source = DependencySource::Path {
132 path: "../local-crate".into(),
133 };
134
135 match source {
136 DependencySource::Path { path } => {
137 assert_eq!(path, "../local-crate");
138 }
139 _ => panic!("Expected Path source"),
140 }
141 }
142
143 #[test]
144 fn test_dependency_source_clone() {
145 let source1 = DependencySource::Git {
146 url: "https://example.com/repo".into(),
147 rev: Some("v1.0".into()),
148 };
149 let source2 = source1.clone();
150
151 assert_eq!(source1, source2);
152 }
153
154 #[test]
155 fn test_dependency_source_equality() {
156 let reg1 = DependencySource::Registry;
157 let reg2 = DependencySource::Registry;
158 assert_eq!(reg1, reg2);
159
160 let git1 = DependencySource::Git {
161 url: "https://example.com".into(),
162 rev: None,
163 };
164 let git2 = DependencySource::Git {
165 url: "https://example.com".into(),
166 rev: None,
167 };
168 assert_eq!(git1, git2);
169
170 let git3 = DependencySource::Git {
171 url: "https://different.com".into(),
172 rev: None,
173 };
174 assert_ne!(git1, git3);
175 }
176
177 #[test]
178 fn test_dependency_source_debug() {
179 let source = DependencySource::Registry;
180 let debug = format!("{:?}", source);
181 assert_eq!(debug, "Registry");
182
183 let git = DependencySource::Git {
184 url: "https://example.com".into(),
185 rev: Some("main".into()),
186 };
187 let git_debug = format!("{:?}", git);
188 assert!(git_debug.contains("https://example.com"));
189 assert!(git_debug.contains("main"));
190 }
191}