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