1use std::fmt::{self, Debug, Display};
7use std::ops::Deref;
8use std::sync::Arc;
9
10use crate::{Map, Package, Set, Term, VersionSet};
11
12pub trait Reporter<P: Package, VS: VersionSet, M: Eq + Clone + Debug + Display> {
14 type Output;
16
17 fn report(derivation_tree: &DerivationTree<P, VS, M>) -> Self::Output;
20
21 fn report_with_formatter(
24 derivation_tree: &DerivationTree<P, VS, M>,
25 formatter: &impl ReportFormatter<P, VS, M, Output = Self::Output>,
26 ) -> Self::Output;
27}
28
29#[derive(Debug, Clone)]
31pub enum DerivationTree<P: Package, VS: VersionSet, M: Eq + Clone + Debug + Display> {
32 External(External<P, VS, M>),
34 Derived(Derived<P, VS, M>),
36}
37
38#[derive(Debug, Clone)]
40pub enum External<P: Package, VS: VersionSet, M: Eq + Clone + Debug + Display> {
41 NotRoot(P, VS::V),
43 NoVersions(P, VS),
45 FromDependencyOf(P, VS, P, VS),
47 Custom(P, VS, M),
49}
50
51#[derive(Debug, Clone)]
53pub struct Derived<P: Package, VS: VersionSet, M: Eq + Clone + Debug + Display> {
54 pub terms: Map<P, Term<VS>>,
56 pub shared_id: Option<usize>,
61 pub cause1: Arc<DerivationTree<P, VS, M>>,
63 pub cause2: Arc<DerivationTree<P, VS, M>>,
65}
66
67impl<P: Package, VS: VersionSet, M: Eq + Clone + Debug + Display> DerivationTree<P, VS, M> {
68 pub fn packages(&self) -> Set<&P> {
70 let mut packages = Set::default();
71 match self {
72 Self::External(external) => match external {
73 External::FromDependencyOf(p, _, p2, _) => {
74 packages.insert(p);
75 packages.insert(p2);
76 }
77 External::NoVersions(p, _)
78 | External::NotRoot(p, _)
79 | External::Custom(p, _, _) => {
80 packages.insert(p);
81 }
82 },
83 Self::Derived(derived) => {
84 packages.extend(derived.terms.keys());
87 packages.extend(derived.cause1.packages().iter());
88 packages.extend(derived.cause2.packages().iter());
89 }
90 }
91 packages
92 }
93
94 pub fn collapse_no_versions(&mut self) {
103 match self {
104 DerivationTree::External(_) => {}
105 DerivationTree::Derived(derived) => {
106 match (
107 Arc::make_mut(&mut derived.cause1),
108 Arc::make_mut(&mut derived.cause2),
109 ) {
110 (DerivationTree::External(External::NoVersions(p, r)), ref mut cause2) => {
111 cause2.collapse_no_versions();
112 *self = cause2
113 .clone()
114 .merge_no_versions(p.to_owned(), r.to_owned())
115 .unwrap_or_else(|| self.to_owned());
116 }
117 (ref mut cause1, DerivationTree::External(External::NoVersions(p, r))) => {
118 cause1.collapse_no_versions();
119 *self = cause1
120 .clone()
121 .merge_no_versions(p.to_owned(), r.to_owned())
122 .unwrap_or_else(|| self.to_owned());
123 }
124 _ => {
125 Arc::make_mut(&mut derived.cause1).collapse_no_versions();
126 Arc::make_mut(&mut derived.cause2).collapse_no_versions();
127 }
128 }
129 }
130 }
131 }
132
133 fn merge_no_versions(self, package: P, set: VS) -> Option<Self> {
134 match self {
135 DerivationTree::Derived(_) => Some(self),
138 DerivationTree::External(External::NotRoot(_, _)) => {
139 panic!("How did we end up with a NoVersions merged with a NotRoot?")
140 }
141 DerivationTree::External(External::NoVersions(_, _)) => None,
144 DerivationTree::External(External::Custom(_, r, reason)) => Some(
145 DerivationTree::External(External::Custom(package, set.union(&r), reason)),
146 ),
147 DerivationTree::External(External::FromDependencyOf(p1, r1, p2, r2)) => {
148 if p1 == package {
149 Some(DerivationTree::External(External::FromDependencyOf(
150 p1,
151 r1.union(&set),
152 p2,
153 r2,
154 )))
155 } else {
156 Some(DerivationTree::External(External::FromDependencyOf(
157 p1,
158 r1,
159 p2,
160 r2.union(&set),
161 )))
162 }
163 }
164 }
165 }
166}
167
168impl<P: Package, VS: VersionSet, M: Eq + Clone + Debug + Display> Display for External<P, VS, M> {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 match self {
171 Self::NotRoot(package, version) => {
172 write!(f, "we are solving dependencies of {package} {version}")
173 }
174 Self::NoVersions(package, set) => {
175 if set == &VS::full() {
176 write!(f, "there is no available version for {package}")
177 } else {
178 write!(f, "there is no version of {package} in {set}")
179 }
180 }
181 Self::Custom(package, set, metadata) => {
182 if set == &VS::full() {
183 write!(f, "dependencies of {package} are unavailable {metadata}")
184 } else {
185 write!(
186 f,
187 "dependencies of {package} at version {set} are unavailable {metadata}"
188 )
189 }
190 }
191 Self::FromDependencyOf(p, set_p, dep, set_dep) => {
192 if set_p == &VS::full() && set_dep == &VS::full() {
193 write!(f, "{p} depends on {dep}")
194 } else if set_p == &VS::full() {
195 write!(f, "{p} depends on {dep} {set_dep}")
196 } else if set_dep == &VS::full() {
197 write!(f, "{p} {set_p} depends on {dep}")
198 } else {
199 write!(f, "{p} {set_p} depends on {dep} {set_dep}")
200 }
201 }
202 }
203 }
204}
205
206pub trait ReportFormatter<P: Package, VS: VersionSet, M: Eq + Clone + Debug + Display> {
208 type Output;
210
211 fn format_external(&self, external: &External<P, VS, M>) -> Self::Output;
213
214 fn format_terms(&self, terms: &Map<P, Term<VS>>) -> Self::Output;
216
217 fn explain_both_external(
219 &self,
220 external1: &External<P, VS, M>,
221 external2: &External<P, VS, M>,
222 current_terms: &Map<P, Term<VS>>,
223 ) -> Self::Output;
224
225 fn explain_both_ref(
227 &self,
228 ref_id1: usize,
229 derived1: &Derived<P, VS, M>,
230 ref_id2: usize,
231 derived2: &Derived<P, VS, M>,
232 current_terms: &Map<P, Term<VS>>,
233 ) -> Self::Output;
234
235 fn explain_ref_and_external(
239 &self,
240 ref_id: usize,
241 derived: &Derived<P, VS, M>,
242 external: &External<P, VS, M>,
243 current_terms: &Map<P, Term<VS>>,
244 ) -> Self::Output;
245
246 fn and_explain_external(
248 &self,
249 external: &External<P, VS, M>,
250 current_terms: &Map<P, Term<VS>>,
251 ) -> Self::Output;
252
253 fn and_explain_ref(
255 &self,
256 ref_id: usize,
257 derived: &Derived<P, VS, M>,
258 current_terms: &Map<P, Term<VS>>,
259 ) -> Self::Output;
260
261 fn and_explain_prior_and_external(
263 &self,
264 prior_external: &External<P, VS, M>,
265 external: &External<P, VS, M>,
266 current_terms: &Map<P, Term<VS>>,
267 ) -> Self::Output;
268}
269
270#[derive(Default, Debug)]
272pub struct DefaultStringReportFormatter;
273
274impl<P: Package, VS: VersionSet, M: Eq + Clone + Debug + Display> ReportFormatter<P, VS, M>
275 for DefaultStringReportFormatter
276{
277 type Output = String;
278
279 fn format_external(&self, external: &External<P, VS, M>) -> String {
280 external.to_string()
281 }
282
283 fn format_terms(&self, terms: &Map<P, Term<VS>>) -> Self::Output {
284 let terms_vec: Vec<_> = terms.iter().collect();
285 match terms_vec.as_slice() {
286 [] => "version solving failed".into(),
287 [(package, Term::Positive(range))] => format!("{package} {range} is forbidden"),
289 [(package, Term::Negative(range))] => format!("{package} {range} is mandatory"),
290 [(p1, Term::Positive(r1)), (p2, Term::Negative(r2))] => self.format_external(
291 &External::<_, _, M>::FromDependencyOf(p1, r1.clone(), p2, r2.clone()),
292 ),
293 [(p1, Term::Negative(r1)), (p2, Term::Positive(r2))] => self.format_external(
294 &External::<_, _, M>::FromDependencyOf(p2, r2.clone(), p1, r1.clone()),
295 ),
296 slice => {
297 let str_terms: Vec<_> = slice.iter().map(|(p, t)| format!("{p} {t}")).collect();
298 str_terms.join(", ") + " are incompatible"
299 }
300 }
301 }
302
303 fn explain_both_external(
305 &self,
306 external1: &External<P, VS, M>,
307 external2: &External<P, VS, M>,
308 current_terms: &Map<P, Term<VS>>,
309 ) -> String {
310 format!(
312 "Because {} and {}, {}.",
313 self.format_external(external1),
314 self.format_external(external2),
315 ReportFormatter::<P, VS, M>::format_terms(self, current_terms)
316 )
317 }
318
319 fn explain_both_ref(
321 &self,
322 ref_id1: usize,
323 derived1: &Derived<P, VS, M>,
324 ref_id2: usize,
325 derived2: &Derived<P, VS, M>,
326 current_terms: &Map<P, Term<VS>>,
327 ) -> String {
328 format!(
330 "Because {} ({}) and {} ({}), {}.",
331 ReportFormatter::<P, VS, M>::format_terms(self, &derived1.terms),
332 ref_id1,
333 ReportFormatter::<P, VS, M>::format_terms(self, &derived2.terms),
334 ref_id2,
335 ReportFormatter::<P, VS, M>::format_terms(self, current_terms)
336 )
337 }
338
339 fn explain_ref_and_external(
343 &self,
344 ref_id: usize,
345 derived: &Derived<P, VS, M>,
346 external: &External<P, VS, M>,
347 current_terms: &Map<P, Term<VS>>,
348 ) -> String {
349 format!(
351 "Because {} ({}) and {}, {}.",
352 ReportFormatter::<P, VS, M>::format_terms(self, &derived.terms),
353 ref_id,
354 self.format_external(external),
355 ReportFormatter::<P, VS, M>::format_terms(self, current_terms)
356 )
357 }
358
359 fn and_explain_external(
361 &self,
362 external: &External<P, VS, M>,
363 current_terms: &Map<P, Term<VS>>,
364 ) -> String {
365 format!(
366 "And because {}, {}.",
367 self.format_external(external),
368 ReportFormatter::<P, VS, M>::format_terms(self, current_terms)
369 )
370 }
371
372 fn and_explain_ref(
374 &self,
375 ref_id: usize,
376 derived: &Derived<P, VS, M>,
377 current_terms: &Map<P, Term<VS>>,
378 ) -> String {
379 format!(
380 "And because {} ({}), {}.",
381 ReportFormatter::<P, VS, M>::format_terms(self, &derived.terms),
382 ref_id,
383 ReportFormatter::<P, VS, M>::format_terms(self, current_terms)
384 )
385 }
386
387 fn and_explain_prior_and_external(
389 &self,
390 prior_external: &External<P, VS, M>,
391 external: &External<P, VS, M>,
392 current_terms: &Map<P, Term<VS>>,
393 ) -> String {
394 format!(
395 "And because {} and {}, {}.",
396 self.format_external(prior_external),
397 self.format_external(external),
398 ReportFormatter::<P, VS, M>::format_terms(self, current_terms)
399 )
400 }
401}
402
403pub struct DefaultStringReporter {
405 ref_count: usize,
407 shared_with_ref: Map<usize, usize>,
410 lines: Vec<String>,
412}
413
414impl DefaultStringReporter {
415 fn new() -> Self {
417 Self {
418 ref_count: 0,
419 shared_with_ref: Map::default(),
420 lines: Vec::new(),
421 }
422 }
423
424 fn build_recursive<
425 P: Package,
426 VS: VersionSet,
427 M: Eq + Clone + Debug + Display,
428 F: ReportFormatter<P, VS, M, Output = String>,
429 >(
430 &mut self,
431 derived: &Derived<P, VS, M>,
432 formatter: &F,
433 ) {
434 self.build_recursive_helper(derived, formatter);
435 if let Some(id) = derived.shared_id {
436 #[allow(clippy::map_entry)] if !self.shared_with_ref.contains_key(&id) {
438 self.add_line_ref();
439 self.shared_with_ref.insert(id, self.ref_count);
440 }
441 };
442 }
443
444 fn build_recursive_helper<
445 P: Package,
446 VS: VersionSet,
447 M: Eq + Clone + Debug + Display,
448 F: ReportFormatter<P, VS, M, Output = String>,
449 >(
450 &mut self,
451 current: &Derived<P, VS, M>,
452 formatter: &F,
453 ) {
454 match (current.cause1.deref(), current.cause2.deref()) {
455 (DerivationTree::External(external1), DerivationTree::External(external2)) => {
456 self.lines.push(formatter.explain_both_external(
458 external1,
459 external2,
460 ¤t.terms,
461 ));
462 }
463 (DerivationTree::Derived(derived), DerivationTree::External(external)) => {
464 self.report_one_each(derived, external, ¤t.terms, formatter);
468 }
469 (DerivationTree::External(external), DerivationTree::Derived(derived)) => {
470 self.report_one_each(derived, external, ¤t.terms, formatter);
471 }
472 (DerivationTree::Derived(derived1), DerivationTree::Derived(derived2)) => {
473 match (
475 self.line_ref_of(derived1.shared_id),
476 self.line_ref_of(derived2.shared_id),
477 ) {
478 (Some(ref1), Some(ref2)) => self.lines.push(formatter.explain_both_ref(
481 ref1,
482 derived1,
483 ref2,
484 derived2,
485 ¤t.terms,
486 )),
487 (Some(ref1), None) => {
491 self.build_recursive(derived2, formatter);
492 self.lines
493 .push(formatter.and_explain_ref(ref1, derived1, ¤t.terms));
494 }
495 (None, Some(ref2)) => {
496 self.build_recursive(derived1, formatter);
497 self.lines
498 .push(formatter.and_explain_ref(ref2, derived2, ¤t.terms));
499 }
500 (None, None) => {
508 self.build_recursive(derived1, formatter);
509 if derived1.shared_id.is_some() {
510 self.lines.push("".into());
511 self.build_recursive(current, formatter);
512 } else {
513 self.add_line_ref();
514 let ref1 = self.ref_count;
515 self.lines.push("".into());
516 self.build_recursive(derived2, formatter);
517 self.lines.push(formatter.and_explain_ref(
518 ref1,
519 derived1,
520 ¤t.terms,
521 ));
522 }
523 }
524 }
525 }
526 }
527 }
528
529 fn report_one_each<
534 P: Package,
535 VS: VersionSet,
536 M: Eq + Clone + Debug + Display,
537 F: ReportFormatter<P, VS, M, Output = String>,
538 >(
539 &mut self,
540 derived: &Derived<P, VS, M>,
541 external: &External<P, VS, M>,
542 current_terms: &Map<P, Term<VS>>,
543 formatter: &F,
544 ) {
545 match self.line_ref_of(derived.shared_id) {
546 Some(ref_id) => self.lines.push(formatter.explain_ref_and_external(
547 ref_id,
548 derived,
549 external,
550 current_terms,
551 )),
552 None => self.report_recurse_one_each(derived, external, current_terms, formatter),
553 }
554 }
555
556 fn report_recurse_one_each<
558 P: Package,
559 VS: VersionSet,
560 M: Eq + Clone + Debug + Display,
561 F: ReportFormatter<P, VS, M, Output = String>,
562 >(
563 &mut self,
564 derived: &Derived<P, VS, M>,
565 external: &External<P, VS, M>,
566 current_terms: &Map<P, Term<VS>>,
567 formatter: &F,
568 ) {
569 match (derived.cause1.deref(), derived.cause2.deref()) {
570 (DerivationTree::Derived(prior_derived), DerivationTree::External(prior_external)) => {
573 self.build_recursive(prior_derived, formatter);
574 self.lines.push(formatter.and_explain_prior_and_external(
575 prior_external,
576 external,
577 current_terms,
578 ));
579 }
580 (DerivationTree::External(prior_external), DerivationTree::Derived(prior_derived)) => {
583 self.build_recursive(prior_derived, formatter);
584 self.lines.push(formatter.and_explain_prior_and_external(
585 prior_external,
586 external,
587 current_terms,
588 ));
589 }
590 _ => {
591 self.build_recursive(derived, formatter);
592 self.lines
593 .push(formatter.and_explain_external(external, current_terms));
594 }
595 }
596 }
597
598 fn add_line_ref(&mut self) {
601 let new_count = self.ref_count + 1;
602 self.ref_count = new_count;
603 if let Some(line) = self.lines.last_mut() {
604 *line = format!("{line} ({new_count})");
605 }
606 }
607
608 fn line_ref_of(&self, shared_id: Option<usize>) -> Option<usize> {
609 shared_id.and_then(|id| self.shared_with_ref.get(&id).cloned())
610 }
611}
612
613impl<P: Package, VS: VersionSet, M: Eq + Clone + Debug + Display> Reporter<P, VS, M>
614 for DefaultStringReporter
615{
616 type Output = String;
617
618 fn report(derivation_tree: &DerivationTree<P, VS, M>) -> Self::Output {
619 let formatter = DefaultStringReportFormatter;
620 match derivation_tree {
621 DerivationTree::External(external) => formatter.format_external(external),
622 DerivationTree::Derived(derived) => {
623 let mut reporter = Self::new();
624 reporter.build_recursive(derived, &formatter);
625 reporter.lines.join("\n")
626 }
627 }
628 }
629
630 fn report_with_formatter(
631 derivation_tree: &DerivationTree<P, VS, M>,
632 formatter: &impl ReportFormatter<P, VS, M, Output = Self::Output>,
633 ) -> Self::Output {
634 match derivation_tree {
635 DerivationTree::External(external) => formatter.format_external(external),
636 DerivationTree::Derived(derived) => {
637 let mut reporter = Self::new();
638 reporter.build_recursive(derived, formatter);
639 reporter.lines.join("\n")
640 }
641 }
642 }
643}