1#[cfg(test)]
47pub(crate) mod test;
48
49#[cfg(test)]
50mod test_group_by_elem;
51
52use std::{
53 borrow::Cow,
54 collections::{btree_map, BTreeMap, HashSet},
55 fmt,
56 ops::Deref,
57 vec,
58};
59
60use tracing::{debug, info};
61
62use crate::json;
63
64#[doc(hidden)]
65#[macro_export]
66macro_rules! from_warning_all {
67 ($($source_kind:path => $target_kind:ident::$target_variant:ident),+) => {
68 $(
69 impl From<$source_kind> for $target_kind {
71 fn from(warning: $source_kind) -> Self {
72 $target_kind::$target_variant(warning)
73 }
74 }
75
76 impl From<$crate::warning::ErrorSet<$source_kind>> for $crate::warning::ErrorSet<$target_kind> {
81 fn from(set_a: $crate::warning::ErrorSet<$source_kind>) -> Self {
82 set_a.into_other()
83 }
84 }
85
86 impl From<$crate::warning::ErrorSetDeferred<$source_kind>> for $crate::warning::ErrorSetDeferred<$target_kind> {
91 fn from(set_a: $crate::warning::ErrorSetDeferred<$source_kind>) -> Self {
92 set_a.into_other()
93 }
94 }
95 )+
96 };
97}
98
99#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
100pub struct Id(Cow<'static, str>);
101
102impl Id {
103 pub(crate) const fn from_static(s: &'static str) -> Self {
105 Self(Cow::Borrowed(s))
106 }
107
108 pub(crate) const fn from_string(s: String) -> Self {
110 Self(Cow::Owned(s))
111 }
112
113 pub fn as_str(&self) -> &str {
115 &self.0
116 }
117}
118
119impl fmt::Debug for Id {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 fmt::Debug::fmt(&self.0, f)
122 }
123}
124
125impl fmt::Display for Id {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 fmt::Display::fmt(&self.0, f)
128 }
129}
130
131#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)]
132pub struct Path(String);
133
134impl Path {
135 pub fn as_str(&self) -> &str {
136 &self.0
137 }
138}
139
140impl fmt::Debug for Path {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 f.write_str(&self.0)
143 }
144}
145
146impl fmt::Display for Path {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 fmt::Display::fmt(&self.0, f)
149 }
150}
151
152pub type Verdict<T, W> = Result<Caveat<T, W>, ErrorSet<W>>;
154
155pub(crate) type VerdictDeferred<T, W> = Result<CaveatDeferred<T, W>, ErrorSetDeferred<W>>;
162
163#[derive(Debug)]
173pub(crate) struct CaveatDeferred<T, W: Warning> {
174 value: T,
176
177 warnings: SetDeferred<W>,
179}
180
181impl<T, W> Deref for CaveatDeferred<T, W>
196where
197 W: Warning,
198{
199 type Target = T;
200
201 fn deref(&self) -> &T {
202 &self.value
203 }
204}
205
206impl<T, W> CaveatDeferred<T, W>
207where
208 W: Warning,
209{
210 pub(crate) fn new(value: T, warnings: SetDeferred<W>) -> Self {
212 Self { value, warnings }
213 }
214
215 pub fn into_parts(self) -> (T, SetDeferred<W>) {
217 let Self { value, warnings } = self;
218 (value, warnings)
219 }
220}
221
222#[derive(Debug)]
226pub struct Caveat<T, W: Warning> {
227 value: T,
229
230 warnings: Set<W>,
232}
233
234impl<T, W> Deref for Caveat<T, W>
247where
248 W: Warning,
249{
250 type Target = T;
251
252 fn deref(&self) -> &T {
253 &self.value
254 }
255}
256
257impl<T, W> Caveat<T, W>
258where
259 W: Warning,
260{
261 pub(crate) fn new(value: T, warnings: Set<W>) -> Self {
263 Self { value, warnings }
264 }
265
266 pub fn into_parts(self) -> (T, Set<W>) {
268 let Self { value, warnings } = self;
269 (value, warnings)
270 }
271
272 pub fn ignore_warnings(self) -> T {
274 self.value
275 }
276
277 pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Caveat<U, W> {
279 let Self { value, warnings } = self;
280 Caveat {
281 value: op(value),
282 warnings,
283 }
284 }
285}
286
287pub(crate) trait GatherWarnings<T, W>
292where
293 W: Warning,
294{
295 type Output;
297
298 #[must_use = "If you want to ignore the value use `let _ =`"]
300 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
301 where
302 W: Into<WA>,
303 WA: Warning;
304}
305
306impl<T, W> GatherWarnings<T, W> for Caveat<T, W>
308where
309 W: Warning,
310{
311 type Output = T;
312
313 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
315 where
316 W: Into<WA>,
317 WA: Warning,
318 {
319 let Self {
320 value,
321 warnings: inner_warnings,
322 } = self;
323
324 let Set(inner_warnings) = inner_warnings;
325 let inner_warnings = inner_warnings
326 .into_iter()
327 .map(|(elem_id, group)| (elem_id, group.into_other()));
328
329 warnings.extend(inner_warnings);
330
331 value
332 }
333}
334
335impl<T, W> GatherWarnings<T, W> for Option<Caveat<T, W>>
337where
338 W: Warning,
339{
340 type Output = Option<T>;
341
342 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
344 where
345 W: Into<WA>,
346 WA: Warning,
347 {
348 match self {
349 Some(cv) => Some(cv.gather_warnings_into(warnings)),
350 None => None,
351 }
352 }
353}
354
355impl<T, W, E> GatherWarnings<T, W> for Result<Caveat<T, W>, E>
357where
358 W: Warning,
359 E: std::error::Error,
360{
361 type Output = Result<T, E>;
362
363 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
365 where
366 W: Into<WA>,
367 WA: Warning,
368 {
369 match self {
370 Ok(cv) => Ok(cv.gather_warnings_into(warnings)),
371 Err(err) => Err(err),
372 }
373 }
374}
375
376impl<T, W> GatherWarnings<T, W> for Verdict<T, W>
378where
379 W: Warning,
380{
381 type Output = Result<T, ErrorSet<W>>;
382
383 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
386 where
387 W: Into<WA>,
388 WA: Warning,
389 {
390 match self {
391 Ok(cv) => Ok(cv.gather_warnings_into(warnings)),
392 Err(err_set) => Err(err_set),
393 }
394 }
395}
396
397pub(crate) trait DeescalateError<T, W>
402where
403 W: Warning,
404{
405 #[must_use = "If you want to ignore the value use `let _ =`"]
407 fn deescalate_error_into<WA>(self, warnings: &mut Set<WA>) -> Option<T>
408 where
409 W: Into<WA>,
410 WA: Warning;
411}
412
413impl<T, W> DeescalateError<T, W> for Verdict<T, W>
415where
416 W: Warning,
417{
418 fn deescalate_error_into<WA>(self, warnings: &mut Set<WA>) -> Option<T>
421 where
422 W: Into<WA>,
423 WA: Warning,
424 {
425 match self {
426 Ok(cv) => Some(cv.gather_warnings_into(warnings)),
427 Err(err_set) => {
428 warnings.deescalate_error(err_set.into_other());
429 None
430 }
431 }
432 }
433}
434
435impl<T, W> DeescalateError<T, W> for Result<T, ErrorSet<W>>
437where
438 W: Warning,
439{
440 fn deescalate_error_into<WA>(self, warnings: &mut Set<WA>) -> Option<T>
443 where
444 W: Into<WA>,
445 WA: Warning,
446 {
447 match self {
448 Ok(cv) => Some(cv),
449 Err(err_set) => {
450 warnings.deescalate_error(err_set.into_other());
451 None
452 }
453 }
454 }
455}
456
457impl<T, W> GatherWarnings<T, W> for Vec<Caveat<T, W>>
459where
460 W: Warning,
461{
462 type Output = Vec<T>;
463
464 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
466 where
467 W: Into<WA>,
468 WA: Warning,
469 {
470 self.into_iter()
471 .map(|cv| cv.gather_warnings_into(warnings))
472 .collect()
473 }
474}
475
476pub(crate) trait GatherDeferredWarnings<T, W>
481where
482 W: Warning,
483{
484 type Output;
486
487 #[must_use = "If you want to ignore the value use `let _ =`"]
489 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
490 where
491 W: Into<WA>,
492 WA: Warning;
493}
494
495impl<T, W> GatherDeferredWarnings<T, W> for CaveatDeferred<T, W>
497where
498 W: Warning,
499{
500 type Output = T;
501
502 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
504 where
505 W: Into<WA>,
506 WA: Warning,
507 {
508 let Self {
509 value,
510 warnings: inner_warnings,
511 } = self;
512
513 warnings.extend(inner_warnings);
514
515 value
516 }
517}
518
519impl<T, W> GatherDeferredWarnings<T, W> for Option<CaveatDeferred<T, W>>
521where
522 W: Warning,
523{
524 type Output = Option<T>;
525
526 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
528 where
529 W: Into<WA>,
530 WA: Warning,
531 {
532 match self {
533 Some(cv) => Some(cv.gather_deferred_warnings_into(warnings)),
534 None => None,
535 }
536 }
537}
538
539impl<T, W, E> GatherDeferredWarnings<T, W> for Result<CaveatDeferred<T, W>, E>
541where
542 W: Warning,
543 E: std::error::Error,
544{
545 type Output = Result<T, E>;
546
547 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
549 where
550 W: Into<WA>,
551 WA: Warning,
552 {
553 match self {
554 Ok(cv) => Ok(cv.gather_deferred_warnings_into(warnings)),
555 Err(err) => Err(err),
556 }
557 }
558}
559
560impl<T, W> GatherDeferredWarnings<T, W> for VerdictDeferred<T, W>
562where
563 W: Warning,
564{
565 type Output = Result<T, ErrorSetDeferred<W>>;
566
567 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
570 where
571 W: Into<WA>,
572 WA: Warning,
573 {
574 match self {
575 Ok(cv) => Ok(cv.gather_deferred_warnings_into(warnings)),
576 Err(err_set) => Err(err_set),
577 }
578 }
579}
580
581impl<T, W> GatherDeferredWarnings<T, W> for Vec<CaveatDeferred<T, W>>
583where
584 W: Warning,
585{
586 type Output = Vec<T>;
587
588 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
590 where
591 W: Into<WA>,
592 WA: Warning,
593 {
594 self.into_iter()
595 .map(|cv| cv.gather_deferred_warnings_into(warnings))
596 .collect()
597 }
598}
599
600pub trait IntoCaveat: Sized {
604 fn into_caveat<W: Warning>(self, warnings: Set<W>) -> Caveat<Self, W>;
606}
607
608pub(crate) trait IntoCaveatDeferred: Sized {
612 fn into_caveat_deferred<W: Warning>(self, warnings: SetDeferred<W>) -> CaveatDeferred<Self, W>;
614}
615
616impl<T> IntoCaveat for T {
618 fn into_caveat<W: Warning>(self, warnings: Set<W>) -> Caveat<Self, W> {
619 Caveat::new(self, warnings)
620 }
621}
622
623impl<T> IntoCaveatDeferred for T {
625 fn into_caveat_deferred<W: Warning>(self, warnings: SetDeferred<W>) -> CaveatDeferred<Self, W> {
626 CaveatDeferred::new(self, warnings)
627 }
628}
629
630pub trait VerdictExt<T, W: Warning> {
632 fn map_caveat<F, U>(self, op: F) -> Verdict<U, W>
635 where
636 F: FnOnce(T) -> U;
637
638 fn only_error(self) -> Result<Caveat<T, W>, Error<W>>;
640}
641
642#[expect(dead_code, reason = "for debugging")]
644pub(crate) trait VerdictTrace<T, W: Warning> {
645 fn info_verdict(self, msg: &'static str) -> Self;
647
648 fn debug_verdict(self, msg: &'static str) -> Self;
650}
651
652#[expect(dead_code, reason = "for debugging")]
654pub(crate) trait ResultTrace<T, W: Warning> {
655 fn info_result(self, msg: &'static str) -> Self;
657
658 fn debug_result(self, msg: &'static str) -> Self;
660}
661
662impl<T, W: Warning> VerdictExt<T, W> for Verdict<T, W> {
663 fn map_caveat<F, U>(self, op: F) -> Verdict<U, W>
664 where
665 F: FnOnce(T) -> U,
666 {
667 match self {
668 Ok(c) => Ok(c.map(op)),
669 Err(w) => Err(w),
670 }
671 }
672
673 fn only_error(self) -> Result<Caveat<T, W>, Error<W>> {
674 match self {
675 Ok(c) => Ok(c),
676 Err(err_set) => {
677 let ErrorSet { error, warnings: _ } = err_set;
678 Err(*error)
679 }
680 }
681 }
682}
683
684impl<T, W: Warning> VerdictTrace<T, W> for Verdict<T, W>
685where
686 T: fmt::Debug,
687{
688 fn info_verdict(self, msg: &'static str) -> Self {
689 match self {
690 Ok(c) => {
691 info!("{msg}: {c:#?}");
692 Ok(c)
693 }
694 Err(err_set) => {
695 info!("{msg}: {err_set:#?}");
696 Err(err_set)
697 }
698 }
699 }
700
701 fn debug_verdict(self, msg: &'static str) -> Self {
702 match self {
703 Ok(c) => {
704 debug!("{msg}: {c:#?}");
705 Ok(c)
706 }
707 Err(err_set) => {
708 debug!("{msg}: {err_set:#?}");
709 Err(err_set)
710 }
711 }
712 }
713}
714
715impl<T, W: Warning> ResultTrace<T, W> for Result<T, ErrorSet<W>>
716where
717 T: fmt::Debug,
718{
719 fn info_result(self, msg: &'static str) -> Self {
720 match self {
721 Ok(c) => {
722 info!("{msg}: {c:#?}");
723 Ok(c)
724 }
725 Err(err_set) => {
726 info!("{msg}: {err_set:#?}");
727 Err(err_set)
728 }
729 }
730 }
731
732 fn debug_result(self, msg: &'static str) -> Self {
733 match self {
734 Ok(c) => {
735 debug!("{msg}: {c:#?}");
736 Ok(c)
737 }
738 Err(err_set) => {
739 debug!("{msg}: {err_set:#?}");
740 Err(err_set)
741 }
742 }
743 }
744}
745
746#[derive(Debug)]
750pub struct Error<W: Warning> {
751 warning: W,
753
754 element: Element,
756}
757
758impl<W: Warning> Error<W> {
759 pub fn warning(&self) -> &W {
761 &self.warning
762 }
763
764 pub fn into_warning(self) -> W {
766 self.warning
767 }
768
769 pub fn element(&self) -> &Element {
771 &self.element
772 }
773
774 pub fn parts(&self) -> (&W, &Element) {
776 (&self.warning, &self.element)
777 }
778
779 pub fn into_parts(self) -> (W, Element) {
781 let Self { warning, element } = self;
782 (warning, element)
783 }
784
785 fn into_other<WA>(self) -> Error<WA>
789 where
790 W: Into<WA>,
791 WA: Warning,
792 {
793 let Self { warning, element } = self;
794 Error {
795 warning: warning.into(),
796 element,
797 }
798 }
799}
800
801impl<W: Warning> std::error::Error for Error<W> {}
802
803impl<W: Warning> fmt::Display for Error<W> {
804 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
805 write!(
806 f,
807 "A warning for element at `{}` was upgraded to an `error`: {}",
808 self.element.path, self.warning
809 )
810 }
811}
812
813pub trait WithElement<T, W: Warning> {
815 fn with_element(self, element: &json::Element<'_>) -> Verdict<T, W>;
816}
817
818impl<T, W: Warning> WithElement<T, W> for VerdictDeferred<T, W> {
819 fn with_element(self, element: &json::Element<'_>) -> Verdict<T, W> {
821 match self {
822 Ok(v) => {
823 let CaveatDeferred { value, warnings } = v;
824 let SetDeferred(warnings) = warnings;
825 let warnings = if warnings.is_empty() {
826 BTreeMap::new()
827 } else {
828 let warnings = Group {
829 element: element.into(),
830 warnings,
831 };
832 BTreeMap::from([(element.id(), warnings)])
833 };
834
835 Ok(Caveat {
836 value,
837 warnings: Set(warnings),
838 })
839 }
840 Err(set) => {
841 let ErrorSetDeferred { error, warnings } = set;
842 let warnings = Group {
844 element: element.into(),
845 warnings,
846 };
847 let warnings = BTreeMap::from([(element.id(), warnings)]);
848 Err(ErrorSet {
849 error: Box::new(Error {
850 warning: error,
851 element: Element::from(element),
852 }),
853 warnings,
854 })
855 }
856 }
857 }
858}
859
860#[derive(Debug)]
870pub struct Element {
871 id: json::ElemId,
875
876 span: json::parser::Span,
878
879 path: Path,
883}
884
885impl Element {
886 pub fn span(&self) -> json::parser::Span {
887 self.span
888 }
889
890 pub fn path(&self) -> &Path {
891 &self.path
892 }
893
894 pub fn into_parts(self) -> (json::parser::Span, Path) {
895 let Self { id: _, span, path } = self;
896 (span, path)
897 }
898}
899
900impl<'buf> From<&json::Element<'buf>> for Element {
901 fn from(elem: &json::Element<'buf>) -> Self {
902 Self {
903 id: elem.id(),
904 span: elem.span(),
905 path: Path(elem.path().to_string()),
906 }
907 }
908}
909
910pub struct SourceReportIter<'caller, 'buf, W: Warning> {
912 report_iter: Iter<'caller, W>,
914
915 json: &'buf str,
917}
918
919impl<'caller, 'buf, W: Warning> SourceReportIter<'caller, 'buf, W> {
920 pub fn new(json: &'buf str, report_iter: Iter<'caller, W>) -> Self {
922 Self { report_iter, json }
923 }
924}
925
926impl<'caller, 'buf, W: Warning> Iterator for SourceReportIter<'caller, 'buf, W> {
927 type Item = ElementReport<'caller, 'buf, W>;
928
929 #[expect(
930 clippy::string_slice,
931 reason = "The disconnection between the source JSON and the `Element` will be fixed in a future PR"
932 )]
933 fn next(&mut self) -> Option<Self::Item> {
934 let group = self.report_iter.next()?;
935 let (element, warnings) = group.to_parts();
936
937 let lead_in = &self.json[..element.span.start];
939 let json::LineCol { line, col } = json::line_col(lead_in);
941 let json = &self.json[element.span.start..element.span.end];
942
943 Some(ElementReport {
944 element_path: element.path(),
945 warnings,
946 json,
947 location: json::LineCol {
948 line,
949 col: col.saturating_add(1),
950 },
951 })
952 }
953}
954
955#[derive(Debug)]
956pub struct ElementReport<'caller, 'buf, W: Warning> {
957 pub element_path: &'caller Path,
959
960 pub warnings: Vec<&'caller W>,
962
963 pub json: &'buf str,
965
966 pub location: json::LineCol,
968}
969
970pub struct SetWriter<'caller, W: Warning> {
984 warnings: &'caller Set<W>,
986
987 indent: &'caller str,
989}
990
991impl<'caller, W: Warning> SetWriter<'caller, W> {
992 pub fn new(warnings: &'caller Set<W>) -> Self {
994 Self {
995 warnings,
996 indent: " - ",
997 }
998 }
999
1000 pub fn with_indent(warnings: &'caller Set<W>, indent: &'caller str) -> Self {
1002 Self { warnings, indent }
1003 }
1004}
1005
1006impl<W: Warning> fmt::Debug for SetWriter<'_, W> {
1007 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1008 fmt::Display::fmt(self, f)
1009 }
1010}
1011
1012impl<W: Warning> fmt::Display for SetWriter<'_, W> {
1013 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1014 let mut iter = self.warnings.iter();
1015
1016 {
1017 let Some((element, warnings)) = iter.next().map(|g| g.to_parts()) else {
1019 return Ok(());
1020 };
1021
1022 writeln!(f, "{}", element.path)?;
1023
1024 for warning in warnings {
1025 write!(f, "{}{}", self.indent, warning)?;
1026 }
1027 }
1028
1029 for (element, warnings) in iter.map(|g| g.to_parts()) {
1031 writeln!(f, "\n{}", element.path)?;
1032
1033 for warning in warnings {
1034 write!(f, "{}{}", self.indent, warning)?;
1035 }
1036 }
1037
1038 Ok(())
1039 }
1040}
1041
1042pub trait Warning: Sized + fmt::Debug + fmt::Display + Send + Sync {
1046 fn id(&self) -> Id;
1051}
1052
1053#[derive(Debug)]
1055struct Source<W: Warning> {
1056 #[cfg(test)]
1057 location: &'static std::panic::Location<'static>,
1059
1060 warning: W,
1062}
1063
1064impl<W: Warning> Source<W> {
1065 #[track_caller]
1066 fn new(warning: W) -> Self {
1068 #[cfg(test)]
1069 {
1070 Self {
1071 location: std::panic::Location::caller(),
1072 warning,
1073 }
1074 }
1075
1076 #[expect(
1077 clippy::cfg_not_test,
1078 reason = "This is code that is designed for use in tests"
1079 )]
1080 #[cfg(not(test))]
1081 {
1082 Self { warning }
1083 }
1084 }
1085
1086 fn into_warning(self) -> W {
1088 self.warning
1089 }
1090
1091 fn into_other<WA>(self) -> Source<WA>
1093 where
1094 W: Into<WA>,
1095 WA: Warning,
1096 {
1097 self.map(Into::into)
1098 }
1099
1100 fn map<F, WA>(self, mut f: F) -> Source<WA>
1102 where
1103 F: FnMut(W) -> WA,
1104 WA: Warning,
1105 {
1106 #[cfg(test)]
1107 {
1108 let Self {
1109 location: source,
1110 warning,
1111 } = self;
1112 Source {
1113 location: source,
1114 warning: f(warning),
1115 }
1116 }
1117
1118 #[expect(
1119 clippy::cfg_not_test,
1120 reason = "This is code that is designed for use in tests"
1121 )]
1122 #[cfg(not(test))]
1123 {
1124 let Self { warning } = self;
1125 Source {
1126 warning: f(warning),
1127 }
1128 }
1129 }
1130}
1131
1132impl<W: Warning> Deref for Source<W> {
1133 type Target = W;
1134
1135 fn deref(&self) -> &Self::Target {
1136 &self.warning
1137 }
1138}
1139
1140#[derive(Debug)]
1149pub(crate) struct SetDeferred<W: Warning>(Vec<Source<W>>);
1150
1151impl<W: Warning> SetDeferred<W> {
1152 pub(crate) fn new() -> Self {
1154 Self(Vec::new())
1155 }
1156
1157 #[track_caller]
1161 pub(crate) fn bail<T>(self, warning: W) -> VerdictDeferred<T, W> {
1162 let Self(warnings) = self;
1163 Err(ErrorSetDeferred {
1164 error: warning,
1165 warnings,
1166 })
1167 }
1168
1169 fn extend<WA>(&mut self, warnings: SetDeferred<WA>)
1173 where
1174 WA: Into<W> + Warning,
1175 {
1176 let SetDeferred(warnings) = warnings;
1177 self.0.extend(warnings.into_iter().map(Source::into_other));
1178 }
1179}
1180
1181#[derive(Debug)]
1191pub struct ErrorSetDeferred<W: Warning> {
1192 error: W,
1194
1195 warnings: Vec<Source<W>>,
1197}
1198
1199impl<W: Warning> ErrorSetDeferred<W> {
1200 pub(crate) fn with_warn(warning: W) -> Self {
1202 Self {
1203 warnings: Vec::new(),
1204 error: warning,
1205 }
1206 }
1207
1208 pub(crate) fn into_other<WA>(self) -> ErrorSetDeferred<WA>
1212 where
1213 W: Into<WA>,
1214 WA: Warning,
1215 {
1216 let Self { error, warnings } = self;
1217 let warnings = warnings.into_iter().map(Source::into_other).collect();
1218 ErrorSetDeferred {
1219 error: error.into(),
1220 warnings,
1221 }
1222 }
1223}
1224
1225#[derive(Debug)]
1227pub struct Set<W: Warning>(BTreeMap<json::ElemId, Group<W>>);
1228
1229impl<W: Warning> Set<W> {
1230 pub(crate) fn new() -> Self {
1232 Self(BTreeMap::new())
1233 }
1234
1235 pub(crate) fn into_inner(self) -> BTreeMap<json::ElemId, Group<W>> {
1237 self.0
1238 }
1239
1240 #[track_caller]
1242 pub(crate) fn insert(&mut self, warning: W, element: &json::Element<'_>) {
1243 self.insert_warning(warning, element.id(), || Element::from(element));
1244 }
1245
1246 #[track_caller]
1250 fn insert_warning<F>(&mut self, warning: W, elem_id: json::ElemId, f: F)
1251 where
1252 F: FnOnce() -> Element,
1253 {
1254 use std::collections::btree_map::Entry;
1255
1256 match self.0.entry(elem_id) {
1257 Entry::Vacant(entry) => {
1258 let element = f();
1259 entry.insert_entry(Group {
1260 element,
1261 warnings: vec![Source::new(warning)],
1262 });
1263 }
1264 Entry::Occupied(mut entry) => {
1265 entry.get_mut().warnings.push(Source::new(warning));
1266 }
1267 }
1268 }
1269
1270 #[track_caller]
1274 pub(crate) fn bail<T>(self, warning: W, element: &json::Element<'_>) -> Verdict<T, W> {
1275 let Self(warnings) = self;
1276
1277 Err(ErrorSet {
1278 error: Box::new(Error {
1279 warning,
1280 element: Element::from(element),
1281 }),
1282 warnings,
1283 })
1284 }
1285
1286 pub(crate) fn into_other<WA>(self) -> Set<WA>
1290 where
1291 W: Into<WA>,
1292 WA: Warning,
1293 {
1294 let Set(warnings) = self;
1295 let warnings = warnings
1296 .into_iter()
1297 .map(|(elem_id, group)| (elem_id, group.into_other()))
1298 .collect();
1299 Set(warnings)
1300 }
1301
1302 pub fn is_empty(&self) -> bool {
1304 self.0.is_empty()
1305 }
1306
1307 pub fn len_elements(&self) -> usize {
1311 self.0.len()
1312 }
1313
1314 pub fn len_warnings(&self) -> usize {
1316 self.0
1317 .values()
1318 .fold(0, |acc, group| acc.saturating_add(group.warnings.len()))
1319 }
1320
1321 pub fn iter(&self) -> Iter<'_, W> {
1323 Iter {
1324 warnings: self.0.iter(),
1325 }
1326 }
1327
1328 pub fn id_path_map(&self, config: Limit) -> IdPathMap<'_> {
1330 let report = match config {
1331 Limit::None => limit_none(&self.0),
1332 Limit::WarningTypes(max_warning_types) => {
1333 limit_warning_types(max_warning_types, &self.0)
1334 }
1335 Limit::ElemPathsPerId(max_elem_paths_per_warning_id) => {
1336 limit_elem_paths_per_id(max_elem_paths_per_warning_id, &self.0)
1337 }
1338 Limit::All {
1339 max_warning_types,
1340 max_elem_paths_per_warning_id,
1341 } => limit_all(max_warning_types, max_elem_paths_per_warning_id, &self.0),
1342 };
1343
1344 let LimitReport {
1345 elements_filtered,
1346 warning_distinct_types_filtered,
1347 warnings,
1348 } = report;
1349
1350 IdPathMap {
1351 total_warnings: self.len_warnings(),
1352 total_elements: self.len_elements(),
1353 elements_filtered,
1354 warning_distinct_types_filtered,
1355 warnings,
1356 }
1357 }
1358
1359 pub fn msg_path_map(&self, config: Limit) -> MsgPathMap<'_> {
1361 let IdPathMap {
1362 total_warnings,
1363 total_elements,
1364 elements_filtered,
1365 warning_distinct_types_filtered,
1366 warnings,
1367 } = self.id_path_map(config);
1368
1369 let warnings = warnings
1370 .into_iter()
1371 .map(|(id, paths)| (id.to_string(), paths))
1372 .collect();
1373
1374 MsgPathMap {
1375 total_warnings,
1376 total_elements,
1377 elements_filtered,
1378 warning_distinct_types_filtered,
1379 warnings,
1380 }
1381 }
1382
1383 pub fn path_map(&self) -> BTreeMap<&str, Vec<&W>> {
1389 self.0
1390 .values()
1391 .map(|Group { element, warnings }| {
1392 let path = element.path.as_str();
1393 let warnings = warnings.iter().map(|w| &**w).collect();
1394 (path, warnings)
1395 })
1396 .collect()
1397 }
1398
1399 pub fn into_path_map(self) -> BTreeMap<Path, Vec<W>> {
1403 self.0
1404 .into_values()
1405 .map(|Group { element, warnings }| {
1406 let warnings = warnings.into_iter().map(Source::into_warning).collect();
1407 (element.path, warnings)
1408 })
1409 .collect()
1410 }
1411
1412 pub fn path_id_map(&self) -> BTreeMap<&str, Vec<Id>> {
1421 self.0
1422 .values()
1423 .map(|group| {
1424 let warnings = group.warnings.iter().map(|w| w.id()).collect();
1425 (group.element.path.as_str(), warnings)
1426 })
1427 .collect()
1428 }
1429
1430 pub fn path_msg_map(&self) -> BTreeMap<&str, Vec<String>> {
1436 self.0
1437 .values()
1438 .map(|group| {
1439 let warnings = group.warnings.iter().map(|w| w.to_string()).collect();
1440 (group.element.path.as_str(), warnings)
1441 })
1442 .collect()
1443 }
1444
1445 pub(crate) fn deescalate_error(&mut self, err_set: ErrorSet<W>) {
1447 let ErrorSet { error, warnings } = err_set;
1448 let Error { warning, element } = *error;
1449 self.0.extend(warnings);
1450 self.insert_warning(warning, element.id, || element);
1451 }
1452
1453 pub(crate) fn extend(&mut self, warnings: impl Iterator<Item = (json::ElemId, Group<W>)>) {
1457 use std::collections::btree_map::Entry;
1458
1459 for (elem_id, group) in warnings {
1460 match self.0.entry(elem_id) {
1461 Entry::Vacant(entry) => {
1462 entry.insert_entry(group);
1463 }
1464 Entry::Occupied(mut entry) => {
1465 let Group {
1466 element: _,
1467 warnings,
1468 } = group;
1469 entry.get_mut().warnings.extend(warnings);
1470 }
1471 }
1472 }
1473 }
1474}
1475
1476#[derive(Debug)]
1478struct LimitReport<'set> {
1479 pub elements_filtered: usize,
1481
1482 pub warning_distinct_types_filtered: usize,
1488
1489 pub warnings: BTreeMap<Id, Vec<&'set str>>,
1491}
1492
1493fn limit_none<W: Warning>(warnings: &BTreeMap<json::ElemId, Group<W>>) -> LimitReport<'_> {
1495 let mut out = BTreeMap::new();
1496
1497 for group in warnings.values() {
1498 let Group { element, warnings } = group;
1499 let path = element.path.as_str();
1500
1501 for w in warnings {
1502 match out.entry(w.id()) {
1503 btree_map::Entry::Vacant(entry) => {
1504 entry.insert(vec![path]);
1505 }
1506 btree_map::Entry::Occupied(mut entry) => {
1507 entry.get_mut().push(path);
1508 }
1509 }
1510 }
1511 }
1512
1513 LimitReport {
1514 warnings: out,
1515 elements_filtered: 0,
1516 warning_distinct_types_filtered: 0,
1517 }
1518}
1519
1520fn limit_warning_types<W: Warning>(
1522 max_warning_types: usize,
1523 warnings: &BTreeMap<json::ElemId, Group<W>>,
1524) -> LimitReport<'_> {
1525 let mut out = BTreeMap::new();
1526 let mut elements_filtered = HashSet::new();
1529 let mut warning_distinct_types_filtered = HashSet::new();
1532
1533 for group in warnings.values() {
1534 let Group { element, warnings } = group;
1535 let path = element.path.as_str();
1536 let mut filtered = false;
1539
1540 for w in warnings {
1541 let len = out.len();
1542 let id = w.id();
1543
1544 match out.entry(id.clone()) {
1545 btree_map::Entry::Vacant(entry) => {
1546 if len < max_warning_types {
1547 entry.insert(vec![path]);
1548 } else {
1549 warning_distinct_types_filtered.insert(id);
1550 filtered = true;
1551 }
1552 }
1553 btree_map::Entry::Occupied(mut entry) => {
1554 entry.get_mut().push(path);
1555 }
1556 }
1557 }
1558
1559 if filtered {
1560 elements_filtered.insert(path);
1561 }
1562 }
1563
1564 LimitReport {
1565 warnings: out,
1566 elements_filtered: elements_filtered.len(),
1567 warning_distinct_types_filtered: warning_distinct_types_filtered.len(),
1568 }
1569}
1570
1571fn limit_elem_paths_per_id<W: Warning>(
1573 max_elem_paths_per_warning_id: usize,
1574 warnings: &BTreeMap<json::ElemId, Group<W>>,
1575) -> LimitReport<'_> {
1576 let mut out = BTreeMap::new();
1577 let mut elements_filtered = HashSet::new();
1580
1581 if max_elem_paths_per_warning_id == 0 {
1582 for group in warnings.values() {
1583 let Group { element, warnings } = group;
1584
1585 for w in warnings {
1586 if let btree_map::Entry::Vacant(entry) = out.entry(w.id()) {
1587 entry.insert(vec![]);
1588 }
1589 }
1590 elements_filtered.insert(element.path.as_str());
1591 }
1592 } else {
1593 for group in warnings.values() {
1594 let Group { element, warnings } = group;
1595 let path = element.path.as_str();
1596
1597 for w in warnings {
1598 let id = w.id();
1599
1600 match out.entry(id.clone()) {
1601 btree_map::Entry::Vacant(entry) => {
1602 entry.insert(vec![path]);
1603 }
1604 btree_map::Entry::Occupied(mut entry) => {
1605 if entry.get().len() < max_elem_paths_per_warning_id {
1606 entry.get_mut().push(path);
1607 } else {
1608 elements_filtered.insert(path);
1609 }
1611 }
1612 }
1613 }
1614 }
1615 }
1616
1617 LimitReport {
1618 warnings: out,
1619 elements_filtered: elements_filtered.len(),
1620 warning_distinct_types_filtered: 0,
1621 }
1622}
1623
1624fn limit_all<W: Warning>(
1626 max_warning_types: usize,
1627 max_elem_paths_per_warning_id: usize,
1628 warnings: &BTreeMap<json::ElemId, Group<W>>,
1629) -> LimitReport<'_> {
1630 let mut out = BTreeMap::new();
1631 let mut elements_filtered = HashSet::new();
1634 let mut warning_distinct_types_filtered = HashSet::new();
1637
1638 if max_warning_types > 0 && max_elem_paths_per_warning_id == 0 {
1639 for group in warnings.values() {
1640 let Group { element, warnings } = group;
1641 let path = element.path.as_str();
1642
1643 for w in warnings {
1644 let len = out.len();
1645 let id = w.id();
1646
1647 if let btree_map::Entry::Vacant(entry) = out.entry(id.clone()) {
1648 if len < max_warning_types {
1649 entry.insert(vec![]);
1650 } else {
1651 warning_distinct_types_filtered.insert(id);
1652 }
1653 }
1654 }
1655
1656 elements_filtered.insert(path);
1657 }
1658 } else {
1659 for group in warnings.values() {
1660 let Group { element, warnings } = group;
1661 let path = element.path.as_str();
1662
1663 for w in warnings {
1664 let len = out.len();
1665 let id = w.id();
1666
1667 match out.entry(id.clone()) {
1668 btree_map::Entry::Vacant(entry) => {
1669 if len < max_warning_types {
1670 entry.insert(vec![path]);
1671 } else {
1672 warning_distinct_types_filtered.insert(id);
1673 elements_filtered.insert(path);
1674 }
1675 }
1676 btree_map::Entry::Occupied(mut entry) => {
1677 if entry.get().len() < max_elem_paths_per_warning_id {
1678 entry.get_mut().push(path);
1679 } else {
1680 elements_filtered.insert(path);
1681 }
1682 }
1683 }
1684 }
1685 }
1686 }
1687
1688 LimitReport {
1689 warnings: out,
1690 elements_filtered: elements_filtered.len(),
1691 warning_distinct_types_filtered: warning_distinct_types_filtered.len(),
1692 }
1693}
1694
1695#[derive(Debug)]
1697pub struct IdPathMap<'set> {
1698 pub total_warnings: usize,
1700
1701 pub total_elements: usize,
1703
1704 pub elements_filtered: usize,
1706
1707 pub warning_distinct_types_filtered: usize,
1713
1714 pub warnings: BTreeMap<Id, Vec<&'set str>>,
1716}
1717
1718#[derive(Debug)]
1720pub struct MsgPathMap<'set> {
1721 pub total_warnings: usize,
1723
1724 pub total_elements: usize,
1726
1727 pub elements_filtered: usize,
1729
1730 pub warning_distinct_types_filtered: usize,
1736
1737 pub warnings: BTreeMap<String, Vec<&'set str>>,
1739}
1740
1741#[derive(Copy, Clone, Debug)]
1743pub enum Limit {
1744 None,
1746
1747 WarningTypes(usize),
1749
1750 ElemPathsPerId(usize),
1752
1753 All {
1754 max_warning_types: usize,
1756
1757 max_elem_paths_per_warning_id: usize,
1759 },
1760}
1761
1762#[derive(Debug)]
1766pub struct ErrorSet<W: Warning> {
1767 error: Box<Error<W>>,
1771
1772 warnings: BTreeMap<json::ElemId, Group<W>>,
1776}
1777
1778impl<W> ErrorSet<W>
1779where
1780 W: Warning,
1781{
1782 pub(crate) fn with_warn(warning: W, element: &json::Element<'_>) -> Self {
1784 Self {
1785 warnings: BTreeMap::new(),
1786 error: Box::new(Error {
1787 warning,
1788 element: Element::from(element),
1789 }),
1790 }
1791 }
1792
1793 pub fn into_parts(self) -> (Error<W>, Set<W>) {
1795 let Self { error, warnings } = self;
1796 (*error, Set(warnings))
1797 }
1798
1799 pub(crate) fn into_other<WA>(self) -> ErrorSet<WA>
1803 where
1804 W: Into<WA>,
1805 WA: Warning,
1806 {
1807 let Self { error, warnings } = self;
1808 let warnings = warnings
1809 .into_iter()
1810 .map(|(elem_id, group)| (elem_id, group.into_other()))
1811 .collect();
1812 ErrorSet {
1813 error: Box::new(Error::into_other(*error)),
1814 warnings,
1815 }
1816 }
1817}
1818
1819#[derive(Debug)]
1824pub struct Group<W: Warning> {
1825 element: Element,
1827
1828 warnings: Vec<Source<W>>,
1830}
1831
1832impl<W> Group<W>
1833where
1834 W: Warning,
1835{
1836 pub fn into_parts(self) -> (Element, Vec<W>) {
1838 let Self { element, warnings } = self;
1839 let warnings = warnings.into_iter().map(Source::into_warning).collect();
1840 (element, warnings)
1841 }
1842
1843 pub(crate) fn map<F, WA>(self, mut f: F) -> Group<WA>
1845 where
1846 F: FnMut(W) -> WA,
1847 WA: Warning,
1848 {
1849 let Self { element, warnings } = self;
1850 let warnings = warnings
1851 .into_iter()
1852 .map(|source| source.map(&mut f))
1853 .collect();
1854 Group { element, warnings }
1855 }
1856
1857 pub fn to_parts(&self) -> (&Element, Vec<&W>) {
1858 let Self { element, warnings } = self;
1859 let warnings = warnings.iter().map(|w| &**w).collect();
1860 (element, warnings)
1861 }
1862
1863 pub fn warnings(&self) -> Vec<&W> {
1864 self.warnings.iter().map(|w| &**w).collect()
1865 }
1866
1867 pub fn into_warnings(self) -> Vec<W> {
1868 let Self {
1869 element: _,
1870 warnings,
1871 } = self;
1872 warnings.into_iter().map(Source::into_warning).collect()
1873 }
1874
1875 fn into_other<WA>(self) -> Group<WA>
1879 where
1880 W: Into<WA>,
1881 WA: Warning,
1882 {
1883 let Self { element, warnings } = self;
1884 let warnings = warnings.into_iter().map(Source::into_other).collect();
1885 Group { element, warnings }
1886 }
1887}
1888
1889pub struct Iter<'caller, W>
1891where
1892 W: Warning,
1893{
1894 warnings: btree_map::Iter<'caller, json::ElemId, Group<W>>,
1896}
1897
1898impl<W> Iter<'_, W> where W: Warning {}
1899
1900impl<'caller, W: Warning> Iterator for Iter<'caller, W> {
1901 type Item = &'caller Group<W>;
1902
1903 fn next(&mut self) -> Option<Self::Item> {
1904 let (_elem_id, group) = self.warnings.next()?;
1905 Some(group)
1906 }
1907}
1908
1909pub struct IntoIter<W>
1911where
1912 W: Warning,
1913{
1914 warnings: btree_map::IntoIter<json::ElemId, Group<W>>,
1916}
1917
1918impl<W: Warning> Iterator for IntoIter<W> {
1919 type Item = Group<W>;
1920
1921 fn next(&mut self) -> Option<Self::Item> {
1922 let (_elem_id, group) = self.warnings.next()?;
1923 Some(group)
1924 }
1925}
1926
1927impl<W: Warning> IntoIterator for Set<W> {
1928 type Item = Group<W>;
1929 type IntoIter = IntoIter<W>;
1930
1931 fn into_iter(self) -> Self::IntoIter {
1932 let Set(warnings) = self;
1933 IntoIter {
1934 warnings: warnings.into_iter(),
1935 }
1936 }
1937}
1938
1939impl<'a, W: Warning> IntoIterator for &'a Set<W> {
1940 type Item = &'a Group<W>;
1941 type IntoIter = Iter<'a, W>;
1942
1943 fn into_iter(self) -> Self::IntoIter {
1944 self.iter()
1945 }
1946}