1use std::{borrow::Cow, collections::BTreeMap, fmt, ops::Deref, vec};
47
48use tracing::{debug, info};
49
50use crate::json;
51
52#[doc(hidden)]
54#[macro_export]
55macro_rules! into_caveat {
56 ($kind:ident<$life:lifetime>) => {
57 impl<$life> $crate::IntoCaveat for $kind<$life> {
58 fn into_caveat<W: $crate::Warning>(
59 self,
60 warnings: $crate::warning::Set<W>,
61 ) -> $crate::Caveat<Self, W> {
62 $crate::Caveat::new(self, warnings)
63 }
64 }
65 };
66 ($kind:ty) => {
67 impl $crate::IntoCaveat for $kind {
68 fn into_caveat<W: $crate::Warning>(
69 self,
70 warnings: $crate::warning::Set<W>,
71 ) -> $crate::Caveat<Self, W> {
72 $crate::Caveat::new(self, warnings)
73 }
74 }
75
76 impl $crate::warning::IntoCaveatDeferred for $kind {
77 fn into_caveat_deferred<W: $crate::Warning>(
78 self,
79 warnings: $crate::warning::SetDeferred<W>,
80 ) -> $crate::warning::CaveatDeferred<Self, W> {
81 $crate::warning::CaveatDeferred::new(self, warnings)
82 }
83 }
84 };
85}
86
87#[doc(hidden)]
89#[macro_export]
90macro_rules! into_caveat_all {
91 ($($kind:ty),+) => {
92 $($crate::into_caveat!($kind);)+
93 };
94}
95
96#[doc(hidden)]
97#[macro_export]
98macro_rules! from_warning_all {
99 ($($source_kind:path => $target_kind:ident::$target_variant:ident),+) => {
100 $(
101 impl From<$source_kind> for $target_kind {
103 fn from(warning: $source_kind) -> Self {
104 $target_kind::$target_variant(warning)
105 }
106 }
107
108 impl From<$crate::warning::ErrorSet<$source_kind>> for $crate::warning::ErrorSet<$target_kind> {
113 fn from(set_a: $crate::warning::ErrorSet<$source_kind>) -> Self {
114 set_a.into_other()
115 }
116 }
117
118 impl From<$crate::warning::ErrorSetDeferred<$source_kind>> for $crate::warning::ErrorSetDeferred<$target_kind> {
123 fn from(set_a: $crate::warning::ErrorSetDeferred<$source_kind>) -> Self {
124 set_a.into_other()
125 }
126 }
127 )+
128 };
129}
130
131#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)]
132pub struct Id(Cow<'static, str>);
133
134impl Id {
135 pub(crate) fn from_static(s: &'static str) -> Self {
136 Id(s.into())
137 }
138
139 pub(crate) fn from_string(s: String) -> Self {
140 Id(s.into())
141 }
142
143 pub fn as_str(&self) -> &str {
144 &self.0
145 }
146}
147
148impl fmt::Debug for Id {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 f.write_str(&self.0)
151 }
152}
153
154impl fmt::Display for Id {
155 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156 fmt::Display::fmt(&self.0, f)
157 }
158}
159
160#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)]
161pub struct Path(String);
162
163impl Path {
164 pub fn as_str(&self) -> &str {
165 &self.0
166 }
167}
168
169impl fmt::Debug for Path {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 f.write_str(&self.0)
172 }
173}
174
175impl fmt::Display for Path {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 fmt::Display::fmt(&self.0, f)
178 }
179}
180
181pub type Verdict<T, W> = Result<Caveat<T, W>, ErrorSet<W>>;
183
184pub(crate) type VerdictDeferred<T, W> = Result<CaveatDeferred<T, W>, ErrorSetDeferred<W>>;
191
192#[derive(Debug)]
202pub struct CaveatDeferred<T, W: Warning> {
203 value: T,
205
206 warnings: SetDeferred<W>,
208}
209
210impl<T, W> CaveatDeferred<T, W>
211where
212 T: IntoCaveatDeferred,
213 W: Warning,
214{
215 pub(crate) fn new(value: T, warnings: SetDeferred<W>) -> Self {
217 Self { value, warnings }
218 }
219}
220
221impl<T, W> Deref for CaveatDeferred<T, W>
236where
237 W: Warning,
238{
239 type Target = T;
240
241 fn deref(&self) -> &T {
242 &self.value
243 }
244}
245
246impl<T, W> CaveatDeferred<T, W>
247where
248 W: Warning,
249{
250 pub fn into_parts(self) -> (T, SetDeferred<W>) {
252 let Self { value, warnings } = self;
253 (value, warnings)
254 }
255
256 pub fn ignore_warnings(self) -> T {
258 self.value
259 }
260
261 pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> CaveatDeferred<U, W> {
263 let Self { value, warnings } = self;
264 CaveatDeferred {
265 value: op(value),
266 warnings,
267 }
268 }
269}
270
271#[derive(Debug)]
275pub struct Caveat<T, W: Warning> {
276 value: T,
278
279 warnings: Set<W>,
281}
282
283impl<T, W> Caveat<T, W>
284where
285 T: IntoCaveat,
286 W: Warning,
287{
288 pub(crate) fn new(value: T, warnings: Set<W>) -> Self {
290 Self { value, warnings }
291 }
292}
293
294impl<T, W> Deref for Caveat<T, W>
307where
308 W: Warning,
309{
310 type Target = T;
311
312 fn deref(&self) -> &T {
313 &self.value
314 }
315}
316
317impl<T, W> Caveat<T, W>
318where
319 W: Warning,
320{
321 pub fn into_parts(self) -> (T, Set<W>) {
323 let Self { value, warnings } = self;
324 (value, warnings)
325 }
326
327 pub fn ignore_warnings(self) -> T {
329 self.value
330 }
331
332 pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Caveat<U, W> {
334 let Self { value, warnings } = self;
335 Caveat {
336 value: op(value),
337 warnings,
338 }
339 }
340}
341
342pub(crate) trait GatherWarnings<T, W>
347where
348 W: Warning,
349{
350 type Output;
352
353 #[must_use = "If you want to ignore the value use `let _ =`"]
355 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
356 where
357 W: Into<WA>,
358 WA: Warning;
359}
360
361impl<T, W> GatherWarnings<T, W> for Caveat<T, W>
363where
364 W: Warning,
365{
366 type Output = T;
367
368 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
370 where
371 W: Into<WA>,
372 WA: Warning,
373 {
374 let Self {
375 value,
376 warnings: inner_warnings,
377 } = self;
378
379 warnings.extend(inner_warnings);
380
381 value
382 }
383}
384
385impl<T, W> GatherWarnings<T, W> for Option<Caveat<T, W>>
387where
388 W: Warning,
389{
390 type Output = Option<T>;
391
392 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
394 where
395 W: Into<WA>,
396 WA: Warning,
397 {
398 match self {
399 Some(cv) => Some(cv.gather_warnings_into(warnings)),
400 None => None,
401 }
402 }
403}
404
405impl<T, W, E> GatherWarnings<T, W> for Result<Caveat<T, W>, E>
407where
408 W: Warning,
409 E: std::error::Error,
410{
411 type Output = Result<T, E>;
412
413 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
415 where
416 W: Into<WA>,
417 WA: Warning,
418 {
419 match self {
420 Ok(cv) => Ok(cv.gather_warnings_into(warnings)),
421 Err(err) => Err(err),
422 }
423 }
424}
425
426impl<T, W> GatherWarnings<T, W> for Verdict<T, W>
428where
429 W: Warning,
430{
431 type Output = Result<T, ErrorSet<W>>;
432
433 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
436 where
437 W: Into<WA>,
438 WA: Warning,
439 {
440 match self {
441 Ok(cv) => Ok(cv.gather_warnings_into(warnings)),
442 Err(err_set) => Err(err_set),
443 }
444 }
445}
446
447pub(crate) trait DeescalateError<T, W>
452where
453 W: Warning,
454{
455 #[must_use = "If you want to ignore the value use `let _ =`"]
457 fn deescalate_error_into<WA>(self, warnings: &mut Set<WA>) -> Option<T>
458 where
459 W: Into<WA>,
460 WA: Warning;
461}
462
463impl<T, W> DeescalateError<T, W> for Verdict<T, W>
465where
466 W: Warning,
467{
468 fn deescalate_error_into<WA>(self, warnings: &mut Set<WA>) -> Option<T>
471 where
472 W: Into<WA>,
473 WA: Warning,
474 {
475 match self {
476 Ok(cv) => Some(cv.gather_warnings_into(warnings)),
477 Err(err_set) => {
478 warnings.deescalate_error(err_set.into_other());
479 None
480 }
481 }
482 }
483}
484
485impl<T, W> DeescalateError<T, W> for Result<T, ErrorSet<W>>
487where
488 W: Warning,
489{
490 fn deescalate_error_into<WA>(self, warnings: &mut Set<WA>) -> Option<T>
493 where
494 W: Into<WA>,
495 WA: Warning,
496 {
497 match self {
498 Ok(cv) => Some(cv),
499 Err(err_set) => {
500 warnings.deescalate_error(err_set.into_other());
501 None
502 }
503 }
504 }
505}
506
507impl<T, W> GatherWarnings<T, W> for Vec<Caveat<T, W>>
509where
510 W: Warning,
511{
512 type Output = Vec<T>;
513
514 fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
516 where
517 W: Into<WA>,
518 WA: Warning,
519 {
520 self.into_iter()
521 .map(|cv| cv.gather_warnings_into(warnings))
522 .collect()
523 }
524}
525
526pub(crate) trait GatherDeferredWarnings<T, W>
531where
532 W: Warning,
533{
534 type Output;
536
537 #[must_use = "If you want to ignore the value use `let _ =`"]
539 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
540 where
541 W: Into<WA>,
542 WA: Warning;
543}
544
545impl<T, W> GatherDeferredWarnings<T, W> for CaveatDeferred<T, W>
547where
548 W: Warning,
549{
550 type Output = T;
551
552 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
554 where
555 W: Into<WA>,
556 WA: Warning,
557 {
558 let Self {
559 value,
560 warnings: inner_warnings,
561 } = self;
562
563 warnings.extend(inner_warnings);
564
565 value
566 }
567}
568
569impl<T, W> GatherDeferredWarnings<T, W> for Option<CaveatDeferred<T, W>>
571where
572 W: Warning,
573{
574 type Output = Option<T>;
575
576 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
578 where
579 W: Into<WA>,
580 WA: Warning,
581 {
582 match self {
583 Some(cv) => Some(cv.gather_deferred_warnings_into(warnings)),
584 None => None,
585 }
586 }
587}
588
589impl<T, W, E> GatherDeferredWarnings<T, W> for Result<CaveatDeferred<T, W>, E>
591where
592 W: Warning,
593 E: std::error::Error,
594{
595 type Output = Result<T, E>;
596
597 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
599 where
600 W: Into<WA>,
601 WA: Warning,
602 {
603 match self {
604 Ok(cv) => Ok(cv.gather_deferred_warnings_into(warnings)),
605 Err(err) => Err(err),
606 }
607 }
608}
609
610impl<T, W> GatherDeferredWarnings<T, W> for VerdictDeferred<T, W>
612where
613 W: Warning,
614{
615 type Output = Result<T, ErrorSetDeferred<W>>;
616
617 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
620 where
621 W: Into<WA>,
622 WA: Warning,
623 {
624 match self {
625 Ok(cv) => Ok(cv.gather_deferred_warnings_into(warnings)),
626 Err(err_set) => Err(err_set),
627 }
628 }
629}
630
631impl<T, W> GatherDeferredWarnings<T, W> for Vec<CaveatDeferred<T, W>>
633where
634 W: Warning,
635{
636 type Output = Vec<T>;
637
638 fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
640 where
641 W: Into<WA>,
642 WA: Warning,
643 {
644 self.into_iter()
645 .map(|cv| cv.gather_deferred_warnings_into(warnings))
646 .collect()
647 }
648}
649
650pub trait IntoCaveat: Sized {
654 fn into_caveat<W: Warning>(self, warnings: Set<W>) -> Caveat<Self, W>;
656}
657
658pub trait IntoCaveatDeferred: Sized {
662 fn into_caveat_deferred<W: Warning>(self, warnings: SetDeferred<W>) -> CaveatDeferred<Self, W>;
664}
665
666macro_rules! peel {
668 ($name:ident, $($other:ident,)*) => (into_caveat_tuple! { $($other,)* })
669}
670
671macro_rules! into_caveat_tuple {
674 () => ();
675 ( $($name:ident,)+ ) => (
676 impl<$($name),+> $crate::IntoCaveat for ($($name,)+) {
677 fn into_caveat<W: $crate::Warning>(
678 self,
679 warnings: $crate::warning::Set<W>,
680 ) -> $crate::Caveat<Self, W> {
681 $crate::Caveat::new(self, warnings)
682 }
683 }
684
685 impl<$($name),+> $crate::warning::IntoCaveatDeferred for ($($name,)+) {
686 fn into_caveat_deferred<W: $crate::Warning>(
687 self,
688 warnings: SetDeferred<W>,
689 ) -> $crate::warning::CaveatDeferred<Self, W> {
690 $crate::warning::CaveatDeferred::new(self, warnings)
691 }
692 }
693 peel! { $($name,)+ }
694 )
695}
696
697into_caveat_tuple! { T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
700
701into_caveat_all!(
703 (),
704 bool,
705 char,
706 u8,
707 u16,
708 u32,
709 u64,
710 u128,
711 i8,
712 i16,
713 i32,
714 i64,
715 i128
716);
717
718impl IntoCaveat for Cow<'_, str> {
720 fn into_caveat<W: Warning>(self, warnings: Set<W>) -> Caveat<Self, W> {
721 Caveat::new(self, warnings)
722 }
723}
724
725impl<T> IntoCaveat for Option<T>
727where
728 T: IntoCaveat,
729{
730 fn into_caveat<W: Warning>(self, warnings: Set<W>) -> Caveat<Self, W> {
731 Caveat::new(self, warnings)
732 }
733}
734
735impl<T> IntoCaveat for Vec<T>
737where
738 T: IntoCaveat,
739{
740 fn into_caveat<W: Warning>(self, warnings: Set<W>) -> Caveat<Self, W> {
741 Caveat::new(self, warnings)
742 }
743}
744
745impl<T> IntoCaveatDeferred for Vec<T>
747where
748 T: IntoCaveat,
749{
750 fn into_caveat_deferred<W: Warning>(self, warnings: SetDeferred<W>) -> CaveatDeferred<Self, W> {
751 CaveatDeferred::new(self, warnings)
752 }
753}
754
755pub trait VerdictExt<T, W: Warning> {
757 fn map_caveat<F, U>(self, op: F) -> Verdict<U, W>
760 where
761 F: FnOnce(T) -> U;
762
763 fn only_error(self) -> Result<Caveat<T, W>, Error<W>>;
765}
766
767#[allow(dead_code, reason = "for debugging")]
768pub(crate) trait VerdictTrace<T, W: Warning> {
769 fn info_verdict(self, msg: &'static str) -> Self;
770 fn debug_verdict(self, msg: &'static str) -> Self;
771}
772
773#[allow(dead_code, reason = "for debugging")]
774pub(crate) trait ResultTrace<T, W: Warning> {
775 fn info_result(self, msg: &'static str) -> Self;
776 fn debug_result(self, msg: &'static str) -> Self;
777}
778
779impl<T, W: Warning> VerdictExt<T, W> for Verdict<T, W> {
780 fn map_caveat<F, U>(self, op: F) -> Verdict<U, W>
781 where
782 F: FnOnce(T) -> U,
783 {
784 match self {
785 Ok(c) => Ok(c.map(op)),
786 Err(w) => Err(w),
787 }
788 }
789
790 fn only_error(self) -> Result<Caveat<T, W>, Error<W>> {
791 match self {
792 Ok(c) => Ok(c),
793 Err(err_set) => {
794 let ErrorSet { error, warnings: _ } = err_set;
795 Err(*error)
796 }
797 }
798 }
799}
800
801impl<T, W: Warning> VerdictTrace<T, W> for Verdict<T, W>
802where
803 T: fmt::Debug,
804{
805 fn info_verdict(self, msg: &'static str) -> Self {
806 match self {
807 Ok(c) => {
808 info!("{msg}: {c:#?}");
809 Ok(c)
810 }
811 Err(err_set) => {
812 info!("{msg}: {err_set:#?}");
813 Err(err_set)
814 }
815 }
816 }
817
818 fn debug_verdict(self, msg: &'static str) -> Self {
819 match self {
820 Ok(c) => {
821 debug!("{msg}: {c:#?}");
822 Ok(c)
823 }
824 Err(err_set) => {
825 debug!("{msg}: {err_set:#?}");
826 Err(err_set)
827 }
828 }
829 }
830}
831
832impl<T, W: Warning> ResultTrace<T, W> for Result<T, ErrorSet<W>>
833where
834 T: fmt::Debug,
835{
836 fn info_result(self, msg: &'static str) -> Self {
837 match self {
838 Ok(c) => {
839 info!("{msg}: {c:#?}");
840 Ok(c)
841 }
842 Err(err_set) => {
843 info!("{msg}: {err_set:#?}");
844 Err(err_set)
845 }
846 }
847 }
848
849 fn debug_result(self, msg: &'static str) -> Self {
850 match self {
851 Ok(c) => {
852 debug!("{msg}: {c:#?}");
853 Ok(c)
854 }
855 Err(err_set) => {
856 debug!("{msg}: {err_set:#?}");
857 Err(err_set)
858 }
859 }
860 }
861}
862
863#[derive(Debug)]
867pub struct Error<W: Warning> {
868 warning: W,
870
871 element: Element,
873}
874
875impl<W: Warning> Error<W> {
876 pub fn warning(&self) -> &W {
878 &self.warning
879 }
880
881 pub fn into_warning(self) -> W {
883 self.warning
884 }
885
886 pub fn element(&self) -> &Element {
888 &self.element
889 }
890
891 pub fn parts(&self) -> (&W, &Element) {
893 (&self.warning, &self.element)
894 }
895
896 pub fn into_parts(self) -> (W, Element) {
898 let Self { warning, element } = self;
899 (warning, element)
900 }
901
902 fn into_other<WA>(self) -> Error<WA>
906 where
907 W: Into<WA>,
908 WA: Warning,
909 {
910 let Self { warning, element } = self;
911 Error {
912 warning: warning.into(),
913 element,
914 }
915 }
916}
917
918impl<W: Warning> std::error::Error for Error<W> {}
919
920impl<W: Warning> fmt::Display for Error<W> {
921 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
922 write!(
923 f,
924 "A warning for element at `{}` was upgraded to an `error`: {}",
925 self.element.path, self.warning
926 )
927 }
928}
929
930pub trait WithElement<T, W: Warning> {
932 fn with_element(self, element: &json::Element<'_>) -> Verdict<T, W>;
933}
934
935impl<T, W: Warning> WithElement<T, W> for VerdictDeferred<T, W> {
936 fn with_element(self, element: &json::Element<'_>) -> Verdict<T, W> {
938 match self {
939 Ok(v) => {
940 let CaveatDeferred { value, warnings } = v;
941 let SetDeferred(warnings) = warnings;
942 Ok(Caveat {
943 value,
944 warnings: Set(warnings),
945 })
946 }
947 Err(set) => {
948 let ErrorSetDeferred { error, warnings } = set;
949 Err(ErrorSet {
950 error: Box::new(Error {
951 warning: error,
952 element: Element::from(element),
953 }),
954 warnings,
955 })
956 }
957 }
958 }
959}
960
961#[derive(Debug)]
971pub struct Element {
972 pub id: json::ElemId,
976
977 pub span: json::parser::Span,
979
980 pub path: Path,
984}
985
986impl<'buf> From<&json::Element<'buf>> for Element {
987 fn from(elem: &json::Element<'buf>) -> Self {
988 Self {
989 id: elem.id(),
990 span: elem.span(),
991 path: Path(elem.path().to_string()),
992 }
993 }
994}
995
996pub struct SetWriter<'caller, W: Warning> {
1010 warnings: &'caller Set<W>,
1012
1013 indent: &'caller str,
1015}
1016
1017impl<'caller, W: Warning> SetWriter<'caller, W> {
1018 pub fn new(warnings: &'caller Set<W>) -> Self {
1020 Self {
1021 warnings,
1022 indent: " - ",
1023 }
1024 }
1025
1026 pub fn with_indent(warnings: &'caller Set<W>, indent: &'caller str) -> Self {
1028 Self { warnings, indent }
1029 }
1030}
1031
1032impl<W: Warning> fmt::Debug for SetWriter<'_, W> {
1033 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1034 fmt::Display::fmt(self, f)
1035 }
1036}
1037
1038impl<W: Warning> fmt::Display for SetWriter<'_, W> {
1039 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1040 let mut iter = self.warnings.iter();
1041
1042 {
1043 let Some(Group { element, warnings }) = iter.next() else {
1045 return Ok(());
1046 };
1047
1048 writeln!(f, "{}", element.path)?;
1049
1050 for warning in warnings {
1051 write!(f, "{}{}", self.indent, warning)?;
1052 }
1053 }
1054
1055 for Group { element, warnings } in iter {
1057 writeln!(f, "\n{}", element.path)?;
1058
1059 for warning in warnings {
1060 write!(f, "{}{}", self.indent, warning)?;
1061 }
1062 }
1063
1064 Ok(())
1065 }
1066}
1067
1068pub trait Warning: Sized + fmt::Debug + fmt::Display + Send + Sync {
1072 fn id(&self) -> Id;
1077}
1078
1079#[derive(Debug)]
1088pub struct SetDeferred<W: Warning>(BTreeMap<json::ElemId, Group<W>>);
1089
1090impl<W: Warning> SetDeferred<W> {
1091 pub(crate) fn new() -> Self {
1093 Self(BTreeMap::new())
1094 }
1095
1096 pub(crate) fn bail<T>(self, warning: W) -> VerdictDeferred<T, W> {
1100 let Self(warnings) = self;
1101 Err(ErrorSetDeferred {
1102 error: warning,
1103 warnings,
1104 })
1105 }
1106
1107 pub fn is_empty(&self) -> bool {
1109 self.0.is_empty()
1110 }
1111
1112 pub(crate) fn extend<WA>(&mut self, warnings: SetDeferred<WA>)
1116 where
1117 WA: Into<W> + Warning,
1118 {
1119 let SetDeferred(warnings) = warnings;
1120 self.0
1121 .extend(warnings.into_iter().map(|(k, v)| (k, v.into_other())));
1122 }
1123}
1124
1125#[derive(Debug)]
1135pub struct ErrorSetDeferred<W: Warning> {
1136 error: W,
1137 warnings: BTreeMap<json::ElemId, Group<W>>,
1138}
1139
1140impl<W: Warning> ErrorSetDeferred<W> {
1141 pub(crate) fn with_warn(warning: W) -> Self {
1143 Self {
1144 warnings: BTreeMap::new(),
1145 error: warning,
1146 }
1147 }
1148
1149 pub(crate) fn into_other<WA>(self) -> ErrorSetDeferred<WA>
1153 where
1154 W: Into<WA>,
1155 WA: Warning,
1156 {
1157 let Self { error, warnings } = self;
1158 let warnings = warnings
1159 .into_iter()
1160 .map(|(k, v)| (k, v.into_other()))
1161 .collect();
1162 ErrorSetDeferred {
1163 error: error.into(),
1164 warnings,
1165 }
1166 }
1167}
1168
1169#[derive(Debug)]
1171pub struct Set<W: Warning>(BTreeMap<json::ElemId, Group<W>>);
1172
1173impl<W: Warning> Set<W> {
1174 pub(crate) fn new() -> Self {
1176 Self(BTreeMap::new())
1177 }
1178
1179 pub(crate) fn with_elem(&mut self, warning: W, element: &json::Element<'_>) {
1181 self.insert_warning(warning, element.id(), || Element::from(element));
1182 }
1183
1184 fn insert_warning<F>(&mut self, warning: W, elem_id: json::ElemId, f: F)
1188 where
1189 F: FnOnce() -> Element,
1190 {
1191 use std::collections::btree_map::Entry;
1192
1193 match self.0.entry(elem_id) {
1194 Entry::Vacant(entry) => {
1195 let element = f();
1196 entry.insert_entry(Group {
1197 element,
1198 warnings: vec![warning],
1199 });
1200 }
1201 Entry::Occupied(mut entry) => {
1202 entry.get_mut().warnings.push(warning);
1203 }
1204 }
1205 }
1206
1207 pub(crate) fn bail<T>(self, warning: W, element: &json::Element<'_>) -> Verdict<T, W> {
1211 let Self(warnings) = self;
1212
1213 Err(ErrorSet {
1214 error: Box::new(Error {
1215 warning,
1216 element: Element::from(element),
1217 }),
1218 warnings,
1219 })
1220 }
1221
1222 pub(crate) fn into_other<WA>(self) -> Set<WA>
1226 where
1227 W: Into<WA>,
1228 WA: Warning,
1229 {
1230 let Set(warnings) = self;
1231 let warnings = warnings
1232 .into_iter()
1233 .map(|(elem_id, group)| (elem_id, group.into_other()))
1234 .collect();
1235 Set(warnings)
1236 }
1237
1238 pub fn is_empty(&self) -> bool {
1240 self.0.is_empty()
1241 }
1242
1243 pub fn len_elements(&self) -> usize {
1247 self.0.len()
1248 }
1249
1250 pub fn len_warnings(&self) -> usize {
1252 self.0
1253 .values()
1254 .fold(0, |acc, group| acc + group.warnings.len())
1255 }
1256
1257 pub fn iter(&self) -> Iter<'_, W> {
1259 Iter {
1260 warnings: self.0.iter(),
1261 }
1262 }
1263
1264 pub fn path_map(&self) -> BTreeMap<&str, &[W]> {
1270 self.0
1271 .values()
1272 .map(|group| (group.element.path.as_str(), group.warnings.as_slice()))
1273 .collect()
1274 }
1275
1276 pub fn into_path_map(self) -> BTreeMap<Path, Vec<W>> {
1280 self.0
1281 .into_values()
1282 .map(|group| (group.element.path, group.warnings))
1283 .collect()
1284 }
1285
1286 pub fn path_id_map(&self) -> BTreeMap<&str, Vec<Id>> {
1295 self.0
1296 .values()
1297 .map(|group| {
1298 let warnings = group.warnings.iter().map(Warning::id).collect();
1299 (group.element.path.as_str(), warnings)
1300 })
1301 .collect()
1302 }
1303
1304 pub fn path_msg_map(&self) -> BTreeMap<&str, Vec<String>> {
1310 self.0
1311 .values()
1312 .map(|group| {
1313 let warnings = group.warnings.iter().map(ToString::to_string).collect();
1314 (group.element.path.as_str(), warnings)
1315 })
1316 .collect()
1317 }
1318
1319 pub(crate) fn deescalate_error(&mut self, err_set: ErrorSet<W>) {
1321 let ErrorSet { error, warnings } = err_set;
1322 let Error { warning, element } = *error;
1323 self.0.extend(warnings);
1324 self.insert_warning(warning, element.id, || element);
1325 }
1326
1327 fn extend<WA>(&mut self, warnings: Set<WA>)
1331 where
1332 WA: Into<W> + Warning,
1333 {
1334 use std::collections::btree_map::Entry;
1335
1336 let Set(warnings) = warnings;
1337 let warnings = warnings
1338 .into_iter()
1339 .map(|(elem_id, group)| (elem_id, group.into_other()));
1340
1341 for (elem_id, group) in warnings {
1342 match self.0.entry(elem_id) {
1343 Entry::Vacant(entry) => {
1344 entry.insert_entry(group);
1345 }
1346 Entry::Occupied(mut entry) => {
1347 let Group {
1348 element: _,
1349 warnings,
1350 } = group;
1351 entry.get_mut().warnings.extend(warnings);
1352 }
1353 }
1354 }
1355 }
1356}
1357
1358#[derive(Debug)]
1362pub struct ErrorSet<W: Warning> {
1363 error: Box<Error<W>>,
1367
1368 warnings: BTreeMap<json::ElemId, Group<W>>,
1372}
1373
1374impl<W> ErrorSet<W>
1375where
1376 W: Warning,
1377{
1378 pub fn into_parts(self) -> (Error<W>, Set<W>) {
1380 let Self { error, warnings } = self;
1381 (*error, Set(warnings))
1382 }
1383
1384 pub(crate) fn into_other<WA>(self) -> ErrorSet<WA>
1388 where
1389 W: Into<WA>,
1390 WA: Warning,
1391 {
1392 let Self { error, warnings } = self;
1393 let warnings = warnings
1394 .into_iter()
1395 .map(|(elem_id, group)| (elem_id, group.into_other()))
1396 .collect();
1397 ErrorSet {
1398 error: Box::new(Error::into_other(*error)),
1399 warnings,
1400 }
1401 }
1402}
1403
1404#[derive(Debug)]
1409pub struct Group<W> {
1410 pub element: Element,
1412
1413 pub warnings: Vec<W>,
1415}
1416
1417impl<W> Group<W>
1418where
1419 W: Warning,
1420{
1421 fn into_other<WA>(self) -> Group<WA>
1425 where
1426 W: Into<WA>,
1427 WA: Warning,
1428 {
1429 let Self { element, warnings } = self;
1430 let warnings = warnings.into_iter().map(Into::into).collect();
1431 Group { element, warnings }
1432 }
1433}
1434
1435pub struct Iter<'caller, W>
1437where
1438 W: Warning,
1439{
1440 warnings: std::collections::btree_map::Iter<'caller, json::ElemId, Group<W>>,
1442}
1443
1444impl<W> Iter<'_, W> where W: Warning {}
1445
1446impl<'caller, W: Warning> Iterator for Iter<'caller, W> {
1447 type Item = &'caller Group<W>;
1448
1449 fn next(&mut self) -> Option<Self::Item> {
1450 let (_elem_id, group) = self.warnings.next()?;
1451 Some(group)
1452 }
1453}
1454
1455pub struct IntoIter<W>
1457where
1458 W: Warning,
1459{
1460 warnings: std::collections::btree_map::IntoIter<json::ElemId, Group<W>>,
1462}
1463
1464impl<W: Warning> Iterator for IntoIter<W> {
1465 type Item = Group<W>;
1466
1467 fn next(&mut self) -> Option<Self::Item> {
1468 let (_elem_id, group) = self.warnings.next()?;
1469 Some(group)
1470 }
1471}
1472
1473impl<W: Warning> IntoIterator for Set<W> {
1474 type Item = Group<W>;
1475 type IntoIter = IntoIter<W>;
1476
1477 fn into_iter(self) -> Self::IntoIter {
1478 let Set(warnings) = self;
1479 IntoIter {
1480 warnings: warnings.into_iter(),
1481 }
1482 }
1483}
1484
1485impl<'a, W: Warning> IntoIterator for &'a Set<W> {
1486 type Item = &'a Group<W>;
1487 type IntoIter = Iter<'a, W>;
1488
1489 fn into_iter(self) -> Self::IntoIter {
1490 self.iter()
1491 }
1492}
1493
1494#[cfg(test)]
1495pub(crate) mod test {
1496 use std::{
1497 collections::{BTreeMap, BTreeSet},
1498 fmt,
1499 };
1500
1501 use crate::test::{ExpectValue, Expectation};
1502
1503 use super::{Caveat, CaveatDeferred, Error, ErrorSet, Group, Id, Set, Verdict, Warning};
1504
1505 pub trait VerdictTestExt<T, W: Warning> {
1507 fn unwrap_only_error(self) -> Error<W>;
1509 }
1510
1511 impl<T, W: Warning> VerdictTestExt<T, W> for Verdict<T, W>
1512 where
1513 T: fmt::Debug,
1514 {
1515 fn unwrap_only_error(self) -> Error<W> {
1516 match self {
1517 Ok(c) => panic!("called `Result::unwrap_only_error` on an `Ok` value: {c:?}"),
1518 Err(set) => {
1519 let ErrorSet { error, warnings: _ } = set;
1520 *error
1521 }
1522 }
1523 }
1524 }
1525
1526 impl<T, W> Caveat<T, W>
1527 where
1528 W: Warning,
1529 {
1530 pub fn unwrap(self) -> T {
1536 let Self { value, warnings } = self;
1537 assert!(warnings.is_empty(), "{warnings:#?}");
1538 value
1539 }
1540 }
1541
1542 impl<T, W> CaveatDeferred<T, W>
1543 where
1544 W: Warning,
1545 {
1546 pub fn unwrap(self) -> T {
1552 let Self { value, warnings } = self;
1553 assert!(warnings.is_empty(), "{warnings:#?}");
1554 value
1555 }
1556 }
1557
1558 impl<W> Group<W>
1559 where
1560 W: Warning,
1561 {
1562 fn path_and_ids(&self) -> (&str, Vec<Id>) {
1567 let Self { element, warnings } = self;
1568 (
1569 element.path.as_str(),
1570 warnings.iter().map(Warning::id).collect(),
1571 )
1572 }
1573 }
1574
1575 impl<W> Set<W>
1576 where
1577 W: Warning,
1578 {
1579 pub fn into_path_as_str_map(self) -> BTreeMap<String, Vec<W>> {
1583 self.0
1584 .into_values()
1585 .map(|group| (group.element.path.0, group.warnings))
1586 .collect()
1587 }
1588 }
1589
1590 pub(crate) fn assert_warnings<W>(
1594 expect_file_name: &str,
1595 warnings: &Set<W>,
1596 expected: Expectation<BTreeMap<String, Vec<String>>>,
1597 ) where
1598 W: Warning,
1599 {
1600 let Expectation::Present(ExpectValue::Some(mut expected)) = expected else {
1601 assert!(
1602 warnings.is_empty(),
1603 "There is no `warnings` field in the `{expect_file_name}` file but the tariff has warnings;\n{:?}",
1604 warnings.path_id_map()
1605 );
1606 return;
1607 };
1608
1609 {
1610 let warnings_grouped = warnings
1612 .iter()
1613 .map(|Group { element, warnings }| (element.path.as_str(), warnings))
1614 .collect::<BTreeMap<_, _>>();
1615
1616 let mut elems_in_expect_without_warning = vec![];
1617
1618 for elem_path in expected.keys() {
1619 if !warnings_grouped.contains_key(elem_path.as_str()) {
1620 elems_in_expect_without_warning.push(elem_path);
1621 }
1622 }
1623
1624 assert!(elems_in_expect_without_warning.is_empty(),
1625 "The expect file `{expect_file_name}` has entries for elements that have no warnings:\n\
1626 {elems_in_expect_without_warning:#?}"
1627 );
1628 }
1629
1630 let mut elems_missing_from_expect = vec![];
1632 let mut unequal_warnings = vec![];
1635
1636 for group in warnings {
1637 let Some(warnings_expected) = expected.remove(group.element.path.as_str()) else {
1638 elems_missing_from_expect.push(group);
1639 continue;
1640 };
1641
1642 let warnings_expected = warnings_expected
1644 .into_iter()
1645 .map(Id::from_string)
1646 .collect::<BTreeSet<_>>();
1647 let warnings = group
1648 .warnings
1649 .iter()
1650 .map(|w| w.id())
1651 .collect::<BTreeSet<_>>();
1652
1653 if warnings_expected != warnings {
1654 unequal_warnings.push(group);
1655 }
1656 }
1657
1658 if !elems_missing_from_expect.is_empty() || !unequal_warnings.is_empty() {
1659 let missing = elems_missing_from_expect
1660 .into_iter()
1661 .map(Group::path_and_ids)
1662 .collect::<BTreeMap<_, _>>();
1663
1664 let unequal = unequal_warnings
1665 .into_iter()
1666 .map(Group::path_and_ids)
1667 .collect::<BTreeMap<_, _>>();
1668
1669 match (!missing.is_empty(), !unequal.is_empty()) {
1670 (true, true) => panic!(
1671 "Elements with warnings but are not defined in the `{expect_file_name}` file:\n{missing:#?}\n\
1672 Elements that are in the `{expect_file_name}` file but the warnings list is not correct.\n\
1673 The warnings reported are: \n{unequal:#?}"
1674 ),
1675 (true, false) => panic!("Elements with warnings but are not defined in the `{expect_file_name}` file:\n{missing:#?}"),
1676 (false, true) => panic!(
1677 "Elements that are in the `{expect_file_name}` file but the warnings list is not correct.\n\
1678 The warnings reported are: \n{unequal:#?}"
1679 ),
1680 (false, false) => (),
1681 }
1682 }
1683 }
1684}
1685
1686#[cfg(test)]
1687mod test_group_by_elem {
1688 use std::fmt;
1689
1690 use assert_matches::assert_matches;
1691
1692 use crate::{json, test, warning};
1693
1694 use super::{Group, Id, Path, Set};
1695
1696 #[derive(Debug)]
1697 enum Warning {
1698 Root,
1699 One,
1700 OneAgain,
1701 Three,
1702 }
1703
1704 impl super::Warning for Warning {
1705 fn id(&self) -> Id {
1706 match self {
1707 Warning::Root => Id::from_static("root"),
1708 Warning::One => Id::from_static("one"),
1709 Warning::OneAgain => Id::from_static("one_again"),
1710 Warning::Three => Id::from_static("three"),
1711 }
1712 }
1713 }
1714
1715 impl fmt::Display for Warning {
1716 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1717 match self {
1718 Warning::Root => write!(f, "NopeRoot"),
1719 Warning::One => write!(f, "NopeOne"),
1720 Warning::OneAgain => write!(f, "NopeOneAgain"),
1721 Warning::Three => write!(f, "NopeThree"),
1722 }
1723 }
1724 }
1725
1726 #[test]
1727 fn should_group_by_elem() {
1728 test::setup();
1729
1730 let mut warnings = Set::<Warning>::new();
1731
1732 warnings.insert_warning(Warning::Root, json::ElemId::from(0), || warning::Element {
1735 id: json::ElemId::from(0),
1736 path: Path("$".to_owned()),
1737 span: json::parser::Span::default(),
1738 });
1739 warnings.insert_warning(Warning::One, json::ElemId::from(1), || warning::Element {
1740 id: json::ElemId::from(1),
1741 path: Path("$.field_one".to_owned()),
1742 span: json::parser::Span::default(),
1743 });
1744 warnings.insert_warning(Warning::Three, json::ElemId::from(3), || warning::Element {
1745 id: json::ElemId::from(3),
1746 path: Path("$.field_three".to_owned()),
1747 span: json::parser::Span::default(),
1748 });
1749 warnings.insert_warning(Warning::OneAgain, json::ElemId::from(1), || {
1750 warning::Element {
1751 id: json::ElemId::from(1),
1752 path: Path("$.field_one".to_owned()),
1753 span: json::parser::Span::default(),
1754 }
1755 });
1756
1757 let mut iter = warnings.iter();
1758
1759 {
1760 let Group { element, warnings } = iter.next().unwrap();
1761
1762 assert_eq!(
1763 element.path.as_str(),
1764 "$",
1765 "The root object should be emitted first"
1766 );
1767 assert_matches!(warnings.as_slice(), [Warning::Root]);
1768 }
1769
1770 {
1771 let Group { element, warnings } = iter.next().unwrap();
1772
1773 assert_eq!(element.path.as_str(), "$.field_one");
1774 assert_matches!(
1775 warnings.as_slice(),
1776 [Warning::One, Warning::OneAgain],
1777 "[`json::Element`] 1 should have two warnings"
1778 );
1779 }
1780
1781 {
1782 let Group { element, warnings } = iter.next().unwrap();
1784
1785 assert_eq!(element.path.as_str(), "$.field_three");
1786 assert_matches!(warnings.as_slice(), [Warning::Three]);
1787 }
1788 }
1789
1790 #[test]
1791 fn should_into_group_by_elem() {
1792 test::setup();
1793
1794 let mut warnings = Set::<Warning>::new();
1795
1796 warnings.insert_warning(Warning::Root, json::ElemId::from(0), || warning::Element {
1799 id: json::ElemId::from(0),
1800 path: Path("$".to_owned()),
1801 span: json::parser::Span::default(),
1802 });
1803 warnings.insert_warning(Warning::One, json::ElemId::from(1), || warning::Element {
1804 id: json::ElemId::from(1),
1805 path: Path("$.field_one".to_owned()),
1806 span: json::parser::Span::default(),
1807 });
1808 warnings.insert_warning(Warning::Three, json::ElemId::from(3), || warning::Element {
1809 id: json::ElemId::from(3),
1810 path: Path("$.field_three".to_owned()),
1811 span: json::parser::Span::default(),
1812 });
1813 warnings.insert_warning(Warning::OneAgain, json::ElemId::from(1), || {
1814 warning::Element {
1815 id: json::ElemId::from(1),
1816 path: Path("$.field_one".to_owned()),
1817 span: json::parser::Span::default(),
1818 }
1819 });
1820
1821 let mut iter = warnings.iter();
1822
1823 {
1824 let Group { element, warnings } = iter.next().unwrap();
1825
1826 assert_eq!(element.path.as_str(), "$");
1827 assert_matches!(warnings.as_slice(), [Warning::Root]);
1828 }
1829
1830 {
1831 let Group { element, warnings } = iter.next().unwrap();
1832
1833 assert_eq!(element.path.as_str(), "$.field_one");
1834 assert_matches!(
1835 warnings.as_slice(),
1836 [Warning::One, Warning::OneAgain],
1837 "[`json::Element`] 1 should have two warnings"
1838 );
1839 }
1840
1841 {
1842 let Group { element, warnings } = iter.next().unwrap();
1844
1845 assert_eq!(element.path.as_str(), "$.field_three");
1846 assert_matches!(warnings.as_slice(), [Warning::Three]);
1847 }
1848 }
1849}