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 get(&self, key: &str) -> Option<&Link> {
96 self.0.iter().find(|l| l.key.as_deref() == Some(key))
97 }
98 pub fn has_numeric_keys(&self) -> bool {
100 self.0.iter().any(|l| l.key.is_none())
101 }
102 pub fn iter(&self) -> impl Iterator<Item = &Link> {
103 self.0.iter()
104 }
105 pub fn len(&self) -> usize {
106 self.0.len()
107 }
108 pub fn is_empty(&self) -> bool {
109 self.0.is_empty()
110 }
111}
112
113#[derive(Debug, Clone, PartialEq, Eq)]
114pub struct SourceRef {
115 pub kind: String,
116 pub url: String,
117 pub reference: Option<String>,
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq)]
122pub enum Origin {
123 Root,
124 Platform,
125 Locked,
126 Repository(usize),
128 Detached,
130 Result,
133}
134
135#[derive(Debug, Clone)]
136pub struct Package {
137 pub name: String,
139 pub pretty_name: String,
140 pub version: String,
142 pub pretty_version: String,
143 pub package_type: String,
144 pub stability: &'static str,
145 pub is_default_branch: bool,
146 pub source: Option<SourceRef>,
147 pub dist: Option<SourceRef>,
148 pub requires: Links,
149 pub dev_requires: Links,
150 pub conflicts: Links,
151 pub provides: Links,
152 pub replaces: Links,
153 pub raw: Value,
155 pub origin: Origin,
156 pub alias_of: Option<usize>,
158 pub root_package_alias: bool,
160 pub has_self_version_requires: bool,
162}
163
164impl Package {
165 pub fn new(pretty_name: &str, version: &str, pretty_version: &str, origin: Origin) -> Package {
166 Package {
167 name: pretty_name.to_lowercase(),
168 pretty_name: pretty_name.to_owned(),
169 version: version.to_owned(),
170 pretty_version: pretty_version.to_owned(),
171 package_type: "library".to_owned(),
172 stability: parse_stability(version),
173 is_default_branch: false,
174 source: None,
175 dist: None,
176 requires: Links::default(),
177 dev_requires: Links::default(),
178 conflicts: Links::default(),
179 provides: Links::default(),
180 replaces: Links::default(),
181 raw: Value::Null,
182 origin,
183 alias_of: None,
184 root_package_alias: false,
185 has_self_version_requires: false,
186 }
187 }
188
189 pub fn is_alias(&self) -> bool {
190 self.alias_of.is_some()
191 }
192
193 pub fn is_dev(&self) -> bool {
194 self.stability == "dev"
195 }
196
197 pub fn names(&self, provides: bool) -> Vec<String> {
199 let mut names: Vec<String> = vec![self.name.clone()];
200 if provides {
201 for l in self.provides.iter() {
202 if !names.contains(&l.target) {
203 names.push(l.target.clone());
204 }
205 }
206 }
207 for l in self.replaces.iter() {
208 if !names.contains(&l.target) {
209 names.push(l.target.clone());
210 }
211 }
212 names
213 }
214
215 pub fn unique_name(&self) -> String {
216 format!("{}-{}", self.name, self.version)
217 }
218
219 pub fn pretty_string(&self) -> String {
220 format!("{} {}", self.pretty_name, self.pretty_version)
221 }
222
223 pub fn source_reference(&self) -> Option<&str> {
224 self.source.as_ref().and_then(|s| s.reference.as_deref())
225 }
226
227 pub fn dist_reference(&self) -> Option<&str> {
228 self.dist.as_ref().and_then(|s| s.reference.as_deref())
229 }
230
231 pub fn links(&self, kind: LinkType) -> &Links {
232 match kind {
233 LinkType::Require => &self.requires,
234 LinkType::DevRequire => &self.dev_requires,
235 LinkType::Conflict => &self.conflicts,
236 LinkType::Provide => &self.provides,
237 LinkType::Replace => &self.replaces,
238 }
239 }
240
241 pub fn alias(&self, alias_of: usize, version: &str, pretty_version: &str) -> Package {
245 let mut a = self.clone();
246 a.version = version.to_owned();
247 a.pretty_version = pretty_version.to_owned();
248 a.stability = parse_stability(version);
249 a.alias_of = Some(alias_of);
250 a.root_package_alias = false;
251 a.has_self_version_requires = false;
252 let pretty = if pretty_version == crate::version::DEFAULT_BRANCH_ALIAS {
253 self.pretty_version.clone()
254 } else {
255 pretty_version.to_owned()
256 };
257 let rewrite = |links: &Links, kind: LinkType, has_self: &mut bool| -> Links {
258 let mut out = Links::default();
259 if matches!(
260 kind,
261 LinkType::Conflict | LinkType::Provide | LinkType::Replace
262 ) {
263 let mut extra: Vec<Link> = Vec::new();
266 for l in links.iter() {
267 out.0.push(l.clone());
268 if l.pretty_constraint == "self.version" {
269 extra.push(Link {
270 key: None,
271 source: l.source.clone(),
272 target: l.target.clone(),
273 constraint: Constraint::new(Op::Eq, version),
274 pretty_constraint: pretty.clone(),
275 kind,
276 });
277 }
278 }
279 out.0.extend(extra);
280 } else {
281 for l in links.iter() {
282 if l.pretty_constraint == "self.version" {
283 if kind == LinkType::Require {
284 *has_self = true;
285 }
286 out.0.push(Link {
287 key: l.key.clone(),
288 source: l.source.clone(),
289 target: l.target.clone(),
290 constraint: Constraint::new(Op::Eq, version),
291 pretty_constraint: pretty.clone(),
292 kind,
293 });
294 } else {
295 out.0.push(l.clone());
296 }
297 }
298 }
299 out
300 };
301 let mut has_self = false;
302 a.requires = rewrite(&self.requires, LinkType::Require, &mut has_self);
303 a.dev_requires = rewrite(&self.dev_requires, LinkType::DevRequire, &mut has_self);
304 a.conflicts = rewrite(&self.conflicts, LinkType::Conflict, &mut has_self);
305 a.provides = rewrite(&self.provides, LinkType::Provide, &mut has_self);
306 a.replaces = rewrite(&self.replaces, LinkType::Replace, &mut has_self);
307 a.has_self_version_requires = has_self;
308 a
309 }
310}