diff --git a/examples/unsat_root_message_no_version.rs b/examples/unsat_root_message_no_version.rs index 5d37df4d..8b01bcf1 100644 --- a/examples/unsat_root_message_no_version.rs +++ b/examples/unsat_root_message_no_version.rs @@ -2,7 +2,7 @@ use pubgrub::error::PubGrubError; use pubgrub::range::Range; -use pubgrub::report::Reporter; +use pubgrub::report::{Derived, Reporter}; use pubgrub::solver::{resolve, OfflineDependencyProvider}; use pubgrub::version::SemanticVersion; @@ -106,6 +106,105 @@ impl ReportFormatter, String> for CustomReportFo } } } + + /// Simplest case, we just combine two external incompatibilities. + fn explain_both_external( + &self, + external1: &External, String>, + external2: &External, String>, + current_terms: &Map>>, + ) -> String { + // TODO: order should be chosen to make it more logical. + format!( + "Because {} and {}, {}.", + self.format_external(external1), + self.format_external(external2), + self.format_terms(current_terms) + ) + } + + /// Both causes have already been explained so we use their refs. + fn explain_both_ref( + &self, + ref_id1: usize, + derived1: &Derived, String>, + ref_id2: usize, + derived2: &Derived, String>, + current_terms: &Map>>, + ) -> String { + // TODO: order should be chosen to make it more logical. + format!( + "Because {} ({}) and {} ({}), {}.", + self.format_terms(&derived1.terms), + ref_id1, + self.format_terms(&derived2.terms), + ref_id2, + self.format_terms(current_terms) + ) + } + + /// One cause is derived (already explained so one-line), + /// the other is a one-line external cause, + /// and finally we conclude with the current incompatibility. + fn explain_ref_and_external( + &self, + ref_id: usize, + derived: &Derived, String>, + external: &External, String>, + current_terms: &Map>>, + ) -> String { + // TODO: order should be chosen to make it more logical. + format!( + "Because {} ({}) and {}, {}.", + self.format_terms(&derived.terms), + ref_id, + self.format_external(external), + self.format_terms(current_terms) + ) + } + + /// Add an external cause to the chain of explanations. + fn and_explain_external( + &self, + external: &External, String>, + current_terms: &Map>>, + ) -> String { + format!( + "And because {}, {}.", + self.format_external(external), + self.format_terms(current_terms) + ) + } + + /// Add an already explained incompat to the chain of explanations. + fn and_explain_ref( + &self, + ref_id: usize, + derived: &Derived, String>, + current_terms: &Map>>, + ) -> String { + format!( + "And because {} ({}), {}.", + self.format_terms(&derived.terms), + ref_id, + self.format_terms(current_terms) + ) + } + + /// Add an already explained incompat to the chain of explanations. + fn and_explain_prior_and_external( + &self, + prior_external: &External, String>, + external: &External, String>, + current_terms: &Map>>, + ) -> String { + format!( + "And because {} and {}, {}.", + self.format_external(prior_external), + self.format_external(external), + self.format_terms(current_terms) + ) + } } fn main() { diff --git a/src/report.rs b/src/report.rs index d1b31655..944bd9f0 100644 --- a/src/report.rs +++ b/src/report.rs @@ -221,6 +221,58 @@ pub trait ReportFormatter>) -> Self::Output; + + /// Simplest case, we just combine two external incompatibilities. + fn explain_both_external( + &self, + external1: &External, + external2: &External, + current_terms: &Map>, + ) -> Self::Output; + + /// Both causes have already been explained so we use their refs. + fn explain_both_ref( + &self, + ref_id1: usize, + derived1: &Derived, + ref_id2: usize, + derived2: &Derived, + current_terms: &Map>, + ) -> Self::Output; + + /// One cause is derived (already explained so one-line), + /// the other is a one-line external cause, + /// and finally we conclude with the current incompatibility. + fn explain_ref_and_external( + &self, + ref_id: usize, + derived: &Derived, + external: &External, + current_terms: &Map>, + ) -> Self::Output; + + /// Add an external cause to the chain of explanations. + fn and_explain_external( + &self, + external: &External, + current_terms: &Map>, + ) -> Self::Output; + + /// Add an already explained incompat to the chain of explanations. + fn and_explain_ref( + &self, + ref_id: usize, + derived: &Derived, + current_terms: &Map>, + ) -> Self::Output; + + /// Add an already explained incompat to the chain of explanations. + fn and_explain_prior_and_external( + &self, + prior_external: &External, + external: &External, + current_terms: &Map>, + ) -> Self::Output; } /// Default formatter for the default reporter. @@ -255,6 +307,105 @@ impl ReportFormatte } } } + + /// Simplest case, we just combine two external incompatibilities. + fn explain_both_external( + &self, + external1: &External, + external2: &External, + current_terms: &Map>, + ) -> String { + // TODO: order should be chosen to make it more logical. + format!( + "Because {} and {}, {}.", + self.format_external(external1), + self.format_external(external2), + ReportFormatter::::format_terms(self, current_terms) + ) + } + + /// Both causes have already been explained so we use their refs. + fn explain_both_ref( + &self, + ref_id1: usize, + derived1: &Derived, + ref_id2: usize, + derived2: &Derived, + current_terms: &Map>, + ) -> String { + // TODO: order should be chosen to make it more logical. + format!( + "Because {} ({}) and {} ({}), {}.", + ReportFormatter::::format_terms(self, &derived1.terms), + ref_id1, + ReportFormatter::::format_terms(self, &derived2.terms), + ref_id2, + ReportFormatter::::format_terms(self, current_terms) + ) + } + + /// One cause is derived (already explained so one-line), + /// the other is a one-line external cause, + /// and finally we conclude with the current incompatibility. + fn explain_ref_and_external( + &self, + ref_id: usize, + derived: &Derived, + external: &External, + current_terms: &Map>, + ) -> String { + // TODO: order should be chosen to make it more logical. + format!( + "Because {} ({}) and {}, {}.", + ReportFormatter::::format_terms(self, &derived.terms), + ref_id, + self.format_external(external), + ReportFormatter::::format_terms(self, current_terms) + ) + } + + /// Add an external cause to the chain of explanations. + fn and_explain_external( + &self, + external: &External, + current_terms: &Map>, + ) -> String { + format!( + "And because {}, {}.", + self.format_external(external), + ReportFormatter::::format_terms(self, current_terms) + ) + } + + /// Add an already explained incompat to the chain of explanations. + fn and_explain_ref( + &self, + ref_id: usize, + derived: &Derived, + current_terms: &Map>, + ) -> String { + format!( + "And because {} ({}), {}.", + ReportFormatter::::format_terms(self, &derived.terms), + ref_id, + ReportFormatter::::format_terms(self, current_terms) + ) + } + + /// Add an already explained incompat to the chain of explanations. + fn and_explain_prior_and_external( + &self, + prior_external: &External, + external: &External, + current_terms: &Map>, + ) -> String { + format!( + "And because {} and {}, {}.", + self.format_external(prior_external), + self.format_external(external), + ReportFormatter::::format_terms(self, current_terms) + ) + } } /// Default reporter able to generate an explanation as a [String]. @@ -311,11 +462,10 @@ impl DefaultStringReporter { match (current.cause1.deref(), current.cause2.deref()) { (DerivationTree::External(external1), DerivationTree::External(external2)) => { // Simplest case, we just combine two external incompatibilities. - self.lines.push(Self::explain_both_external( + self.lines.push(formatter.explain_both_external( external1, external2, ¤t.terms, - formatter, )); } (DerivationTree::Derived(derived), DerivationTree::External(external)) => { @@ -335,34 +485,25 @@ impl DefaultStringReporter { ) { // If both causes already have been referenced (shared_id), // the explanation simply uses those references. - (Some(ref1), Some(ref2)) => self.lines.push(Self::explain_both_ref( + (Some(ref1), Some(ref2)) => self.lines.push(formatter.explain_both_ref( ref1, derived1, ref2, derived2, ¤t.terms, - formatter, )), // Otherwise, if one only has a line number reference, // we recursively call the one without reference and then // add the one with reference to conclude. (Some(ref1), None) => { self.build_recursive(derived2, formatter); - self.lines.push(Self::and_explain_ref( - ref1, - derived1, - ¤t.terms, - formatter, - )); + self.lines + .push(formatter.and_explain_ref(ref1, derived1, ¤t.terms)); } (None, Some(ref2)) => { self.build_recursive(derived1, formatter); - self.lines.push(Self::and_explain_ref( - ref2, - derived2, - ¤t.terms, - formatter, - )); + self.lines + .push(formatter.and_explain_ref(ref2, derived2, ¤t.terms)); } // Finally, if no line reference exists yet, // we call recursively the first one and then, @@ -381,11 +522,10 @@ impl DefaultStringReporter { let ref1 = self.ref_count; self.lines.push("".into()); self.build_recursive(derived2, formatter); - self.lines.push(Self::and_explain_ref( + self.lines.push(formatter.and_explain_ref( ref1, derived1, ¤t.terms, - formatter, )); } } @@ -411,12 +551,11 @@ impl DefaultStringReporter { formatter: &F, ) { match self.line_ref_of(derived.shared_id) { - Some(ref_id) => self.lines.push(Self::explain_ref_and_external( + Some(ref_id) => self.lines.push(formatter.explain_ref_and_external( ref_id, derived, external, current_terms, - formatter, )), None => self.report_recurse_one_each(derived, external, current_terms, formatter), } @@ -440,166 +579,30 @@ impl DefaultStringReporter { // we can chain the external explanations. (DerivationTree::Derived(prior_derived), DerivationTree::External(prior_external)) => { self.build_recursive(prior_derived, formatter); - self.lines.push(Self::and_explain_prior_and_external( + self.lines.push(formatter.and_explain_prior_and_external( prior_external, external, current_terms, - formatter, )); } // If the derived cause has itself one external prior cause, // we can chain the external explanations. (DerivationTree::External(prior_external), DerivationTree::Derived(prior_derived)) => { self.build_recursive(prior_derived, formatter); - self.lines.push(Self::and_explain_prior_and_external( + self.lines.push(formatter.and_explain_prior_and_external( prior_external, external, current_terms, - formatter, )); } _ => { self.build_recursive(derived, formatter); - self.lines.push(Self::and_explain_external( - external, - current_terms, - formatter, - )); + self.lines + .push(formatter.and_explain_external(external, current_terms)); } } } - // String explanations ##################################################### - - /// Simplest case, we just combine two external incompatibilities. - fn explain_both_external< - P: Package, - VS: VersionSet, - M: Eq + Clone + Debug + Display, - F: ReportFormatter, - >( - external1: &External, - external2: &External, - current_terms: &Map>, - formatter: &F, - ) -> String { - // TODO: order should be chosen to make it more logical. - format!( - "Because {} and {}, {}.", - formatter.format_external(external1), - formatter.format_external(external2), - formatter.format_terms(current_terms) - ) - } - - /// Both causes have already been explained so we use their refs. - fn explain_both_ref< - P: Package, - VS: VersionSet, - M: Eq + Clone + Debug + Display, - F: ReportFormatter, - >( - ref_id1: usize, - derived1: &Derived, - ref_id2: usize, - derived2: &Derived, - current_terms: &Map>, - formatter: &F, - ) -> String { - // TODO: order should be chosen to make it more logical. - format!( - "Because {} ({}) and {} ({}), {}.", - formatter.format_terms(&derived1.terms), - ref_id1, - formatter.format_terms(&derived2.terms), - ref_id2, - formatter.format_terms(current_terms) - ) - } - - /// One cause is derived (already explained so one-line), - /// the other is a one-line external cause, - /// and finally we conclude with the current incompatibility. - fn explain_ref_and_external< - P: Package, - VS: VersionSet, - M: Eq + Clone + Debug + Display, - F: ReportFormatter, - >( - ref_id: usize, - derived: &Derived, - external: &External, - current_terms: &Map>, - formatter: &F, - ) -> String { - // TODO: order should be chosen to make it more logical. - format!( - "Because {} ({}) and {}, {}.", - formatter.format_terms(&derived.terms), - ref_id, - formatter.format_external(external), - formatter.format_terms(current_terms) - ) - } - - /// Add an external cause to the chain of explanations. - fn and_explain_external< - P: Package, - VS: VersionSet, - M: Eq + Clone + Debug + Display, - F: ReportFormatter, - >( - external: &External, - current_terms: &Map>, - formatter: &F, - ) -> String { - format!( - "And because {}, {}.", - formatter.format_external(external), - formatter.format_terms(current_terms) - ) - } - - /// Add an already explained incompat to the chain of explanations. - fn and_explain_ref< - P: Package, - VS: VersionSet, - M: Eq + Clone + Debug + Display, - F: ReportFormatter, - >( - ref_id: usize, - derived: &Derived, - current_terms: &Map>, - formatter: &F, - ) -> String { - format!( - "And because {} ({}), {}.", - formatter.format_terms(&derived.terms), - ref_id, - formatter.format_terms(current_terms) - ) - } - - /// Add an already explained incompat to the chain of explanations. - fn and_explain_prior_and_external< - P: Package, - VS: VersionSet, - M: Eq + Clone + Debug + Display, - F: ReportFormatter, - >( - prior_external: &External, - external: &External, - current_terms: &Map>, - formatter: &F, - ) -> String { - format!( - "And because {} and {}, {}.", - formatter.format_external(prior_external), - formatter.format_external(external), - formatter.format_terms(current_terms) - ) - } - // Helper functions ######################################################## fn add_line_ref(&mut self) {