1#[cfg(test)]
47pub(crate) mod test;
48
49#[cfg(test)]
50mod test_group_by_elem;
51
52use std::{borrow::Cow, collections::BTreeMap, fmt, ops::Deref, vec};
53
54use tracing::{debug, info};
55
56use crate::json;
57
58#[doc(hidden)]
59#[macro_export]
60macro_rules! from_warning_all {
61 ($($source_kind:path => $target_kind:ident::$target_variant:ident),+) => {
62 $(
63 impl From<$source_kind> for $target_kind {
65 fn from(warning: $source_kind) -> Self {
66 $target_kind::$target_variant(warning)
67 }
68 }
69
70 impl From<$crate::warning::ErrorSet<$source_kind>> for $crate::warning::ErrorSet<$target_kind> {
75 fn from(set_a: $crate::warning::ErrorSet<$source_kind>) -> Self {
76 set_a.into_other()
77 }
78 }
79
80 impl From<$crate::warning::ErrorSetDeferred<$source_kind>> for $crate::warning::ErrorSetDeferred<$target_kind> {
85 fn from(set_a: $crate::warning::ErrorSetDeferred<$source_kind>) -> Self {
86 set_a.into_other()
87 }
88 }
89 )+
90 };
91}
92
93#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)]
94pub struct Id(Cow<'static, str>);
95
96impl Id {
97 pub(crate) fn from_static(s: &'static str) -> Self {
98 Self(s.into())
99 }
100
101 pub(crate) fn from_string(s: String) -> Self {
102 Self(s.into())
103 }
104
105 pub fn as_str(&self) -> &str {
106 &self.0
107 }
108}
109
110impl fmt::Debug for Id {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 fmt::Debug::fmt(&self.0, f)
113 }
114}
115
116impl fmt::Display for Id {
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 fmt::Display::fmt(&self.0, f)
119 }
120}
121
122#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)]
123pub struct Path(String);
124
125impl Path {
126 pub fn as_str(&self) -> &str {
127 &self.0
128 }
129}
130
131impl fmt::Debug for Path {
132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133 f.write_str(&self.0)
134 }
135}
136
137impl fmt::Display for Path {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 fmt::Display::fmt(&self.0, f)
140 }
141}
142
143pub type Verdict<T, W> = Result<Caveat<T, W>, ErrorSet<W>>;
145
146pub(crate) type VerdictDeferred<T, W> = Result<CaveatDeferred<T, W>, ErrorSetDeferred<W>>;
153
154#[derive(Debug)]
164pub(crate) struct CaveatDeferred<T, W: Warning> {
165 value: T,
167
168 warnings: SetDeferred<W>,
170}
171
172impl<T, W> CaveatDeferred<T, W>
173where
174 W: Warning,
175{
176 pub(crate) fn new(value: T, warnings: SetDeferred<W>) -> Self {
178 Self { value, warnings }
179 }
180}
181
182impl<T, W> Deref for CaveatDeferred<T, W>
197where
198 W: Warning,
199{
200 type Target = T;
201
202 fn deref(&self) -> &T {
203 &self.value
204 }
205}
206
207impl<T, W> CaveatDeferred<T, W>
208where
209 W: Warning,
210{
211 pub fn into_parts(self) -> (T, SetDeferred<W>) {
213 let Self { value, warnings } = self;
214 (value, warnings)
215 }
216}
217
218#[derive(Debug)]
222pub struct Caveat<T, W: Warning> {
223 value: T,
225
226 warnings: Set<W>,
228}
229
230impl<T, W> Caveat<T, W>
231where
232 W: Warning,
233{
234 pub(crate) fn new(value: T, warnings: Set<W>) -> Self {
236 Self { value, warnings }
237 }
238}
239
240impl<T, W> Deref for Caveat<T, W>
253where
254 W: Warning,
255{
256 type Target = T;
257
258 fn deref(&self) -> &T {
259 &self.value
260 }
261}
262
263impl<T, W> Caveat<T, W>
264where
265 W: Warning,
266{
267 pub fn into_parts(self) -> (T, Set<W>) {
269 let Self { value, warnings } = self;
270 (value, warnings)
271 }
272
273 pub fn ignore_warnings(self) -> T {
275 self.value
276 }
277
278 pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Caveat<U, W> {
280 let Self { value, warnings } = self;
281 Caveat {
282 value: op(value),
283 warnings,
284 }
285 }
286}
287
288pub(crate) trait GatherWarnings<T, W>
293where
294 W: Warning,
295{
296 type Output;
298
299 #[must_use = "If you want to ignore the value use `let _ =`"]
301 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
302 where
303 W: Into<WA>,
304 WA: Warning;
305}
306
307impl<T, W> GatherWarnings<T, W> for Caveat<T, W>
309where
310 W: Warning,
311{
312 type Output = T;
313
314 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
316 where
317 W: Into<WA>,
318 WA: Warning,
319 {
320 let Self {
321 value,
322 warnings: inner_warnings,
323 } = self;
324
325 let Set(inner_warnings) = inner_warnings;
326 let inner_warnings = inner_warnings
327 .into_iter()
328 .map(|(elem_id, group)| (elem_id, group.into_other()));
329
330 warnings.extend(inner_warnings);
331
332 value
333 }
334}
335
336impl<T, W> GatherWarnings<T, W> for Option<Caveat<T, W>>
338where
339 W: Warning,
340{
341 type Output = Option<T>;
342
343 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
345 where
346 W: Into<WA>,
347 WA: Warning,
348 {
349 match self {
350 Some(cv) => Some(cv.gather_warnings_into(warnings)),
351 None => None,
352 }
353 }
354}
355
356impl<T, W, E> GatherWarnings<T, W> for Result<Caveat<T, W>, E>
358where
359 W: Warning,
360 E: std::error::Error,
361{
362 type Output = Result<T, E>;
363
364 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
366 where
367 W: Into<WA>,
368 WA: Warning,
369 {
370 match self {
371 Ok(cv) => Ok(cv.gather_warnings_into(warnings)),
372 Err(err) => Err(err),
373 }
374 }
375}
376
377impl<T, W> GatherWarnings<T, W> for Verdict<T, W>
379where
380 W: Warning,
381{
382 type Output = Result<T, ErrorSet<W>>;
383
384 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
387 where
388 W: Into<WA>,
389 WA: Warning,
390 {
391 match self {
392 Ok(cv) => Ok(cv.gather_warnings_into(warnings)),
393 Err(err_set) => Err(err_set),
394 }
395 }
396}
397
398pub(crate) trait DeescalateError<T, W>
403where
404 W: Warning,
405{
406 #[must_use = "If you want to ignore the value use `let _ =`"]
408 fn deescalate_error_into<WA>(self, warnings: &mut Set<WA>) -> Option<T>
409 where
410 W: Into<WA>,
411 WA: Warning;
412}
413
414impl<T, W> DeescalateError<T, W> for Verdict<T, W>
416where
417 W: Warning,
418{
419 fn deescalate_error_into<WA>(self, warnings: &mut Set<WA>) -> Option<T>
422 where
423 W: Into<WA>,
424 WA: Warning,
425 {
426 match self {
427 Ok(cv) => Some(cv.gather_warnings_into(warnings)),
428 Err(err_set) => {
429 warnings.deescalate_error(err_set.into_other());
430 None
431 }
432 }
433 }
434}
435
436impl<T, W> DeescalateError<T, W> for Result<T, ErrorSet<W>>
438where
439 W: Warning,
440{
441 fn deescalate_error_into<WA>(self, warnings: &mut Set<WA>) -> Option<T>
444 where
445 W: Into<WA>,
446 WA: Warning,
447 {
448 match self {
449 Ok(cv) => Some(cv),
450 Err(err_set) => {
451 warnings.deescalate_error(err_set.into_other());
452 None
453 }
454 }
455 }
456}
457
458impl<T, W> GatherWarnings<T, W> for Vec<Caveat<T, W>>
460where
461 W: Warning,
462{
463 type Output = Vec<T>;
464
465 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
467 where
468 W: Into<WA>,
469 WA: Warning,
470 {
471 self.into_iter()
472 .map(|cv| cv.gather_warnings_into(warnings))
473 .collect()
474 }
475}
476
477pub(crate) trait GatherDeferredWarnings<T, W>
482where
483 W: Warning,
484{
485 type Output;
487
488 #[must_use = "If you want to ignore the value use `let _ =`"]
490 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
491 where
492 W: Into<WA>,
493 WA: Warning;
494}
495
496impl<T, W> GatherDeferredWarnings<T, W> for CaveatDeferred<T, W>
498where
499 W: Warning,
500{
501 type Output = T;
502
503 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
505 where
506 W: Into<WA>,
507 WA: Warning,
508 {
509 let Self {
510 value,
511 warnings: inner_warnings,
512 } = self;
513
514 warnings.extend(inner_warnings);
515
516 value
517 }
518}
519
520impl<T, W> GatherDeferredWarnings<T, W> for Option<CaveatDeferred<T, W>>
522where
523 W: Warning,
524{
525 type Output = Option<T>;
526
527 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
529 where
530 W: Into<WA>,
531 WA: Warning,
532 {
533 match self {
534 Some(cv) => Some(cv.gather_deferred_warnings_into(warnings)),
535 None => None,
536 }
537 }
538}
539
540impl<T, W, E> GatherDeferredWarnings<T, W> for Result<CaveatDeferred<T, W>, E>
542where
543 W: Warning,
544 E: std::error::Error,
545{
546 type Output = Result<T, E>;
547
548 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
550 where
551 W: Into<WA>,
552 WA: Warning,
553 {
554 match self {
555 Ok(cv) => Ok(cv.gather_deferred_warnings_into(warnings)),
556 Err(err) => Err(err),
557 }
558 }
559}
560
561impl<T, W> GatherDeferredWarnings<T, W> for VerdictDeferred<T, W>
563where
564 W: Warning,
565{
566 type Output = Result<T, ErrorSetDeferred<W>>;
567
568 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
571 where
572 W: Into<WA>,
573 WA: Warning,
574 {
575 match self {
576 Ok(cv) => Ok(cv.gather_deferred_warnings_into(warnings)),
577 Err(err_set) => Err(err_set),
578 }
579 }
580}
581
582impl<T, W> GatherDeferredWarnings<T, W> for Vec<CaveatDeferred<T, W>>
584where
585 W: Warning,
586{
587 type Output = Vec<T>;
588
589 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
591 where
592 W: Into<WA>,
593 WA: Warning,
594 {
595 self.into_iter()
596 .map(|cv| cv.gather_deferred_warnings_into(warnings))
597 .collect()
598 }
599}
600
601pub trait IntoCaveat: Sized {
605 fn into_caveat<W: Warning>(self, warnings: Set<W>) -> Caveat<Self, W>;
607}
608
609pub(crate) trait IntoCaveatDeferred: Sized {
613 fn into_caveat_deferred<W: Warning>(self, warnings: SetDeferred<W>) -> CaveatDeferred<Self, W>;
615}
616
617impl<T> IntoCaveat for T {
619 fn into_caveat<W: Warning>(self, warnings: Set<W>) -> Caveat<Self, W> {
620 Caveat::new(self, warnings)
621 }
622}
623
624impl<T> IntoCaveatDeferred for T {
626 fn into_caveat_deferred<W: Warning>(self, warnings: SetDeferred<W>) -> CaveatDeferred<Self, W> {
627 CaveatDeferred::new(self, warnings)
628 }
629}
630
631pub trait VerdictExt<T, W: Warning> {
633 fn map_caveat<F, U>(self, op: F) -> Verdict<U, W>
636 where
637 F: FnOnce(T) -> U;
638
639 fn only_error(self) -> Result<Caveat<T, W>, Error<W>>;
641}
642
643#[allow(dead_code, reason = "for debugging")]
644pub(crate) trait VerdictTrace<T, W: Warning> {
645 fn info_verdict(self, msg: &'static str) -> Self;
646 fn debug_verdict(self, msg: &'static str) -> Self;
647}
648
649#[allow(dead_code, reason = "for debugging")]
650pub(crate) trait ResultTrace<T, W: Warning> {
651 fn info_result(self, msg: &'static str) -> Self;
652 fn debug_result(self, msg: &'static str) -> Self;
653}
654
655impl<T, W: Warning> VerdictExt<T, W> for Verdict<T, W> {
656 fn map_caveat<F, U>(self, op: F) -> Verdict<U, W>
657 where
658 F: FnOnce(T) -> U,
659 {
660 match self {
661 Ok(c) => Ok(c.map(op)),
662 Err(w) => Err(w),
663 }
664 }
665
666 fn only_error(self) -> Result<Caveat<T, W>, Error<W>> {
667 match self {
668 Ok(c) => Ok(c),
669 Err(err_set) => {
670 let ErrorSet { error, warnings: _ } = err_set;
671 Err(*error)
672 }
673 }
674 }
675}
676
677impl<T, W: Warning> VerdictTrace<T, W> for Verdict<T, W>
678where
679 T: fmt::Debug,
680{
681 fn info_verdict(self, msg: &'static str) -> Self {
682 match self {
683 Ok(c) => {
684 info!("{msg}: {c:#?}");
685 Ok(c)
686 }
687 Err(err_set) => {
688 info!("{msg}: {err_set:#?}");
689 Err(err_set)
690 }
691 }
692 }
693
694 fn debug_verdict(self, msg: &'static str) -> Self {
695 match self {
696 Ok(c) => {
697 debug!("{msg}: {c:#?}");
698 Ok(c)
699 }
700 Err(err_set) => {
701 debug!("{msg}: {err_set:#?}");
702 Err(err_set)
703 }
704 }
705 }
706}
707
708impl<T, W: Warning> ResultTrace<T, W> for Result<T, ErrorSet<W>>
709where
710 T: fmt::Debug,
711{
712 fn info_result(self, msg: &'static str) -> Self {
713 match self {
714 Ok(c) => {
715 info!("{msg}: {c:#?}");
716 Ok(c)
717 }
718 Err(err_set) => {
719 info!("{msg}: {err_set:#?}");
720 Err(err_set)
721 }
722 }
723 }
724
725 fn debug_result(self, msg: &'static str) -> Self {
726 match self {
727 Ok(c) => {
728 debug!("{msg}: {c:#?}");
729 Ok(c)
730 }
731 Err(err_set) => {
732 debug!("{msg}: {err_set:#?}");
733 Err(err_set)
734 }
735 }
736 }
737}
738
739#[derive(Debug)]
743pub struct Error<W: Warning> {
744 warning: W,
746
747 element: Element,
749}
750
751impl<W: Warning> Error<W> {
752 pub fn warning(&self) -> &W {
754 &self.warning
755 }
756
757 pub fn into_warning(self) -> W {
759 self.warning
760 }
761
762 pub fn element(&self) -> &Element {
764 &self.element
765 }
766
767 pub fn parts(&self) -> (&W, &Element) {
769 (&self.warning, &self.element)
770 }
771
772 pub fn into_parts(self) -> (W, Element) {
774 let Self { warning, element } = self;
775 (warning, element)
776 }
777
778 fn into_other<WA>(self) -> Error<WA>
782 where
783 W: Into<WA>,
784 WA: Warning,
785 {
786 let Self { warning, element } = self;
787 Error {
788 warning: warning.into(),
789 element,
790 }
791 }
792}
793
794impl<W: Warning> std::error::Error for Error<W> {}
795
796impl<W: Warning> fmt::Display for Error<W> {
797 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
798 write!(
799 f,
800 "A warning for element at `{}` was upgraded to an `error`: {}",
801 self.element.path, self.warning
802 )
803 }
804}
805
806pub trait WithElement<T, W: Warning> {
808 fn with_element(self, element: &json::Element<'_>) -> Verdict<T, W>;
809}
810
811impl<T, W: Warning> WithElement<T, W> for VerdictDeferred<T, W> {
812 fn with_element(self, element: &json::Element<'_>) -> Verdict<T, W> {
814 match self {
815 Ok(v) => {
816 let CaveatDeferred { value, warnings } = v;
817 let SetDeferred(warnings) = warnings;
818 let warnings = if warnings.is_empty() {
819 BTreeMap::new()
820 } else {
821 let warnings = Group {
822 element: element.into(),
823 warnings,
824 };
825 BTreeMap::from([(element.id(), warnings)])
826 };
827
828 Ok(Caveat {
829 value,
830 warnings: Set(warnings),
831 })
832 }
833 Err(set) => {
834 let ErrorSetDeferred { error, warnings } = set;
835 let warnings = Group {
837 element: element.into(),
838 warnings,
839 };
840 let warnings = BTreeMap::from([(element.id(), warnings)]);
841 Err(ErrorSet {
842 error: Box::new(Error {
843 warning: error,
844 element: Element::from(element),
845 }),
846 warnings,
847 })
848 }
849 }
850 }
851}
852
853#[derive(Debug)]
863pub struct Element {
864 id: json::ElemId,
868
869 span: json::parser::Span,
871
872 path: Path,
876}
877
878impl Element {
879 pub fn span(&self) -> json::parser::Span {
880 self.span
881 }
882
883 pub fn path(&self) -> &Path {
884 &self.path
885 }
886
887 pub fn into_parts(self) -> (json::parser::Span, Path) {
888 let Self { id: _, span, path } = self;
889 (span, path)
890 }
891}
892
893impl<'buf> From<&json::Element<'buf>> for Element {
894 fn from(elem: &json::Element<'buf>) -> Self {
895 Self {
896 id: elem.id(),
897 span: elem.span(),
898 path: Path(elem.path().to_string()),
899 }
900 }
901}
902
903pub struct SourceReportIter<'caller, 'buf, W: Warning> {
905 report_iter: Iter<'caller, W>,
907
908 json: &'buf str,
910}
911
912impl<'caller, 'buf, W: Warning> SourceReportIter<'caller, 'buf, W> {
913 pub fn new(json: &'buf str, report_iter: Iter<'caller, W>) -> Self {
914 Self { report_iter, json }
915 }
916}
917
918impl<'caller, 'buf, W: Warning> Iterator for SourceReportIter<'caller, 'buf, W> {
919 type Item = ElementReport<'caller, 'buf, W>;
920
921 #[expect(
922 clippy::string_slice,
923 reason = "The disconnection between the source JSON and the `Element` will be fixed in a future PR"
924 )]
925 fn next(&mut self) -> Option<Self::Item> {
926 let group = self.report_iter.next()?;
927 let (element, warnings) = group.to_parts();
928
929 let lead_in = &self.json[..element.span.start];
931 let json::LineCol { line, col } = json::line_col(lead_in);
933 let json = &self.json[element.span.start..element.span.end];
934
935 Some(ElementReport {
936 element_path: element.path(),
937 warnings,
938 json,
939 location: json::LineCol {
940 line,
941 col: col.saturating_add(1),
942 },
943 })
944 }
945}
946
947#[derive(Debug)]
948pub struct ElementReport<'caller, 'buf, W: Warning> {
949 pub element_path: &'caller Path,
951
952 pub warnings: Vec<&'caller W>,
954
955 pub json: &'buf str,
957
958 pub location: json::LineCol,
960}
961
962pub struct SetWriter<'caller, W: Warning> {
976 warnings: &'caller Set<W>,
978
979 indent: &'caller str,
981}
982
983impl<'caller, W: Warning> SetWriter<'caller, W> {
984 pub fn new(warnings: &'caller Set<W>) -> Self {
986 Self {
987 warnings,
988 indent: " - ",
989 }
990 }
991
992 pub fn with_indent(warnings: &'caller Set<W>, indent: &'caller str) -> Self {
994 Self { warnings, indent }
995 }
996}
997
998impl<W: Warning> fmt::Debug for SetWriter<'_, W> {
999 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1000 fmt::Display::fmt(self, f)
1001 }
1002}
1003
1004impl<W: Warning> fmt::Display for SetWriter<'_, W> {
1005 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1006 let mut iter = self.warnings.iter();
1007
1008 {
1009 let Some((element, warnings)) = iter.next().map(|g| g.to_parts()) else {
1011 return Ok(());
1012 };
1013
1014 writeln!(f, "{}", element.path)?;
1015
1016 for warning in warnings {
1017 write!(f, "{}{}", self.indent, warning)?;
1018 }
1019 }
1020
1021 for (element, warnings) in iter.map(|g| g.to_parts()) {
1023 writeln!(f, "\n{}", element.path)?;
1024
1025 for warning in warnings {
1026 write!(f, "{}{}", self.indent, warning)?;
1027 }
1028 }
1029
1030 Ok(())
1031 }
1032}
1033
1034pub trait Warning: Sized + fmt::Debug + fmt::Display + Send + Sync {
1038 fn id(&self) -> Id;
1043}
1044
1045#[derive(Debug)]
1047struct Source<W: Warning> {
1048 #[cfg(test)]
1049 location: &'static std::panic::Location<'static>,
1051
1052 warning: W,
1054}
1055
1056impl<W: Warning> Source<W> {
1057 #[track_caller]
1058 fn new(warning: W) -> Self {
1059 #[cfg(test)]
1060 {
1061 Self {
1062 location: std::panic::Location::caller(),
1063 warning,
1064 }
1065 }
1066
1067 #[expect(
1068 clippy::cfg_not_test,
1069 reason = "This is code that is designed for use in tests"
1070 )]
1071 #[cfg(not(test))]
1072 {
1073 Self { warning }
1074 }
1075 }
1076
1077 fn into_warning(self) -> W {
1079 self.warning
1080 }
1081
1082 fn into_other<WA>(self) -> Source<WA>
1084 where
1085 W: Into<WA>,
1086 WA: Warning,
1087 {
1088 self.map(Into::into)
1089 }
1090
1091 fn map<F, WA>(self, mut f: F) -> Source<WA>
1093 where
1094 F: FnMut(W) -> WA,
1095 WA: Warning,
1096 {
1097 #[cfg(test)]
1098 {
1099 let Self {
1100 location: source,
1101 warning,
1102 } = self;
1103 Source {
1104 location: source,
1105 warning: f(warning),
1106 }
1107 }
1108
1109 #[expect(
1110 clippy::cfg_not_test,
1111 reason = "This is code that is designed for use in tests"
1112 )]
1113 #[cfg(not(test))]
1114 {
1115 let Self { warning } = self;
1116 Source {
1117 warning: f(warning),
1118 }
1119 }
1120 }
1121}
1122
1123impl<W: Warning> Deref for Source<W> {
1124 type Target = W;
1125
1126 fn deref(&self) -> &Self::Target {
1127 &self.warning
1128 }
1129}
1130
1131#[derive(Debug)]
1140pub(crate) struct SetDeferred<W: Warning>(Vec<Source<W>>);
1141
1142impl<W: Warning> SetDeferred<W> {
1143 pub(crate) fn new() -> Self {
1145 Self(Vec::new())
1146 }
1147
1148 #[track_caller]
1152 pub(crate) fn bail<T>(self, warning: W) -> VerdictDeferred<T, W> {
1153 let Self(warnings) = self;
1154 Err(ErrorSetDeferred {
1155 error: warning,
1156 warnings,
1157 })
1158 }
1159
1160 fn extend<WA>(&mut self, warnings: SetDeferred<WA>)
1164 where
1165 WA: Into<W> + Warning,
1166 {
1167 let SetDeferred(warnings) = warnings;
1168 self.0.extend(warnings.into_iter().map(Source::into_other));
1169 }
1170}
1171
1172#[derive(Debug)]
1182pub struct ErrorSetDeferred<W: Warning> {
1183 error: W,
1184 warnings: Vec<Source<W>>,
1185}
1186
1187impl<W: Warning> ErrorSetDeferred<W> {
1188 pub(crate) fn with_warn(warning: W) -> Self {
1190 Self {
1191 warnings: Vec::new(),
1192 error: warning,
1193 }
1194 }
1195
1196 pub(crate) fn into_other<WA>(self) -> ErrorSetDeferred<WA>
1200 where
1201 W: Into<WA>,
1202 WA: Warning,
1203 {
1204 let Self { error, warnings } = self;
1205 let warnings = warnings.into_iter().map(Source::into_other).collect();
1206 ErrorSetDeferred {
1207 error: error.into(),
1208 warnings,
1209 }
1210 }
1211}
1212
1213#[derive(Debug)]
1215pub struct Set<W: Warning>(BTreeMap<json::ElemId, Group<W>>);
1216
1217impl<W: Warning> Set<W> {
1218 pub(crate) fn new() -> Self {
1220 Self(BTreeMap::new())
1221 }
1222
1223 pub(crate) fn into_inner(self) -> BTreeMap<json::ElemId, Group<W>> {
1224 self.0
1225 }
1226
1227 #[track_caller]
1229 pub(crate) fn insert(&mut self, warning: W, element: &json::Element<'_>) {
1230 self.insert_warning(warning, element.id(), || Element::from(element));
1231 }
1232
1233 #[track_caller]
1237 fn insert_warning<F>(&mut self, warning: W, elem_id: json::ElemId, f: F)
1238 where
1239 F: FnOnce() -> Element,
1240 {
1241 use std::collections::btree_map::Entry;
1242
1243 match self.0.entry(elem_id) {
1244 Entry::Vacant(entry) => {
1245 let element = f();
1246 entry.insert_entry(Group {
1247 element,
1248 warnings: vec![Source::new(warning)],
1249 });
1250 }
1251 Entry::Occupied(mut entry) => {
1252 entry.get_mut().warnings.push(Source::new(warning));
1253 }
1254 }
1255 }
1256
1257 #[track_caller]
1261 pub(crate) fn bail<T>(self, warning: W, element: &json::Element<'_>) -> Verdict<T, W> {
1262 let Self(warnings) = self;
1263
1264 Err(ErrorSet {
1265 error: Box::new(Error {
1266 warning,
1267 element: Element::from(element),
1268 }),
1269 warnings,
1270 })
1271 }
1272
1273 pub(crate) fn into_other<WA>(self) -> Set<WA>
1277 where
1278 W: Into<WA>,
1279 WA: Warning,
1280 {
1281 let Set(warnings) = self;
1282 let warnings = warnings
1283 .into_iter()
1284 .map(|(elem_id, group)| (elem_id, group.into_other()))
1285 .collect();
1286 Set(warnings)
1287 }
1288
1289 pub fn is_empty(&self) -> bool {
1291 self.0.is_empty()
1292 }
1293
1294 pub fn len_elements(&self) -> usize {
1298 self.0.len()
1299 }
1300
1301 pub fn len_warnings(&self) -> usize {
1303 self.0
1304 .values()
1305 .fold(0, |acc, group| acc.saturating_add(group.warnings.len()))
1306 }
1307
1308 pub fn iter(&self) -> Iter<'_, W> {
1310 Iter {
1311 warnings: self.0.iter(),
1312 }
1313 }
1314
1315 pub fn path_map(&self) -> BTreeMap<&str, Vec<&W>> {
1321 self.0
1322 .values()
1323 .map(|Group { element, warnings }| {
1324 let path = element.path.as_str();
1325 let warnings = warnings.iter().map(|w| &**w).collect();
1326 (path, warnings)
1327 })
1328 .collect()
1329 }
1330
1331 pub fn into_path_map(self) -> BTreeMap<Path, Vec<W>> {
1335 self.0
1336 .into_values()
1337 .map(|Group { element, warnings }| {
1338 let warnings = warnings.into_iter().map(Source::into_warning).collect();
1339 (element.path, warnings)
1340 })
1341 .collect()
1342 }
1343
1344 pub fn path_id_map(&self) -> BTreeMap<&str, Vec<Id>> {
1353 self.0
1354 .values()
1355 .map(|group| {
1356 let warnings = group.warnings.iter().map(|w| w.id()).collect();
1357 (group.element.path.as_str(), warnings)
1358 })
1359 .collect()
1360 }
1361
1362 pub fn path_msg_map(&self) -> BTreeMap<&str, Vec<String>> {
1368 self.0
1369 .values()
1370 .map(|group| {
1371 let warnings = group.warnings.iter().map(|w| w.to_string()).collect();
1372 (group.element.path.as_str(), warnings)
1373 })
1374 .collect()
1375 }
1376
1377 pub(crate) fn deescalate_error(&mut self, err_set: ErrorSet<W>) {
1379 let ErrorSet { error, warnings } = err_set;
1380 let Error { warning, element } = *error;
1381 self.0.extend(warnings);
1382 self.insert_warning(warning, element.id, || element);
1383 }
1384
1385 pub(crate) fn extend(&mut self, warnings: impl Iterator<Item = (json::ElemId, Group<W>)>) {
1389 use std::collections::btree_map::Entry;
1390
1391 for (elem_id, group) in warnings {
1392 match self.0.entry(elem_id) {
1393 Entry::Vacant(entry) => {
1394 entry.insert_entry(group);
1395 }
1396 Entry::Occupied(mut entry) => {
1397 let Group {
1398 element: _,
1399 warnings,
1400 } = group;
1401 entry.get_mut().warnings.extend(warnings);
1402 }
1403 }
1404 }
1405 }
1406}
1407
1408#[derive(Debug)]
1412pub struct ErrorSet<W: Warning> {
1413 error: Box<Error<W>>,
1417
1418 warnings: BTreeMap<json::ElemId, Group<W>>,
1422}
1423
1424impl<W> ErrorSet<W>
1425where
1426 W: Warning,
1427{
1428 pub(crate) fn with_warn(warning: W, element: &json::Element<'_>) -> Self {
1430 Self {
1431 warnings: BTreeMap::new(),
1432 error: Box::new(Error {
1433 warning,
1434 element: Element::from(element),
1435 }),
1436 }
1437 }
1438
1439 pub fn into_parts(self) -> (Error<W>, Set<W>) {
1441 let Self { error, warnings } = self;
1442 (*error, Set(warnings))
1443 }
1444
1445 pub(crate) fn into_other<WA>(self) -> ErrorSet<WA>
1449 where
1450 W: Into<WA>,
1451 WA: Warning,
1452 {
1453 let Self { error, warnings } = self;
1454 let warnings = warnings
1455 .into_iter()
1456 .map(|(elem_id, group)| (elem_id, group.into_other()))
1457 .collect();
1458 ErrorSet {
1459 error: Box::new(Error::into_other(*error)),
1460 warnings,
1461 }
1462 }
1463}
1464
1465#[derive(Debug)]
1470pub struct Group<W: Warning> {
1471 element: Element,
1473
1474 warnings: Vec<Source<W>>,
1476}
1477
1478impl<W> Group<W>
1479where
1480 W: Warning,
1481{
1482 pub fn into_parts(self) -> (Element, Vec<W>) {
1484 let Self { element, warnings } = self;
1485 let warnings = warnings.into_iter().map(Source::into_warning).collect();
1486 (element, warnings)
1487 }
1488
1489 pub(crate) fn map<F, WA>(self, mut f: F) -> Group<WA>
1491 where
1492 F: FnMut(W) -> WA,
1493 WA: Warning,
1494 {
1495 let Self { element, warnings } = self;
1496 let warnings = warnings
1497 .into_iter()
1498 .map(|source| source.map(&mut f))
1499 .collect();
1500 Group { element, warnings }
1501 }
1502
1503 pub fn to_parts(&self) -> (&Element, Vec<&W>) {
1504 let Self { element, warnings } = self;
1505 let warnings = warnings.iter().map(|w| &**w).collect();
1506 (element, warnings)
1507 }
1508
1509 pub fn warnings(&self) -> Vec<&W> {
1510 self.warnings.iter().map(|w| &**w).collect()
1511 }
1512
1513 pub fn into_warnings(self) -> Vec<W> {
1514 let Self {
1515 element: _,
1516 warnings,
1517 } = self;
1518 warnings.into_iter().map(Source::into_warning).collect()
1519 }
1520
1521 fn into_other<WA>(self) -> Group<WA>
1525 where
1526 W: Into<WA>,
1527 WA: Warning,
1528 {
1529 let Self { element, warnings } = self;
1530 let warnings = warnings.into_iter().map(Source::into_other).collect();
1531 Group { element, warnings }
1532 }
1533}
1534
1535pub struct Iter<'caller, W>
1537where
1538 W: Warning,
1539{
1540 warnings: std::collections::btree_map::Iter<'caller, json::ElemId, Group<W>>,
1542}
1543
1544impl<W> Iter<'_, W> where W: Warning {}
1545
1546impl<'caller, W: Warning> Iterator for Iter<'caller, W> {
1547 type Item = &'caller Group<W>;
1548
1549 fn next(&mut self) -> Option<Self::Item> {
1550 let (_elem_id, group) = self.warnings.next()?;
1551 Some(group)
1552 }
1553}
1554
1555pub struct IntoIter<W>
1557where
1558 W: Warning,
1559{
1560 warnings: std::collections::btree_map::IntoIter<json::ElemId, Group<W>>,
1562}
1563
1564impl<W: Warning> Iterator for IntoIter<W> {
1565 type Item = Group<W>;
1566
1567 fn next(&mut self) -> Option<Self::Item> {
1568 let (_elem_id, group) = self.warnings.next()?;
1569 Some(group)
1570 }
1571}
1572
1573impl<W: Warning> IntoIterator for Set<W> {
1574 type Item = Group<W>;
1575 type IntoIter = IntoIter<W>;
1576
1577 fn into_iter(self) -> Self::IntoIter {
1578 let Set(warnings) = self;
1579 IntoIter {
1580 warnings: warnings.into_iter(),
1581 }
1582 }
1583}
1584
1585impl<'a, W: Warning> IntoIterator for &'a Set<W> {
1586 type Item = &'a Group<W>;
1587 type IntoIter = Iter<'a, W>;
1588
1589 fn into_iter(self) -> Self::IntoIter {
1590 self.iter()
1591 }
1592}