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)]
60#[macro_export]
61macro_rules! into_caveat {
62 ($kind:ident<$life:lifetime>) => {
63 impl<$life> $crate::IntoCaveat for $kind<$life> {
64 fn into_caveat<W: $crate::Warning>(
65 self,
66 warnings: $crate::warning::Set<W>,
67 ) -> $crate::Caveat<Self, W> {
68 $crate::Caveat::new(self, warnings)
69 }
70 }
71 };
72 ($kind:ty) => {
73 impl $crate::IntoCaveat for $kind {
74 fn into_caveat<W: $crate::Warning>(
75 self,
76 warnings: $crate::warning::Set<W>,
77 ) -> $crate::Caveat<Self, W> {
78 $crate::Caveat::new(self, warnings)
79 }
80 }
81
82 impl $crate::warning::IntoCaveatDeferred for $kind {
83 fn into_caveat_deferred<W: $crate::Warning>(
84 self,
85 warnings: $crate::warning::SetDeferred<W>,
86 ) -> $crate::warning::CaveatDeferred<Self, W> {
87 $crate::warning::CaveatDeferred::new(self, warnings)
88 }
89 }
90 };
91}
92
93#[doc(hidden)]
95#[macro_export]
96macro_rules! into_caveat_all {
97 ($($kind:ty),+) => {
98 $($crate::into_caveat!($kind);)+
99 };
100}
101
102#[doc(hidden)]
103#[macro_export]
104macro_rules! from_warning_all {
105 ($($source_kind:path => $target_kind:ident::$target_variant:ident),+) => {
106 $(
107 impl From<$source_kind> for $target_kind {
109 fn from(warning: $source_kind) -> Self {
110 $target_kind::$target_variant(warning)
111 }
112 }
113
114 impl From<$crate::warning::ErrorSet<$source_kind>> for $crate::warning::ErrorSet<$target_kind> {
119 fn from(set_a: $crate::warning::ErrorSet<$source_kind>) -> Self {
120 set_a.into_other()
121 }
122 }
123
124 impl From<$crate::warning::ErrorSetDeferred<$source_kind>> for $crate::warning::ErrorSetDeferred<$target_kind> {
129 fn from(set_a: $crate::warning::ErrorSetDeferred<$source_kind>) -> Self {
130 set_a.into_other()
131 }
132 }
133 )+
134 };
135}
136
137#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)]
138pub struct Id(Cow<'static, str>);
139
140impl Id {
141 pub(crate) fn from_static(s: &'static str) -> Self {
142 Self(s.into())
143 }
144
145 pub(crate) fn from_string(s: String) -> Self {
146 Self(s.into())
147 }
148
149 pub fn as_str(&self) -> &str {
150 &self.0
151 }
152}
153
154impl fmt::Debug for Id {
155 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156 fmt::Debug::fmt(&self.0, f)
157 }
158}
159
160impl fmt::Display for Id {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 fmt::Display::fmt(&self.0, f)
163 }
164}
165
166#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)]
167pub struct Path(String);
168
169impl Path {
170 pub fn as_str(&self) -> &str {
171 &self.0
172 }
173}
174
175impl fmt::Debug for Path {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 f.write_str(&self.0)
178 }
179}
180
181impl fmt::Display for Path {
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 fmt::Display::fmt(&self.0, f)
184 }
185}
186
187pub type Verdict<T, W> = Result<Caveat<T, W>, ErrorSet<W>>;
189
190pub(crate) type VerdictDeferred<T, W> = Result<CaveatDeferred<T, W>, ErrorSetDeferred<W>>;
197
198#[derive(Debug)]
208pub(crate) struct CaveatDeferred<T, W: Warning> {
209 value: T,
211
212 warnings: SetDeferred<W>,
214}
215
216impl<T, W> CaveatDeferred<T, W>
217where
218 T: IntoCaveatDeferred,
219 W: Warning,
220{
221 pub(crate) fn new(value: T, warnings: SetDeferred<W>) -> Self {
223 Self { value, warnings }
224 }
225}
226
227impl<T, W> Deref for CaveatDeferred<T, W>
242where
243 W: Warning,
244{
245 type Target = T;
246
247 fn deref(&self) -> &T {
248 &self.value
249 }
250}
251
252impl<T, W> CaveatDeferred<T, W>
253where
254 W: Warning,
255{
256 pub fn into_parts(self) -> (T, SetDeferred<W>) {
258 let Self { value, warnings } = self;
259 (value, warnings)
260 }
261}
262
263#[derive(Debug)]
267pub struct Caveat<T, W: Warning> {
268 value: T,
270
271 warnings: Set<W>,
273}
274
275impl<T, W> Caveat<T, W>
276where
277 T: IntoCaveat,
278 W: Warning,
279{
280 pub(crate) fn new(value: T, warnings: Set<W>) -> Self {
282 Self { value, warnings }
283 }
284}
285
286impl<T, W> Deref for Caveat<T, W>
299where
300 W: Warning,
301{
302 type Target = T;
303
304 fn deref(&self) -> &T {
305 &self.value
306 }
307}
308
309impl<T, W> Caveat<T, W>
310where
311 W: Warning,
312{
313 pub fn into_parts(self) -> (T, Set<W>) {
315 let Self { value, warnings } = self;
316 (value, warnings)
317 }
318
319 pub fn ignore_warnings(self) -> T {
321 self.value
322 }
323
324 pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Caveat<U, W> {
326 let Self { value, warnings } = self;
327 Caveat {
328 value: op(value),
329 warnings,
330 }
331 }
332}
333
334pub(crate) trait GatherWarnings<T, W>
339where
340 W: Warning,
341{
342 type Output;
344
345 #[must_use = "If you want to ignore the value use `let _ =`"]
347 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
348 where
349 W: Into<WA>,
350 WA: Warning;
351}
352
353impl<T, W> GatherWarnings<T, W> for Caveat<T, W>
355where
356 W: Warning,
357{
358 type Output = T;
359
360 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
362 where
363 W: Into<WA>,
364 WA: Warning,
365 {
366 let Self {
367 value,
368 warnings: inner_warnings,
369 } = self;
370
371 warnings.extend(inner_warnings);
372
373 value
374 }
375}
376
377impl<T, W> GatherWarnings<T, W> for Option<Caveat<T, W>>
379where
380 W: Warning,
381{
382 type Output = Option<T>;
383
384 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 Some(cv) => Some(cv.gather_warnings_into(warnings)),
392 None => None,
393 }
394 }
395}
396
397impl<T, W, E> GatherWarnings<T, W> for Result<Caveat<T, W>, E>
399where
400 W: Warning,
401 E: std::error::Error,
402{
403 type Output = Result<T, E>;
404
405 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
407 where
408 W: Into<WA>,
409 WA: Warning,
410 {
411 match self {
412 Ok(cv) => Ok(cv.gather_warnings_into(warnings)),
413 Err(err) => Err(err),
414 }
415 }
416}
417
418impl<T, W> GatherWarnings<T, W> for Verdict<T, W>
420where
421 W: Warning,
422{
423 type Output = Result<T, ErrorSet<W>>;
424
425 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
428 where
429 W: Into<WA>,
430 WA: Warning,
431 {
432 match self {
433 Ok(cv) => Ok(cv.gather_warnings_into(warnings)),
434 Err(err_set) => Err(err_set),
435 }
436 }
437}
438
439pub(crate) trait DeescalateError<T, W>
444where
445 W: Warning,
446{
447 #[must_use = "If you want to ignore the value use `let _ =`"]
449 fn deescalate_error_into<WA>(self, warnings: &mut Set<WA>) -> Option<T>
450 where
451 W: Into<WA>,
452 WA: Warning;
453}
454
455impl<T, W> DeescalateError<T, W> for Verdict<T, W>
457where
458 W: Warning,
459{
460 fn deescalate_error_into<WA>(self, warnings: &mut Set<WA>) -> Option<T>
463 where
464 W: Into<WA>,
465 WA: Warning,
466 {
467 match self {
468 Ok(cv) => Some(cv.gather_warnings_into(warnings)),
469 Err(err_set) => {
470 warnings.deescalate_error(err_set.into_other());
471 None
472 }
473 }
474 }
475}
476
477impl<T, W> DeescalateError<T, W> for Result<T, ErrorSet<W>>
479where
480 W: Warning,
481{
482 fn deescalate_error_into<WA>(self, warnings: &mut Set<WA>) -> Option<T>
485 where
486 W: Into<WA>,
487 WA: Warning,
488 {
489 match self {
490 Ok(cv) => Some(cv),
491 Err(err_set) => {
492 warnings.deescalate_error(err_set.into_other());
493 None
494 }
495 }
496 }
497}
498
499impl<T, W> GatherWarnings<T, W> for Vec<Caveat<T, W>>
501where
502 W: Warning,
503{
504 type Output = Vec<T>;
505
506 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
508 where
509 W: Into<WA>,
510 WA: Warning,
511 {
512 self.into_iter()
513 .map(|cv| cv.gather_warnings_into(warnings))
514 .collect()
515 }
516}
517
518pub(crate) trait GatherDeferredWarnings<T, W>
523where
524 W: Warning,
525{
526 type Output;
528
529 #[must_use = "If you want to ignore the value use `let _ =`"]
531 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
532 where
533 W: Into<WA>,
534 WA: Warning;
535}
536
537impl<T, W> GatherDeferredWarnings<T, W> for CaveatDeferred<T, W>
539where
540 W: Warning,
541{
542 type Output = T;
543
544 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
546 where
547 W: Into<WA>,
548 WA: Warning,
549 {
550 let Self {
551 value,
552 warnings: inner_warnings,
553 } = self;
554
555 warnings.extend(inner_warnings);
556
557 value
558 }
559}
560
561impl<T, W> GatherDeferredWarnings<T, W> for Option<CaveatDeferred<T, W>>
563where
564 W: Warning,
565{
566 type Output = Option<T>;
567
568 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 Some(cv) => Some(cv.gather_deferred_warnings_into(warnings)),
576 None => None,
577 }
578 }
579}
580
581impl<T, W, E> GatherDeferredWarnings<T, W> for Result<CaveatDeferred<T, W>, E>
583where
584 W: Warning,
585 E: std::error::Error,
586{
587 type Output = Result<T, E>;
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 match self {
596 Ok(cv) => Ok(cv.gather_deferred_warnings_into(warnings)),
597 Err(err) => Err(err),
598 }
599 }
600}
601
602impl<T, W> GatherDeferredWarnings<T, W> for VerdictDeferred<T, W>
604where
605 W: Warning,
606{
607 type Output = Result<T, ErrorSetDeferred<W>>;
608
609 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
612 where
613 W: Into<WA>,
614 WA: Warning,
615 {
616 match self {
617 Ok(cv) => Ok(cv.gather_deferred_warnings_into(warnings)),
618 Err(err_set) => Err(err_set),
619 }
620 }
621}
622
623impl<T, W> GatherDeferredWarnings<T, W> for Vec<CaveatDeferred<T, W>>
625where
626 W: Warning,
627{
628 type Output = Vec<T>;
629
630 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
632 where
633 W: Into<WA>,
634 WA: Warning,
635 {
636 self.into_iter()
637 .map(|cv| cv.gather_deferred_warnings_into(warnings))
638 .collect()
639 }
640}
641
642pub trait IntoCaveat: Sized {
646 fn into_caveat<W: Warning>(self, warnings: Set<W>) -> Caveat<Self, W>;
648}
649
650pub(crate) trait IntoCaveatDeferred: Sized {
654 fn into_caveat_deferred<W: Warning>(self, warnings: SetDeferred<W>) -> CaveatDeferred<Self, W>;
656}
657
658macro_rules! peel {
660 ($name:ident, $($other:ident,)*) => (into_caveat_tuple! { $($other,)* })
661}
662
663macro_rules! into_caveat_tuple {
666 () => ();
667 ( $($name:ident,)+ ) => (
668 impl<$($name),+> $crate::IntoCaveat for ($($name,)+) {
669 fn into_caveat<W: $crate::Warning>(
670 self,
671 warnings: $crate::warning::Set<W>,
672 ) -> $crate::Caveat<Self, W> {
673 $crate::Caveat::new(self, warnings)
674 }
675 }
676
677 impl<$($name),+> $crate::warning::IntoCaveatDeferred for ($($name,)+) {
678 fn into_caveat_deferred<W: $crate::Warning>(
679 self,
680 warnings: SetDeferred<W>,
681 ) -> $crate::warning::CaveatDeferred<Self, W> {
682 $crate::warning::CaveatDeferred::new(self, warnings)
683 }
684 }
685 peel! { $($name,)+ }
686 )
687}
688
689into_caveat_tuple! { T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
692
693into_caveat_all!(
695 (),
696 bool,
697 char,
698 u8,
699 u16,
700 u32,
701 u64,
702 u128,
703 i8,
704 i16,
705 i32,
706 i64,
707 i128
708);
709
710impl IntoCaveat for Cow<'_, str> {
712 fn into_caveat<W: Warning>(self, warnings: Set<W>) -> Caveat<Self, W> {
713 Caveat::new(self, warnings)
714 }
715}
716
717impl<T> IntoCaveat for Option<T>
719where
720 T: IntoCaveat,
721{
722 fn into_caveat<W: Warning>(self, warnings: Set<W>) -> Caveat<Self, W> {
723 Caveat::new(self, warnings)
724 }
725}
726
727impl<T> IntoCaveat for Vec<T>
729where
730 T: IntoCaveat,
731{
732 fn into_caveat<W: Warning>(self, warnings: Set<W>) -> Caveat<Self, W> {
733 Caveat::new(self, warnings)
734 }
735}
736
737impl<T> IntoCaveatDeferred for Vec<T>
739where
740 T: IntoCaveat,
741{
742 fn into_caveat_deferred<W: Warning>(self, warnings: SetDeferred<W>) -> CaveatDeferred<Self, W> {
743 CaveatDeferred::new(self, warnings)
744 }
745}
746
747pub trait VerdictExt<T, W: Warning> {
749 fn map_caveat<F, U>(self, op: F) -> Verdict<U, W>
752 where
753 F: FnOnce(T) -> U;
754
755 fn only_error(self) -> Result<Caveat<T, W>, Error<W>>;
757}
758
759#[allow(dead_code, reason = "for debugging")]
760pub(crate) trait VerdictTrace<T, W: Warning> {
761 fn info_verdict(self, msg: &'static str) -> Self;
762 fn debug_verdict(self, msg: &'static str) -> Self;
763}
764
765#[allow(dead_code, reason = "for debugging")]
766pub(crate) trait ResultTrace<T, W: Warning> {
767 fn info_result(self, msg: &'static str) -> Self;
768 fn debug_result(self, msg: &'static str) -> Self;
769}
770
771impl<T, W: Warning> VerdictExt<T, W> for Verdict<T, W> {
772 fn map_caveat<F, U>(self, op: F) -> Verdict<U, W>
773 where
774 F: FnOnce(T) -> U,
775 {
776 match self {
777 Ok(c) => Ok(c.map(op)),
778 Err(w) => Err(w),
779 }
780 }
781
782 fn only_error(self) -> Result<Caveat<T, W>, Error<W>> {
783 match self {
784 Ok(c) => Ok(c),
785 Err(err_set) => {
786 let ErrorSet { error, warnings: _ } = err_set;
787 Err(*error)
788 }
789 }
790 }
791}
792
793impl<T, W: Warning> VerdictTrace<T, W> for Verdict<T, W>
794where
795 T: fmt::Debug,
796{
797 fn info_verdict(self, msg: &'static str) -> Self {
798 match self {
799 Ok(c) => {
800 info!("{msg}: {c:#?}");
801 Ok(c)
802 }
803 Err(err_set) => {
804 info!("{msg}: {err_set:#?}");
805 Err(err_set)
806 }
807 }
808 }
809
810 fn debug_verdict(self, msg: &'static str) -> Self {
811 match self {
812 Ok(c) => {
813 debug!("{msg}: {c:#?}");
814 Ok(c)
815 }
816 Err(err_set) => {
817 debug!("{msg}: {err_set:#?}");
818 Err(err_set)
819 }
820 }
821 }
822}
823
824impl<T, W: Warning> ResultTrace<T, W> for Result<T, ErrorSet<W>>
825where
826 T: fmt::Debug,
827{
828 fn info_result(self, msg: &'static str) -> Self {
829 match self {
830 Ok(c) => {
831 info!("{msg}: {c:#?}");
832 Ok(c)
833 }
834 Err(err_set) => {
835 info!("{msg}: {err_set:#?}");
836 Err(err_set)
837 }
838 }
839 }
840
841 fn debug_result(self, msg: &'static str) -> Self {
842 match self {
843 Ok(c) => {
844 debug!("{msg}: {c:#?}");
845 Ok(c)
846 }
847 Err(err_set) => {
848 debug!("{msg}: {err_set:#?}");
849 Err(err_set)
850 }
851 }
852 }
853}
854
855#[derive(Debug)]
859pub struct Error<W: Warning> {
860 warning: W,
862
863 element: Element,
865}
866
867impl<W: Warning> Error<W> {
868 pub fn warning(&self) -> &W {
870 &self.warning
871 }
872
873 pub fn into_warning(self) -> W {
875 self.warning
876 }
877
878 pub fn element(&self) -> &Element {
880 &self.element
881 }
882
883 pub fn parts(&self) -> (&W, &Element) {
885 (&self.warning, &self.element)
886 }
887
888 pub fn into_parts(self) -> (W, Element) {
890 let Self { warning, element } = self;
891 (warning, element)
892 }
893
894 fn into_other<WA>(self) -> Error<WA>
898 where
899 W: Into<WA>,
900 WA: Warning,
901 {
902 let Self { warning, element } = self;
903 Error {
904 warning: warning.into(),
905 element,
906 }
907 }
908}
909
910impl<W: Warning> std::error::Error for Error<W> {}
911
912impl<W: Warning> fmt::Display for Error<W> {
913 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
914 write!(
915 f,
916 "A warning for element at `{}` was upgraded to an `error`: {}",
917 self.element.path, self.warning
918 )
919 }
920}
921
922pub trait WithElement<T, W: Warning> {
924 fn with_element(self, element: &json::Element<'_>) -> Verdict<T, W>;
925}
926
927impl<T, W: Warning> WithElement<T, W> for VerdictDeferred<T, W> {
928 fn with_element(self, element: &json::Element<'_>) -> Verdict<T, W> {
930 match self {
931 Ok(v) => {
932 let CaveatDeferred { value, warnings } = v;
933 let SetDeferred(warnings) = warnings;
934 let warnings = if warnings.is_empty() {
935 BTreeMap::new()
936 } else {
937 let warnings = Group {
938 element: element.into(),
939 warnings,
940 };
941 BTreeMap::from([(element.id(), warnings)])
942 };
943
944 Ok(Caveat {
945 value,
946 warnings: Set(warnings),
947 })
948 }
949 Err(set) => {
950 let ErrorSetDeferred { error, warnings } = set;
951 let warnings = Group {
953 element: element.into(),
954 warnings,
955 };
956 let warnings = BTreeMap::from([(element.id(), warnings)]);
957 Err(ErrorSet {
958 error: Box::new(Error {
959 warning: error,
960 element: Element::from(element),
961 }),
962 warnings,
963 })
964 }
965 }
966 }
967}
968
969#[derive(Debug)]
979pub struct Element {
980 id: json::ElemId,
984
985 span: json::parser::Span,
987
988 path: Path,
992}
993
994impl Element {
995 pub fn span(&self) -> json::parser::Span {
996 self.span
997 }
998
999 pub fn path(&self) -> &Path {
1000 &self.path
1001 }
1002
1003 pub fn into_parts(self) -> (json::parser::Span, Path) {
1004 let Self { id: _, span, path } = self;
1005 (span, path)
1006 }
1007}
1008
1009impl<'buf> From<&json::Element<'buf>> for Element {
1010 fn from(elem: &json::Element<'buf>) -> Self {
1011 Self {
1012 id: elem.id(),
1013 span: elem.span(),
1014 path: Path(elem.path().to_string()),
1015 }
1016 }
1017}
1018
1019pub struct SourceReportIter<'caller, 'buf, W: Warning> {
1021 report_iter: Iter<'caller, W>,
1023
1024 json: &'buf str,
1026
1027 line: u32,
1029
1030 byte: usize,
1033}
1034
1035impl<'caller, 'buf, W: Warning> SourceReportIter<'caller, 'buf, W> {
1036 pub fn new(json: &'buf str, report_iter: Iter<'caller, W>) -> Self {
1037 Self {
1038 report_iter,
1039 json,
1040 line: 1,
1041 byte: 0,
1042 }
1043 }
1044}
1045
1046impl<'caller, 'buf, W: Warning> Iterator for SourceReportIter<'caller, 'buf, W> {
1047 type Item = ElementReport<'caller, 'buf, W>;
1048
1049 #[expect(
1050 clippy::string_slice,
1051 reason = "The disconnection between the source JSON and the `Element` will be fixed in a future PR"
1052 )]
1053 fn next(&mut self) -> Option<Self::Item> {
1054 let group = self.report_iter.next()?;
1055 let (element, warnings) = group.to_parts();
1056
1057 let lead_in = &self.json[self.byte..element.span.start];
1059 let json::LineCol { line, col } = json::line_col(lead_in);
1061 let json = &self.json[element.span.start..element.span.end];
1062 self.byte = element.span.end;
1063
1064 self.line = self.line.checked_add(line)?;
1065
1066 Some(ElementReport {
1067 element_path: element.path(),
1068 warnings,
1069 json,
1070 location: json::LineCol {
1071 line: self.line,
1072 col: col.saturating_add(1),
1073 },
1074 })
1075 }
1076}
1077
1078#[derive(Debug)]
1079pub struct ElementReport<'caller, 'buf, W: Warning> {
1080 pub element_path: &'caller Path,
1082
1083 pub warnings: Vec<&'caller W>,
1085
1086 pub json: &'buf str,
1088
1089 pub location: json::LineCol,
1091}
1092
1093pub struct SetWriter<'caller, W: Warning> {
1107 warnings: &'caller Set<W>,
1109
1110 indent: &'caller str,
1112}
1113
1114impl<'caller, W: Warning> SetWriter<'caller, W> {
1115 pub fn new(warnings: &'caller Set<W>) -> Self {
1117 Self {
1118 warnings,
1119 indent: " - ",
1120 }
1121 }
1122
1123 pub fn with_indent(warnings: &'caller Set<W>, indent: &'caller str) -> Self {
1125 Self { warnings, indent }
1126 }
1127}
1128
1129impl<W: Warning> fmt::Debug for SetWriter<'_, W> {
1130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1131 fmt::Display::fmt(self, f)
1132 }
1133}
1134
1135impl<W: Warning> fmt::Display for SetWriter<'_, W> {
1136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1137 let mut iter = self.warnings.iter();
1138
1139 {
1140 let Some((element, warnings)) = iter.next().map(|g| g.to_parts()) else {
1142 return Ok(());
1143 };
1144
1145 writeln!(f, "{}", element.path)?;
1146
1147 for warning in warnings {
1148 write!(f, "{}{}", self.indent, warning)?;
1149 }
1150 }
1151
1152 for (element, warnings) in iter.map(|g| g.to_parts()) {
1154 writeln!(f, "\n{}", element.path)?;
1155
1156 for warning in warnings {
1157 write!(f, "{}{}", self.indent, warning)?;
1158 }
1159 }
1160
1161 Ok(())
1162 }
1163}
1164
1165pub trait Warning: Sized + fmt::Debug + fmt::Display + Send + Sync {
1169 fn id(&self) -> Id;
1174}
1175
1176#[derive(Debug)]
1178struct Source<W: Warning> {
1179 #[cfg(test)]
1180 location: &'static std::panic::Location<'static>,
1182
1183 warning: W,
1185}
1186
1187impl<W: Warning> Source<W> {
1188 #[track_caller]
1189 fn new(warning: W) -> Self {
1190 #[cfg(test)]
1191 {
1192 Self {
1193 location: std::panic::Location::caller(),
1194 warning,
1195 }
1196 }
1197
1198 #[expect(
1199 clippy::cfg_not_test,
1200 reason = "This is code that is designed for use in tests"
1201 )]
1202 #[cfg(not(test))]
1203 {
1204 Self { warning }
1205 }
1206 }
1207
1208 fn into_warning(self) -> W {
1210 self.warning
1211 }
1212
1213 fn into_other<WA>(self) -> Source<WA>
1215 where
1216 W: Into<WA>,
1217 WA: Warning,
1218 {
1219 #[cfg(test)]
1220 {
1221 let Self {
1222 location: source,
1223 warning,
1224 } = self;
1225 Source {
1226 location: source,
1227 warning: warning.into(),
1228 }
1229 }
1230
1231 #[expect(
1232 clippy::cfg_not_test,
1233 reason = "This is code that is designed for use in tests"
1234 )]
1235 #[cfg(not(test))]
1236 {
1237 let Self { warning } = self;
1238 Source {
1239 warning: warning.into(),
1240 }
1241 }
1242 }
1243}
1244
1245impl<W: Warning> Deref for Source<W> {
1246 type Target = W;
1247
1248 fn deref(&self) -> &Self::Target {
1249 &self.warning
1250 }
1251}
1252
1253#[derive(Debug)]
1262pub(crate) struct SetDeferred<W: Warning>(Vec<Source<W>>);
1263
1264impl<W: Warning> SetDeferred<W> {
1265 pub(crate) fn new() -> Self {
1267 Self(Vec::new())
1268 }
1269
1270 #[track_caller]
1274 pub(crate) fn bail<T>(self, warning: W) -> VerdictDeferred<T, W> {
1275 let Self(warnings) = self;
1276 Err(ErrorSetDeferred {
1277 error: warning,
1278 warnings,
1279 })
1280 }
1281
1282 fn extend<WA>(&mut self, warnings: SetDeferred<WA>)
1286 where
1287 WA: Into<W> + Warning,
1288 {
1289 let SetDeferred(warnings) = warnings;
1290 self.0.extend(warnings.into_iter().map(Source::into_other));
1291 }
1292}
1293
1294#[derive(Debug)]
1304pub struct ErrorSetDeferred<W: Warning> {
1305 error: W,
1306 warnings: Vec<Source<W>>,
1307}
1308
1309impl<W: Warning> ErrorSetDeferred<W> {
1310 pub(crate) fn with_warn(warning: W) -> Self {
1312 Self {
1313 warnings: Vec::new(),
1314 error: warning,
1315 }
1316 }
1317
1318 pub(crate) fn into_other<WA>(self) -> ErrorSetDeferred<WA>
1322 where
1323 W: Into<WA>,
1324 WA: Warning,
1325 {
1326 let Self { error, warnings } = self;
1327 let warnings = warnings.into_iter().map(Source::into_other).collect();
1328 ErrorSetDeferred {
1329 error: error.into(),
1330 warnings,
1331 }
1332 }
1333}
1334
1335#[derive(Debug)]
1337pub struct Set<W: Warning>(BTreeMap<json::ElemId, Group<W>>);
1338
1339impl<W: Warning> Set<W> {
1340 pub(crate) fn new() -> Self {
1342 Self(BTreeMap::new())
1343 }
1344
1345 #[track_caller]
1347 pub(crate) fn insert(&mut self, warning: W, element: &json::Element<'_>) {
1348 self.insert_warning(warning, element.id(), || Element::from(element));
1349 }
1350
1351 #[track_caller]
1355 fn insert_warning<F>(&mut self, warning: W, elem_id: json::ElemId, f: F)
1356 where
1357 F: FnOnce() -> Element,
1358 {
1359 use std::collections::btree_map::Entry;
1360
1361 match self.0.entry(elem_id) {
1362 Entry::Vacant(entry) => {
1363 let element = f();
1364 entry.insert_entry(Group {
1365 element,
1366 warnings: vec![Source::new(warning)],
1367 });
1368 }
1369 Entry::Occupied(mut entry) => {
1370 entry.get_mut().warnings.push(Source::new(warning));
1371 }
1372 }
1373 }
1374
1375 #[track_caller]
1379 pub(crate) fn bail<T>(self, warning: W, element: &json::Element<'_>) -> Verdict<T, W> {
1380 let Self(warnings) = self;
1381
1382 Err(ErrorSet {
1383 error: Box::new(Error {
1384 warning,
1385 element: Element::from(element),
1386 }),
1387 warnings,
1388 })
1389 }
1390
1391 pub(crate) fn into_other<WA>(self) -> Set<WA>
1395 where
1396 W: Into<WA>,
1397 WA: Warning,
1398 {
1399 let Set(warnings) = self;
1400 let warnings = warnings
1401 .into_iter()
1402 .map(|(elem_id, group)| (elem_id, group.into_other()))
1403 .collect();
1404 Set(warnings)
1405 }
1406
1407 pub fn is_empty(&self) -> bool {
1409 self.0.is_empty()
1410 }
1411
1412 pub fn len_elements(&self) -> usize {
1416 self.0.len()
1417 }
1418
1419 pub fn len_warnings(&self) -> usize {
1421 self.0
1422 .values()
1423 .fold(0, |acc, group| acc.saturating_add(group.warnings.len()))
1424 }
1425
1426 pub fn iter(&self) -> Iter<'_, W> {
1428 Iter {
1429 warnings: self.0.iter(),
1430 }
1431 }
1432
1433 pub fn path_map(&self) -> BTreeMap<&str, Vec<&W>> {
1439 self.0
1440 .values()
1441 .map(|Group { element, warnings }| {
1442 let path = element.path.as_str();
1443 let warnings = warnings.iter().map(|w| &**w).collect();
1444 (path, warnings)
1445 })
1446 .collect()
1447 }
1448
1449 pub fn into_path_map(self) -> BTreeMap<Path, Vec<W>> {
1453 self.0
1454 .into_values()
1455 .map(|Group { element, warnings }| {
1456 let warnings = warnings.into_iter().map(Source::into_warning).collect();
1457 (element.path, warnings)
1458 })
1459 .collect()
1460 }
1461
1462 pub fn path_id_map(&self) -> BTreeMap<&str, Vec<Id>> {
1471 self.0
1472 .values()
1473 .map(|group| {
1474 let warnings = group.warnings.iter().map(|w| w.id()).collect();
1475 (group.element.path.as_str(), warnings)
1476 })
1477 .collect()
1478 }
1479
1480 pub fn path_msg_map(&self) -> BTreeMap<&str, Vec<String>> {
1486 self.0
1487 .values()
1488 .map(|group| {
1489 let warnings = group.warnings.iter().map(|w| w.to_string()).collect();
1490 (group.element.path.as_str(), warnings)
1491 })
1492 .collect()
1493 }
1494
1495 pub(crate) fn deescalate_error(&mut self, err_set: ErrorSet<W>) {
1497 let ErrorSet { error, warnings } = err_set;
1498 let Error { warning, element } = *error;
1499 self.0.extend(warnings);
1500 self.insert_warning(warning, element.id, || element);
1501 }
1502
1503 fn extend<WA>(&mut self, warnings: Set<WA>)
1507 where
1508 WA: Into<W> + Warning,
1509 {
1510 use std::collections::btree_map::Entry;
1511
1512 let Set(warnings) = warnings;
1513 let warnings = warnings
1514 .into_iter()
1515 .map(|(elem_id, group)| (elem_id, group.into_other()));
1516
1517 for (elem_id, group) in warnings {
1518 match self.0.entry(elem_id) {
1519 Entry::Vacant(entry) => {
1520 entry.insert_entry(group);
1521 }
1522 Entry::Occupied(mut entry) => {
1523 let Group {
1524 element: _,
1525 warnings,
1526 } = group;
1527 entry.get_mut().warnings.extend(warnings);
1528 }
1529 }
1530 }
1531 }
1532}
1533
1534#[derive(Debug)]
1538pub struct ErrorSet<W: Warning> {
1539 error: Box<Error<W>>,
1543
1544 warnings: BTreeMap<json::ElemId, Group<W>>,
1548}
1549
1550impl<W> ErrorSet<W>
1551where
1552 W: Warning,
1553{
1554 pub(crate) fn with_warn(warning: W, element: &json::Element<'_>) -> Self {
1556 Self {
1557 warnings: BTreeMap::new(),
1558 error: Box::new(Error {
1559 warning,
1560 element: Element::from(element),
1561 }),
1562 }
1563 }
1564
1565 pub fn into_parts(self) -> (Error<W>, Set<W>) {
1567 let Self { error, warnings } = self;
1568 (*error, Set(warnings))
1569 }
1570
1571 pub(crate) fn into_other<WA>(self) -> ErrorSet<WA>
1575 where
1576 W: Into<WA>,
1577 WA: Warning,
1578 {
1579 let Self { error, warnings } = self;
1580 let warnings = warnings
1581 .into_iter()
1582 .map(|(elem_id, group)| (elem_id, group.into_other()))
1583 .collect();
1584 ErrorSet {
1585 error: Box::new(Error::into_other(*error)),
1586 warnings,
1587 }
1588 }
1589}
1590
1591#[derive(Debug)]
1596pub struct Group<W: Warning> {
1597 element: Element,
1599
1600 warnings: Vec<Source<W>>,
1602}
1603
1604impl<W> Group<W>
1605where
1606 W: Warning,
1607{
1608 pub fn into_parts(self) -> (Element, Vec<W>) {
1609 let Self { element, warnings } = self;
1610 let warnings = warnings.into_iter().map(Source::into_warning).collect();
1611 (element, warnings)
1612 }
1613
1614 pub fn to_parts(&self) -> (&Element, Vec<&W>) {
1615 let Self { element, warnings } = self;
1616 let warnings = warnings.iter().map(|w| &**w).collect();
1617 (element, warnings)
1618 }
1619
1620 pub fn warnings(&self) -> Vec<&W> {
1621 self.warnings.iter().map(|w| &**w).collect()
1622 }
1623
1624 pub fn into_warnings(self) -> Vec<W> {
1625 let Self {
1626 element: _,
1627 warnings,
1628 } = self;
1629 warnings.into_iter().map(Source::into_warning).collect()
1630 }
1631
1632 fn into_other<WA>(self) -> Group<WA>
1636 where
1637 W: Into<WA>,
1638 WA: Warning,
1639 {
1640 let Self { element, warnings } = self;
1641 let warnings = warnings.into_iter().map(Source::into_other).collect();
1642 Group { element, warnings }
1643 }
1644}
1645
1646pub struct Iter<'caller, W>
1648where
1649 W: Warning,
1650{
1651 warnings: std::collections::btree_map::Iter<'caller, json::ElemId, Group<W>>,
1653}
1654
1655impl<W> Iter<'_, W> where W: Warning {}
1656
1657impl<'caller, W: Warning> Iterator for Iter<'caller, W> {
1658 type Item = &'caller Group<W>;
1659
1660 fn next(&mut self) -> Option<Self::Item> {
1661 let (_elem_id, group) = self.warnings.next()?;
1662 Some(group)
1663 }
1664}
1665
1666pub struct IntoIter<W>
1668where
1669 W: Warning,
1670{
1671 warnings: std::collections::btree_map::IntoIter<json::ElemId, Group<W>>,
1673}
1674
1675impl<W: Warning> Iterator for IntoIter<W> {
1676 type Item = Group<W>;
1677
1678 fn next(&mut self) -> Option<Self::Item> {
1679 let (_elem_id, group) = self.warnings.next()?;
1680 Some(group)
1681 }
1682}
1683
1684impl<W: Warning> IntoIterator for Set<W> {
1685 type Item = Group<W>;
1686 type IntoIter = IntoIter<W>;
1687
1688 fn into_iter(self) -> Self::IntoIter {
1689 let Set(warnings) = self;
1690 IntoIter {
1691 warnings: warnings.into_iter(),
1692 }
1693 }
1694}
1695
1696impl<'a, W: Warning> IntoIterator for &'a Set<W> {
1697 type Item = &'a Group<W>;
1698 type IntoIter = Iter<'a, W>;
1699
1700 fn into_iter(self) -> Self::IntoIter {
1701 self.iter()
1702 }
1703}