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!(self, Self::Direct | Self::Optional | Self::Peer | Self::Replaces)
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 use crate::{ConstraintSpec, Version};
84
85 #[test]
86 fn kind_string_tokens_are_stable() {
87 for k in [
88 DependencyKind::Direct,
89 DependencyKind::Build,
90 DependencyKind::Dev,
91 DependencyKind::Optional,
92 DependencyKind::Peer,
93 DependencyKind::Replaces,
94 ] {
95 assert!(!k.as_str().is_empty());
96 }
97 }
98
99 #[test]
100 fn is_runtime_classifies_correctly() {
101 assert!(DependencyKind::Direct.is_runtime());
102 assert!(DependencyKind::Optional.is_runtime());
103 assert!(DependencyKind::Peer.is_runtime());
104 assert!(DependencyKind::Replaces.is_runtime());
105 assert!(!DependencyKind::Build.is_runtime());
106 assert!(!DependencyKind::Dev.is_runtime());
107 }
108
109 #[test]
110 fn round_trip_through_serde() {
111 let d = Dependency {
112 name: "serde".into(),
113 constraint: VersionConstraint::from_spec(ConstraintSpec::Caret(Version::new(1, 0, 0))),
114 kind: DependencyKind::Direct,
115 features_enabled: vec!["derive".into()],
116 default_features: true,
117 target_predicate: None,
118 source_override: None,
119 };
120 let j = serde_json::to_string(&d).unwrap();
121 let parsed: Dependency = serde_json::from_str(&j).unwrap();
122 assert_eq!(d, parsed);
123 }
124}