1use crate::constraint::{Constraint, Op};
8use crate::version::parse_stability;
9use serde_json::Value;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum LinkType {
13 Require,
14 DevRequire,
15 Conflict,
16 Provide,
17 Replace,
18}
19
20impl LinkType {
21 pub fn description(self) -> &'static str {
23 match self {
24 LinkType::Require => "requires",
25 LinkType::DevRequire => "requires (for development)",
26 LinkType::Conflict => "conflicts",
27 LinkType::Provide => "provides",
28 LinkType::Replace => "replaces",
29 }
30 }
31
32 pub fn json_key(self) -> &'static str {
33 match self {
34 LinkType::Require => "require",
35 LinkType::DevRequire => "require-dev",
36 LinkType::Conflict => "conflict",
37 LinkType::Provide => "provide",
38 LinkType::Replace => "replace",
39 }
40 }
41}
42
43#[derive(Debug, Clone, PartialEq, Eq)]
49pub struct Link {
50 pub key: Option<String>,
51 pub source: String,
52 pub target: String,
53 pub constraint: Constraint,
54 pub pretty_constraint: String,
55 pub kind: LinkType,
56}
57
58impl Link {
59 pub fn new(
61 source: &str,
62 target: &str,
63 constraint: Constraint,
64 pretty_constraint: &str,
65 kind: LinkType,
66 ) -> Link {
67 Link {
68 key: Some(target.to_owned()),
69 source: source.to_owned(),
70 target: target.to_owned(),
71 constraint,
72 pretty_constraint: pretty_constraint.to_owned(),
73 kind,
74 }
75 }
76}
77
78#[derive(Debug, Clone, Default, PartialEq, Eq)]
82pub struct Links(pub Vec<Link>);
83
84impl Links {
85 pub fn insert(&mut self, link: Link) {
86 if link.key.is_some() {
87 if let Some(existing) = self.0.iter_mut().find(|l| l.key == link.key) {
88 *existing = link;
89 return;
90 }
91 }
92 self.0.push(link);
93 }
94 pub fn remove(&mut self, key: &str) {
97 self.0.retain(|l| l.key.as_deref() != Some(key));
98 }
99
100 pub fn get(&self, key: &str) -> Option<&Link> {
101 self.0.iter().find(|l| l.key.as_deref() == Some(key))
102 }
103 pub fn has_numeric_keys(&self) -> bool {
105 self.0.iter().any(|l| l.key.is_none())
106 }
107 pub fn iter(&self) -> impl Iterator<Item = &Link> {
108 self.0.iter()
109 }
110 pub fn len(&self) -> usize {
111 self.0.len()
112 }
113 pub fn is_empty(&self) -> bool {
114 self.0.is_empty()
115 }
116}
117
118#[derive(Debug, Clone, PartialEq, Eq)]
119pub struct SourceRef {
120 pub kind: String,
121 pub url: String,
122 pub reference: Option<String>,
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
127pub enum Origin {
128 Root,
129 Platform,
130 Locked,
131 Repository(usize),
133 Detached,
135 Result,
138}
139
140#[derive(Debug, Clone)]
141pub struct Package {
142 pub name: String,
144 pub pretty_name: String,
145 pub version: String,
147 pub pretty_version: String,
148 pub package_type: String,
149 pub stability: &'static str,
150 pub is_default_branch: bool,
151 pub source: Option<SourceRef>,
152 pub dist: Option<SourceRef>,
153 pub requires: Links,
154 pub dev_requires: Links,
155 pub conflicts: Links,
156 pub provides: Links,
157 pub replaces: Links,
158 pub raw: Value,
160 pub origin: Origin,
161 pub alias_of: Option<usize>,
163 pub root_package_alias: bool,
165 pub has_self_version_requires: bool,
167}
168
169impl Package {
170 pub fn new(pretty_name: &str, version: &str, pretty_version: &str, origin: Origin) -> Package {
171 Package {
172 name: pretty_name.to_lowercase(),
173 pretty_name: pretty_name.to_owned(),
174 version: version.to_owned(),
175 pretty_version: pretty_version.to_owned(),
176 package_type: "library".to_owned(),
177 stability: parse_stability(version),
178 is_default_branch: false,
179 source: None,
180 dist: None,
181 requires: Links::default(),
182 dev_requires: Links::default(),
183 conflicts: Links::default(),
184 provides: Links::default(),
185 replaces: Links::default(),
186 raw: Value::Null,
187 origin,
188 alias_of: None,
189 root_package_alias: false,
190 has_self_version_requires: false,
191 }
192 }
193
194 pub fn is_alias(&self) -> bool {
195 self.alias_of.is_some()
196 }
197
198 pub fn is_dev(&self) -> bool {
199 self.stability == "dev"
200 }
201
202 pub fn names(&self, provides: bool) -> Vec<String> {
204 let mut names: Vec<String> = vec![self.name.clone()];
205 if provides {
206 for l in self.provides.iter() {
207 if !names.contains(&l.target) {
208 names.push(l.target.clone());
209 }
210 }
211 }
212 for l in self.replaces.iter() {
213 if !names.contains(&l.target) {
214 names.push(l.target.clone());
215 }
216 }
217 names
218 }
219
220 pub fn unique_name(&self) -> String {
221 format!("{}-{}", self.name, self.version)
222 }
223
224 pub fn pretty_string(&self) -> String {
225 format!("{} {}", self.pretty_name, self.pretty_version)
226 }
227
228 pub fn source_reference(&self) -> Option<&str> {
229 self.source.as_ref().and_then(|s| s.reference.as_deref())
230 }
231
232 pub fn dist_reference(&self) -> Option<&str> {
233 self.dist.as_ref().and_then(|s| s.reference.as_deref())
234 }
235
236 pub fn links(&self, kind: LinkType) -> &Links {
237 match kind {
238 LinkType::Require => &self.requires,
239 LinkType::DevRequire => &self.dev_requires,
240 LinkType::Conflict => &self.conflicts,
241 LinkType::Provide => &self.provides,
242 LinkType::Replace => &self.replaces,
243 }
244 }
245
246 pub fn alias(&self, alias_of: usize, version: &str, pretty_version: &str) -> Package {
250 let mut a = self.clone();
251 a.version = version.to_owned();
252 a.pretty_version = pretty_version.to_owned();
253 a.stability = parse_stability(version);
254 a.alias_of = Some(alias_of);
255 a.root_package_alias = false;
256 a.has_self_version_requires = false;
257 let pretty = if pretty_version == crate::version::DEFAULT_BRANCH_ALIAS {
258 self.pretty_version.clone()
259 } else {
260 pretty_version.to_owned()
261 };
262 let rewrite = |links: &Links, kind: LinkType, has_self: &mut bool| -> Links {
263 let mut out = Links::default();
264 if matches!(
265 kind,
266 LinkType::Conflict | LinkType::Provide | LinkType::Replace
267 ) {
268 let mut extra: Vec<Link> = Vec::new();
271 for l in links.iter() {
272 out.0.push(l.clone());
273 if l.pretty_constraint == "self.version" {
274 extra.push(Link {
275 key: None,
276 source: l.source.clone(),
277 target: l.target.clone(),
278 constraint: Constraint::new(Op::Eq, version),
279 pretty_constraint: pretty.clone(),
280 kind,
281 });
282 }
283 }
284 out.0.extend(extra);
285 } else {
286 for l in links.iter() {
287 if l.pretty_constraint == "self.version" {
288 if kind == LinkType::Require {
289 *has_self = true;
290 }
291 out.0.push(Link {
292 key: l.key.clone(),
293 source: l.source.clone(),
294 target: l.target.clone(),
295 constraint: Constraint::new(Op::Eq, version),
296 pretty_constraint: pretty.clone(),
297 kind,
298 });
299 } else {
300 out.0.push(l.clone());
301 }
302 }
303 }
304 out
305 };
306 let mut has_self = false;
307 a.requires = rewrite(&self.requires, LinkType::Require, &mut has_self);
308 a.dev_requires = rewrite(&self.dev_requires, LinkType::DevRequire, &mut has_self);
309 a.conflicts = rewrite(&self.conflicts, LinkType::Conflict, &mut has_self);
310 a.provides = rewrite(&self.provides, LinkType::Provide, &mut has_self);
311 a.replaces = rewrite(&self.replaces, LinkType::Replace, &mut has_self);
312 a.has_self_version_requires = has_self;
313 a
314 }
315}