1use cargo_platform::Platform;
2use semver::VersionReq;
3use serde::ser;
4use serde::Serialize;
5use std::borrow::Cow;
6use std::fmt;
7use std::path::PathBuf;
8use std::sync::Arc;
9use tracing::trace;
10
11use crate::core::compiler::{CompileKind, CompileTarget};
12use crate::core::{CliUnstable, Feature, Features, PackageId, SourceId, Summary};
13use crate::util::errors::CargoResult;
14use crate::util::interning::InternedString;
15use crate::util::OptVersionReq;
16
17#[derive(PartialEq, Eq, Hash, Clone, Debug)]
20pub struct Dependency {
21 inner: Arc<Inner>,
22}
23
24#[derive(PartialEq, Eq, Hash, Clone, Debug)]
26struct Inner {
27 name: InternedString,
28 source_id: SourceId,
29 registry_id: Option<SourceId>,
36 req: OptVersionReq,
37 specified_req: bool,
38 kind: DepKind,
39 only_match_name: bool,
40 explicit_name_in_toml: Option<InternedString>,
41
42 optional: bool,
43 public: bool,
44 default_features: bool,
45 features: Vec<InternedString>,
46 artifact: Option<Artifact>,
48
49 platform: Option<Platform>,
52}
53
54#[derive(Serialize)]
55pub struct SerializedDependency {
56 name: InternedString,
57 source: SourceId,
58 req: String,
59 kind: DepKind,
60 rename: Option<InternedString>,
61
62 optional: bool,
63 uses_default_features: bool,
64 features: Vec<InternedString>,
65 #[serde(skip_serializing_if = "Option::is_none")]
66 artifact: Option<Artifact>,
67 target: Option<Platform>,
68 registry: Option<String>,
71
72 #[serde(skip_serializing_if = "Option::is_none")]
74 path: Option<PathBuf>,
75
76 #[serde(skip_serializing_if = "Option::is_none")]
80 public: Option<bool>,
81}
82
83#[derive(PartialEq, Eq, Hash, Ord, PartialOrd, Clone, Debug, Copy)]
84pub enum DepKind {
85 Normal,
86 Development,
87 Build,
88}
89
90impl DepKind {
91 pub fn kind_table(&self) -> &'static str {
92 match self {
93 DepKind::Normal => "dependencies",
94 DepKind::Development => "dev-dependencies",
95 DepKind::Build => "build-dependencies",
96 }
97 }
98}
99
100impl ser::Serialize for DepKind {
101 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
102 where
103 S: ser::Serializer,
104 {
105 match *self {
106 DepKind::Normal => None,
107 DepKind::Development => Some("dev"),
108 DepKind::Build => Some("build"),
109 }
110 .serialize(s)
111 }
112}
113
114impl Dependency {
115 pub fn parse(
117 name: impl Into<InternedString>,
118 version: Option<&str>,
119 source_id: SourceId,
120 ) -> CargoResult<Dependency> {
121 let name = name.into();
122 let (specified_req, version_req) = match version {
123 Some(v) => match VersionReq::parse(v) {
124 Ok(req) => (true, OptVersionReq::Req(req)),
125 Err(err) => {
126 return Err(anyhow::Error::new(err).context(format!(
127 "failed to parse the version requirement `{}` for dependency `{}`",
128 v, name,
129 )))
130 }
131 },
132 None => (false, OptVersionReq::Any),
133 };
134
135 let mut ret = Dependency::new_override(name, source_id);
136 {
137 let ptr = Arc::make_mut(&mut ret.inner);
138 ptr.only_match_name = false;
139 ptr.req = version_req;
140 ptr.specified_req = specified_req;
141 }
142 Ok(ret)
143 }
144
145 pub fn new_override(name: InternedString, source_id: SourceId) -> Dependency {
146 assert!(!name.is_empty());
147 Dependency {
148 inner: Arc::new(Inner {
149 name,
150 source_id,
151 registry_id: None,
152 req: OptVersionReq::Any,
153 kind: DepKind::Normal,
154 only_match_name: true,
155 optional: false,
156 public: false,
157 features: Vec::new(),
158 default_features: true,
159 specified_req: false,
160 platform: None,
161 explicit_name_in_toml: None,
162 artifact: None,
163 }),
164 }
165 }
166
167 pub fn serialized(
168 &self,
169 unstable_flags: &CliUnstable,
170 features: &Features,
171 ) -> SerializedDependency {
172 SerializedDependency {
173 name: self.package_name(),
174 source: self.source_id(),
175 req: self.version_req().to_string(),
176 kind: self.kind(),
177 optional: self.is_optional(),
178 uses_default_features: self.uses_default_features(),
179 features: self.features().to_vec(),
180 target: self.inner.platform.clone(),
181 rename: self.explicit_name_in_toml(),
182 registry: self.registry_id().as_ref().map(|sid| sid.url().to_string()),
183 path: self.source_id().local_path(),
184 artifact: self.inner.artifact.clone(),
185 public: if unstable_flags.public_dependency
186 || features.is_enabled(Feature::public_dependency())
187 {
188 Some(self.inner.public)
189 } else {
190 None
191 },
192 }
193 }
194
195 pub fn version_req(&self) -> &OptVersionReq {
196 &self.inner.req
197 }
198
199 pub fn name_in_toml(&self) -> InternedString {
220 self.explicit_name_in_toml().unwrap_or(self.inner.name)
221 }
222
223 pub fn package_name(&self) -> InternedString {
242 self.inner.name
243 }
244
245 pub fn source_id(&self) -> SourceId {
246 self.inner.source_id
247 }
248
249 pub fn registry_id(&self) -> Option<SourceId> {
250 self.inner.registry_id
251 }
252
253 pub fn set_registry_id(&mut self, registry_id: SourceId) -> &mut Dependency {
254 Arc::make_mut(&mut self.inner).registry_id = Some(registry_id);
255 self
256 }
257
258 pub fn kind(&self) -> DepKind {
259 self.inner.kind
260 }
261
262 pub fn is_public(&self) -> bool {
263 self.inner.public
264 }
265
266 pub fn set_public(&mut self, public: bool) -> &mut Dependency {
268 if public {
269 assert_eq!(self.kind(), DepKind::Normal);
271 }
272 Arc::make_mut(&mut self.inner).public = public;
273 self
274 }
275
276 pub fn specified_req(&self) -> bool {
277 self.inner.specified_req
278 }
279
280 pub fn platform(&self) -> Option<&Platform> {
283 self.inner.platform.as_ref()
284 }
285
286 pub fn explicit_name_in_toml(&self) -> Option<InternedString> {
291 self.inner.explicit_name_in_toml
292 }
293
294 pub fn set_kind(&mut self, kind: DepKind) -> &mut Dependency {
295 if self.is_public() {
296 assert_eq!(kind, DepKind::Normal);
298 }
299 Arc::make_mut(&mut self.inner).kind = kind;
300 self
301 }
302
303 pub fn set_features(
305 &mut self,
306 features: impl IntoIterator<Item = impl Into<InternedString>>,
307 ) -> &mut Dependency {
308 Arc::make_mut(&mut self.inner).features = features.into_iter().map(|s| s.into()).collect();
309 self
310 }
311
312 pub fn set_default_features(&mut self, default_features: bool) -> &mut Dependency {
314 Arc::make_mut(&mut self.inner).default_features = default_features;
315 self
316 }
317
318 pub fn set_optional(&mut self, optional: bool) -> &mut Dependency {
320 Arc::make_mut(&mut self.inner).optional = optional;
321 self
322 }
323
324 pub fn set_source_id(&mut self, id: SourceId) -> &mut Dependency {
326 Arc::make_mut(&mut self.inner).source_id = id;
327 self
328 }
329
330 pub fn set_version_req(&mut self, req: OptVersionReq) -> &mut Dependency {
332 Arc::make_mut(&mut self.inner).req = req;
333 self
334 }
335
336 pub fn set_platform(&mut self, platform: Option<Platform>) -> &mut Dependency {
337 Arc::make_mut(&mut self.inner).platform = platform;
338 self
339 }
340
341 pub fn set_explicit_name_in_toml(
342 &mut self,
343 name: impl Into<InternedString>,
344 ) -> &mut Dependency {
345 Arc::make_mut(&mut self.inner).explicit_name_in_toml = Some(name.into());
346 self
347 }
348
349 pub fn lock_to(&mut self, id: PackageId) -> &mut Dependency {
351 assert_eq!(self.inner.source_id, id.source_id());
352 trace!(
353 "locking dep from `{}` with `{}` at {} to {}",
354 self.package_name(),
355 self.version_req(),
356 self.source_id(),
357 id
358 );
359 let me = Arc::make_mut(&mut self.inner);
360 me.req.lock_to(id.version());
361
362 me.source_id = me.source_id.with_precise_from(id.source_id());
366 self
367 }
368
369 pub fn lock_version(&mut self, version: &semver::Version) -> &mut Dependency {
374 let me = Arc::make_mut(&mut self.inner);
375 me.req.lock_to(version);
376 self
377 }
378
379 pub fn is_locked(&self) -> bool {
382 self.inner.req.is_locked()
383 }
384
385 pub fn is_transitive(&self) -> bool {
387 match self.inner.kind {
388 DepKind::Normal | DepKind::Build => true,
389 DepKind::Development => false,
390 }
391 }
392
393 pub fn is_build(&self) -> bool {
394 matches!(self.inner.kind, DepKind::Build)
395 }
396
397 pub fn is_optional(&self) -> bool {
398 self.inner.optional
399 }
400
401 pub fn uses_default_features(&self) -> bool {
403 self.inner.default_features
404 }
405 pub fn features(&self) -> &[InternedString] {
407 &self.inner.features
408 }
409
410 pub fn matches(&self, sum: &Summary) -> bool {
412 self.matches_id(sum.package_id())
413 }
414
415 pub fn matches_prerelease(&self, sum: &Summary) -> bool {
416 let id = sum.package_id();
417 self.inner.name == id.name()
418 && (self.inner.only_match_name
419 || (self.inner.req.matches_prerelease(id.version())
420 && self.inner.source_id == id.source_id()))
421 }
422
423 pub fn matches_ignoring_source(&self, id: PackageId) -> bool {
425 self.package_name() == id.name() && self.version_req().matches(id.version())
426 }
427
428 pub fn matches_id(&self, id: PackageId) -> bool {
430 self.inner.name == id.name()
431 && (self.inner.only_match_name
432 || (self.inner.req.matches(id.version()) && self.inner.source_id == id.source_id()))
433 }
434
435 pub fn map_source(mut self, to_replace: SourceId, replace_with: SourceId) -> Dependency {
436 if self.source_id() == to_replace {
437 self.set_source_id(replace_with);
438 }
439 self
440 }
441
442 pub(crate) fn set_artifact(&mut self, artifact: Artifact) {
443 Arc::make_mut(&mut self.inner).artifact = Some(artifact);
444 }
445
446 pub(crate) fn artifact(&self) -> Option<&Artifact> {
447 self.inner.artifact.as_ref()
448 }
449
450 pub(crate) fn maybe_lib(&self) -> bool {
454 self.artifact().map(|a| a.is_lib).unwrap_or(true)
455 }
456}
457
458#[derive(PartialEq, Eq, Hash, Clone, Debug)]
465pub struct Artifact {
466 inner: Arc<Vec<ArtifactKind>>,
467 is_lib: bool,
468 target: Option<ArtifactTarget>,
469}
470
471#[derive(Serialize)]
472pub struct SerializedArtifact<'a> {
473 kinds: &'a [ArtifactKind],
474 lib: bool,
475 target: Option<&'a str>,
476}
477
478impl ser::Serialize for Artifact {
479 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
480 where
481 S: ser::Serializer,
482 {
483 SerializedArtifact {
484 kinds: self.kinds(),
485 lib: self.is_lib,
486 target: self.target.as_ref().map(ArtifactTarget::as_str),
487 }
488 .serialize(s)
489 }
490}
491
492impl Artifact {
493 pub(crate) fn parse(
494 artifacts: &[impl AsRef<str>],
495 is_lib: bool,
496 target: Option<&str>,
497 ) -> CargoResult<Self> {
498 let kinds = ArtifactKind::validate(
499 artifacts
500 .iter()
501 .map(|s| ArtifactKind::parse(s.as_ref()))
502 .collect::<Result<Vec<_>, _>>()?,
503 )?;
504 Ok(Artifact {
505 inner: Arc::new(kinds),
506 is_lib,
507 target: target.map(ArtifactTarget::parse).transpose()?,
508 })
509 }
510
511 pub(crate) fn kinds(&self) -> &[ArtifactKind] {
512 &self.inner
513 }
514
515 pub(crate) fn is_lib(&self) -> bool {
516 self.is_lib
517 }
518
519 pub(crate) fn target(&self) -> Option<ArtifactTarget> {
520 self.target
521 }
522}
523
524#[derive(PartialEq, Eq, Hash, Copy, Clone, Ord, PartialOrd, Debug)]
525pub enum ArtifactTarget {
526 BuildDependencyAssumeTarget,
530 Force(CompileTarget),
534}
535
536impl ArtifactTarget {
537 pub fn parse(target: &str) -> CargoResult<ArtifactTarget> {
538 Ok(match target {
539 "target" => ArtifactTarget::BuildDependencyAssumeTarget,
540 name => ArtifactTarget::Force(CompileTarget::new(name)?),
541 })
542 }
543
544 pub fn as_str(&self) -> &str {
545 match self {
546 ArtifactTarget::BuildDependencyAssumeTarget => "target",
547 ArtifactTarget::Force(target) => target.rustc_target().as_str(),
548 }
549 }
550
551 pub fn to_compile_kind(&self) -> Option<CompileKind> {
552 self.to_compile_target().map(CompileKind::Target)
553 }
554
555 pub fn to_compile_target(&self) -> Option<CompileTarget> {
556 match self {
557 ArtifactTarget::BuildDependencyAssumeTarget => None,
558 ArtifactTarget::Force(target) => Some(*target),
559 }
560 }
561
562 pub(crate) fn to_resolved_compile_kind(
563 &self,
564 root_unit_compile_kind: CompileKind,
565 ) -> CompileKind {
566 match self {
567 ArtifactTarget::Force(target) => CompileKind::Target(*target),
568 ArtifactTarget::BuildDependencyAssumeTarget => root_unit_compile_kind,
569 }
570 }
571
572 pub(crate) fn to_resolved_compile_target(
573 &self,
574 root_unit_compile_kind: CompileKind,
575 ) -> Option<CompileTarget> {
576 match self.to_resolved_compile_kind(root_unit_compile_kind) {
577 CompileKind::Host => None,
578 CompileKind::Target(target) => Some(target),
579 }
580 }
581}
582
583#[derive(PartialEq, Eq, Hash, Copy, Clone, Ord, PartialOrd, Debug)]
584pub enum ArtifactKind {
585 AllBinaries,
587 SelectedBinary(InternedString),
589 Cdylib,
590 Staticlib,
591}
592
593impl ser::Serialize for ArtifactKind {
594 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
595 where
596 S: ser::Serializer,
597 {
598 self.as_str().serialize(s)
599 }
600}
601
602impl fmt::Display for ArtifactKind {
603 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
604 f.write_str(&self.as_str())
605 }
606}
607
608impl ArtifactKind {
609 pub fn crate_type(&self) -> &'static str {
613 match self {
614 ArtifactKind::AllBinaries | ArtifactKind::SelectedBinary(_) => "bin",
615 ArtifactKind::Cdylib => "cdylib",
616 ArtifactKind::Staticlib => "staticlib",
617 }
618 }
619
620 pub fn as_str(&self) -> Cow<'static, str> {
621 match *self {
622 ArtifactKind::SelectedBinary(name) => format!("bin:{}", name.as_str()).into(),
623 _ => self.crate_type().into(),
624 }
625 }
626
627 pub fn parse(kind: &str) -> CargoResult<Self> {
628 Ok(match kind {
629 "bin" => ArtifactKind::AllBinaries,
630 "cdylib" => ArtifactKind::Cdylib,
631 "staticlib" => ArtifactKind::Staticlib,
632 _ => {
633 return kind
634 .strip_prefix("bin:")
635 .map(|bin_name| ArtifactKind::SelectedBinary(InternedString::new(bin_name)))
636 .ok_or_else(|| anyhow::anyhow!("'{}' is not a valid artifact specifier", kind))
637 }
638 })
639 }
640
641 fn validate(kinds: Vec<ArtifactKind>) -> CargoResult<Vec<ArtifactKind>> {
642 if kinds.iter().any(|k| matches!(k, ArtifactKind::AllBinaries))
643 && kinds
644 .iter()
645 .any(|k| matches!(k, ArtifactKind::SelectedBinary(_)))
646 {
647 anyhow::bail!("Cannot specify both 'bin' and 'bin:<name>' binary artifacts, as 'bin' selects all available binaries.");
648 }
649 let mut kinds_without_dupes = kinds.clone();
650 kinds_without_dupes.sort();
651 kinds_without_dupes.dedup();
652 let num_dupes = kinds.len() - kinds_without_dupes.len();
653 if num_dupes != 0 {
654 anyhow::bail!(
655 "Found {} duplicate binary artifact{}",
656 num_dupes,
657 (num_dupes > 1).then(|| "s").unwrap_or("")
658 );
659 }
660 Ok(kinds)
661 }
662}