1use std::any::Any;
2use std::collections::HashMap;
3use tower_lsp_server::ls_types::Range;
4
5pub use deps_core::parser::DependencySource;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct ParsedDependency {
36 pub name: deps_core::PackageName,
37 pub name_range: Range,
38 pub version_req: Option<deps_core::VersionReq>,
39 pub version_range: Option<Range>,
40 pub features: Vec<String>,
41 pub features_range: Option<Range>,
42 pub source: DependencySource,
43 pub section: DependencySection,
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub enum DependencySection {
64 Dependencies,
66 DevDependencies,
68 BuildDependencies,
70 WorkspaceDependencies,
72}
73
74#[derive(Debug, Clone)]
101pub struct CargoVersion {
102 pub num: deps_core::ConcreteVersion,
103 pub yanked: bool,
104 pub features: HashMap<String, Vec<String>>,
105 pub published_at: Option<deps_core::PublishTime>,
111}
112
113#[derive(Debug, Clone)]
134pub struct CrateInfo {
135 pub name: deps_core::PackageName,
136 pub description: Option<String>,
137 pub repository: Option<String>,
138 pub documentation: Option<String>,
139 pub max_version: deps_core::ConcreteVersion,
140}
141
142impl deps_core::Dependency for ParsedDependency {
145 fn name(&self) -> &deps_core::PackageName {
146 &self.name
147 }
148
149 fn name_range(&self) -> Range {
150 self.name_range
151 }
152
153 fn version_requirement(&self) -> Option<&deps_core::VersionReq> {
154 self.version_req.as_ref()
155 }
156
157 fn version_range(&self) -> Option<Range> {
158 self.version_range
159 }
160
161 fn source(&self) -> deps_core::parser::DependencySource {
162 self.source.clone()
163 }
164
165 fn features(&self) -> &[String] {
166 &self.features
167 }
168
169 fn features_range(&self) -> Option<Range> {
170 self.features_range
171 }
172
173 fn as_any(&self) -> &dyn Any {
174 self
175 }
176}
177
178impl deps_core::Version for CargoVersion {
179 fn version_string(&self) -> &deps_core::ConcreteVersion {
180 &self.num
181 }
182
183 fn removal_status(&self) -> deps_core::RemovalStatus {
184 deps_core::RemovalStatus::from_yanked(self.yanked)
185 }
186
187 fn is_prerelease(&self) -> bool {
193 semver::Version::parse(self.num.as_str()).is_ok_and(|v| !v.pre.is_empty())
194 }
195
196 fn features(&self) -> Vec<String> {
197 self.features.keys().cloned().collect()
198 }
199
200 fn published_at(&self) -> Option<deps_core::PublishTime> {
201 self.published_at
202 }
203
204 fn as_any(&self) -> &dyn Any {
205 self
206 }
207}
208
209impl deps_core::Metadata for CrateInfo {
210 fn name(&self) -> &deps_core::PackageName {
211 &self.name
212 }
213
214 fn description(&self) -> Option<&str> {
215 self.description.as_deref()
216 }
217
218 fn repository(&self) -> Option<&str> {
219 self.repository.as_deref()
220 }
221
222 fn documentation(&self) -> Option<&str> {
223 self.documentation.as_deref()
224 }
225
226 fn latest_version(&self) -> &deps_core::ConcreteVersion {
227 &self.max_version
228 }
229
230 fn as_any(&self) -> &dyn Any {
231 self
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use super::*;
238
239 use std::assert_matches;
240
241 #[test]
242 fn test_dependency_source_variants() {
243 assert_matches!(DependencySource::Registry, DependencySource::Registry);
244 assert_matches!(
245 DependencySource::Git {
246 url: "u".into(),
247 rev: None
248 },
249 DependencySource::Git { .. }
250 );
251 assert_matches!(
252 DependencySource::Path { path: "p".into() },
253 DependencySource::Path { .. }
254 );
255 assert_matches!(DependencySource::Workspace, DependencySource::Workspace);
256 }
257
258 #[test]
259 fn test_dependency_section_variants() {
260 let deps = DependencySection::Dependencies;
261 let dev_deps = DependencySection::DevDependencies;
262 let build_deps = DependencySection::BuildDependencies;
263 let workspace_deps = DependencySection::WorkspaceDependencies;
264
265 assert_matches!(deps, DependencySection::Dependencies);
266 assert_matches!(dev_deps, DependencySection::DevDependencies);
267 assert_matches!(build_deps, DependencySection::BuildDependencies);
268 assert_matches!(workspace_deps, DependencySection::WorkspaceDependencies);
269 }
270
271 #[test]
272 fn test_cargo_version_creation() {
273 let version = CargoVersion {
274 num: "1.0.0".into(),
275 yanked: false,
276 features: HashMap::new(),
277 published_at: None,
278 };
279
280 assert_eq!(version.num, "1.0.0");
281 assert!(!version.yanked);
282 assert!(version.features.is_empty());
283 assert!(version.published_at.is_none());
284 }
285
286 #[test]
287 fn test_cargo_version_is_prerelease() {
288 use deps_core::Version;
289
290 let stable = CargoVersion {
291 num: "1.0.0".into(),
292 yanked: false,
293 features: HashMap::new(),
294 published_at: None,
295 };
296 let prerelease = CargoVersion {
297 num: "1.0.0-alpha.1".into(),
298 yanked: false,
299 features: HashMap::new(),
300 published_at: None,
301 };
302
303 assert!(!stable.is_prerelease());
304 assert!(stable.is_stable());
305 assert!(prerelease.is_prerelease());
306 assert!(!prerelease.is_stable());
307 }
308}