1use crate::{TargetPredicate, VersionConstraint};
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
8pub struct Dependency {
9 pub name: String,
10 pub constraint: VersionConstraint,
11 pub kind: DependencyKind,
12 #[serde(default)]
14 pub features_enabled: Vec<String>,
15 #[serde(default = "default_true")]
17 pub default_features: bool,
18 #[serde(default)]
20 pub target_predicate: Option<TargetPredicate>,
21 #[serde(default)]
25 pub source_override: Option<crate::PackageSource>,
26}
27
28fn default_true() -> bool {
29 true
30}
31
32#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
34#[serde(rename_all = "kebab-case")]
35pub enum DependencyKind {
36 Direct,
38 Build,
41 Dev,
44 Optional,
47 Peer,
52 Replaces,
55}
56
57impl DependencyKind {
58 #[must_use]
60 pub const fn as_str(self) -> &'static str {
61 match self {
62 Self::Direct => "direct",
63 Self::Build => "build",
64 Self::Dev => "dev",
65 Self::Optional => "optional",
66 Self::Peer => "peer",
67 Self::Replaces => "replaces",
68 }
69 }
70
71 #[must_use]
75 pub const fn is_runtime(self) -> bool {
76 matches!(
77 self,
78 Self::Direct | Self::Optional | Self::Peer | Self::Replaces
79 )
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86 use crate::{ConstraintSpec, Version};
87
88 #[test]
89 fn kind_string_tokens_are_stable() {
90 for k in [
91 DependencyKind::Direct,
92 DependencyKind::Build,
93 DependencyKind::Dev,
94 DependencyKind::Optional,
95 DependencyKind::Peer,
96 DependencyKind::Replaces,
97 ] {
98 assert!(!k.as_str().is_empty());
99 }
100 }
101
102 #[test]
103 fn is_runtime_classifies_correctly() {
104 assert!(DependencyKind::Direct.is_runtime());
105 assert!(DependencyKind::Optional.is_runtime());
106 assert!(DependencyKind::Peer.is_runtime());
107 assert!(DependencyKind::Replaces.is_runtime());
108 assert!(!DependencyKind::Build.is_runtime());
109 assert!(!DependencyKind::Dev.is_runtime());
110 }
111
112 #[test]
113 fn round_trip_through_serde() {
114 let d = Dependency {
115 name: "serde".into(),
116 constraint: VersionConstraint::from_spec(ConstraintSpec::Caret(Version::new(1, 0, 0))),
117 kind: DependencyKind::Direct,
118 features_enabled: vec!["derive".into()],
119 default_features: true,
120 target_predicate: None,
121 source_override: None,
122 };
123 let j = serde_json::to_string(&d).unwrap();
124 let parsed: Dependency = serde_json::from_str(&j).unwrap();
125 assert_eq!(d, parsed);
126 }
127}