1use std::{borrow::Cow, collections::BTreeMap, fmt, iter, ops::Deref, vec};
47
48use tracing::error;
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<K: $crate::warning::Kind>(
59 self,
60 warnings: $crate::warning::Set<K>,
61 ) -> $crate::Caveat<Self, K> {
62 $crate::Caveat::new(self, warnings)
63 }
64 }
65 };
66 ($kind:ty) => {
67 impl $crate::IntoCaveat for $kind {
68 fn into_caveat<K: $crate::warning::Kind>(
69 self,
70 warnings: $crate::warning::Set<K>,
71 ) -> $crate::Caveat<Self, K> {
72 $crate::Caveat::new(self, warnings)
73 }
74 }
75
76 impl $crate::warning::IntoCaveatDeferred for $kind {
77 fn into_caveat_deferred<K: $crate::warning::Kind>(
78 self,
79 warnings: $crate::warning::SetDeferred<K>,
80 ) -> $crate::warning::CaveatDeferred<Self, K> {
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(warn_kind: $source_kind) -> Self {
104 $target_kind::$target_variant(warn_kind)
105 }
106 }
107
108 impl From<$crate::warning::Set<$source_kind>> for $crate::warning::Set<$target_kind> {
113 fn from(set_a: warning::Set<$source_kind>) -> Self {
114 set_a.into_set()
115 }
116 }
117
118 impl From<$crate::warning::SetDeferred<$source_kind>> for $crate::warning::SetDeferred<$target_kind> {
123 fn from(set_a: warning::SetDeferred<$source_kind>) -> Self {
124 set_a.into_set_deferred()
125 }
126 }
127 )+
128 };
129}
130
131pub type Verdict<T, K> = Result<Caveat<T, K>, Set<K>>;
133
134pub(crate) type VerdictDeferred<T, K> = Result<CaveatDeferred<T, K>, SetDeferred<K>>;
142
143pub type Map<K> = BTreeMap<String, Vec<K>>;
145
146#[derive(Debug)]
156pub struct CaveatDeferred<T, K: Kind> {
157 value: T,
159
160 warnings: SetDeferred<K>,
162}
163
164impl<T, K> CaveatDeferred<T, K>
165where
166 T: IntoCaveatDeferred,
167 K: Kind,
168{
169 pub(crate) fn new(value: T, warnings: SetDeferred<K>) -> Self {
171 Self { value, warnings }
172 }
173}
174
175impl<T, K> Deref for CaveatDeferred<T, K>
190where
191 K: Kind,
192{
193 type Target = T;
194
195 fn deref(&self) -> &T {
196 &self.value
197 }
198}
199
200impl<T, K> CaveatDeferred<T, K>
201where
202 K: Kind,
203{
204 pub fn into_parts(self) -> (T, SetDeferred<K>) {
206 let Self { value, warnings } = self;
207 (value, warnings)
208 }
209
210 pub fn ignore_warnings(self) -> T {
212 self.value
213 }
214
215 pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> CaveatDeferred<U, K> {
217 let Self { value, warnings } = self;
218 CaveatDeferred {
219 value: op(value),
220 warnings,
221 }
222 }
223}
224
225#[derive(Debug)]
229pub struct Caveat<T, K: Kind> {
230 value: T,
232
233 warnings: Set<K>,
235}
236
237impl<T, K> Caveat<T, K>
238where
239 T: IntoCaveat,
240 K: Kind,
241{
242 pub(crate) fn new(value: T, warnings: Set<K>) -> Self {
244 Self { value, warnings }
245 }
246}
247
248impl<T, K> Deref for Caveat<T, K>
261where
262 K: Kind,
263{
264 type Target = T;
265
266 fn deref(&self) -> &T {
267 &self.value
268 }
269}
270
271impl<T, K> Caveat<T, K>
272where
273 K: Kind,
274{
275 pub fn into_parts(self) -> (T, Set<K>) {
277 let Self { value, warnings } = self;
278 (value, warnings)
279 }
280
281 pub fn ignore_warnings(self) -> T {
283 self.value
284 }
285
286 pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Caveat<U, K> {
288 let Self { value, warnings } = self;
289 Caveat {
290 value: op(value),
291 warnings,
292 }
293 }
294}
295
296pub(crate) trait GatherWarnings<T, K>
301where
302 K: Kind,
303{
304 type Output;
306
307 #[must_use = "If you want to ignore the value use `let _ =`"]
309 fn gather_warnings_into<KA>(self, warnings: &mut Set<KA>) -> Self::Output
310 where
311 K: Into<KA>,
312 KA: Kind;
313}
314
315impl<T, K> GatherWarnings<T, K> for Caveat<T, K>
317where
318 K: Kind,
319{
320 type Output = T;
321
322 fn gather_warnings_into<KA>(self, warnings: &mut Set<KA>) -> Self::Output
324 where
325 K: Into<KA>,
326 KA: Kind,
327 {
328 let Self {
329 value,
330 warnings: inner_warnings,
331 } = self;
332
333 warnings.extend(inner_warnings);
334
335 value
336 }
337}
338
339impl<T, K> GatherWarnings<T, K> for Option<Caveat<T, K>>
341where
342 K: Kind,
343{
344 type Output = Option<T>;
345
346 fn gather_warnings_into<KA>(self, warnings: &mut Set<KA>) -> Self::Output
348 where
349 K: Into<KA>,
350 KA: Kind,
351 {
352 match self {
353 Some(cv) => Some(cv.gather_warnings_into(warnings)),
354 None => None,
355 }
356 }
357}
358
359impl<T, K, E> GatherWarnings<T, K> for Result<Caveat<T, K>, E>
361where
362 K: Kind,
363 E: std::error::Error,
364{
365 type Output = Result<T, E>;
366
367 fn gather_warnings_into<KA>(self, warnings: &mut Set<KA>) -> Self::Output
369 where
370 K: Into<KA>,
371 KA: Kind,
372 {
373 match self {
374 Ok(cv) => Ok(cv.gather_warnings_into(warnings)),
375 Err(err) => Err(err),
376 }
377 }
378}
379
380impl<T, K> GatherWarnings<T, K> for Verdict<T, K>
382where
383 K: Kind,
384{
385 type Output = Option<T>;
386
387 fn gather_warnings_into<KA>(self, warnings: &mut Set<KA>) -> Self::Output
390 where
391 K: Into<KA>,
392 KA: Kind,
393 {
394 match self {
395 Ok(cv) => Some(cv.gather_warnings_into(warnings)),
396 Err(inner_warnings) => {
397 warnings.extend(inner_warnings);
398 None
399 }
400 }
401 }
402}
403
404impl<T, K> GatherWarnings<T, K> for Vec<Caveat<T, K>>
406where
407 K: Kind,
408{
409 type Output = Vec<T>;
410
411 fn gather_warnings_into<KA>(self, warnings: &mut Set<KA>) -> Self::Output
413 where
414 K: Into<KA>,
415 KA: Kind,
416 {
417 self.into_iter()
418 .map(|cv| cv.gather_warnings_into(warnings))
419 .collect()
420 }
421}
422
423pub(crate) trait GatherWarningKinds<T, K>
428where
429 K: Kind,
430{
431 type Output;
433
434 #[must_use = "If you want to ignore the value use `let _ =`"]
436 fn gather_warning_kinds_into<KA>(self, warnings: &mut SetDeferred<KA>) -> Self::Output
437 where
438 K: Into<KA>,
439 KA: Kind;
440}
441
442impl<T, K> GatherWarningKinds<T, K> for CaveatDeferred<T, K>
444where
445 K: Kind,
446{
447 type Output = T;
448
449 fn gather_warning_kinds_into<KA>(self, warnings: &mut SetDeferred<KA>) -> Self::Output
451 where
452 K: Into<KA>,
453 KA: Kind,
454 {
455 let Self {
456 value,
457 warnings: inner_warnings,
458 } = self;
459
460 warnings.extend(inner_warnings);
461
462 value
463 }
464}
465
466impl<T, K> GatherWarningKinds<T, K> for Option<CaveatDeferred<T, K>>
468where
469 K: Kind,
470{
471 type Output = Option<T>;
472
473 fn gather_warning_kinds_into<KA>(self, warnings: &mut SetDeferred<KA>) -> Self::Output
475 where
476 K: Into<KA>,
477 KA: Kind,
478 {
479 match self {
480 Some(cv) => Some(cv.gather_warning_kinds_into(warnings)),
481 None => None,
482 }
483 }
484}
485
486impl<T, K, E> GatherWarningKinds<T, K> for Result<CaveatDeferred<T, K>, E>
488where
489 K: Kind,
490 E: std::error::Error,
491{
492 type Output = Result<T, E>;
493
494 fn gather_warning_kinds_into<KA>(self, warnings: &mut SetDeferred<KA>) -> Self::Output
496 where
497 K: Into<KA>,
498 KA: Kind,
499 {
500 match self {
501 Ok(cv) => Ok(cv.gather_warning_kinds_into(warnings)),
502 Err(err) => Err(err),
503 }
504 }
505}
506
507impl<T, K> GatherWarningKinds<T, K> for VerdictDeferred<T, K>
509where
510 K: Kind,
511{
512 type Output = Option<T>;
513
514 fn gather_warning_kinds_into<KA>(self, warnings: &mut SetDeferred<KA>) -> Self::Output
517 where
518 K: Into<KA>,
519 KA: Kind,
520 {
521 match self {
522 Ok(cv) => Some(cv.gather_warning_kinds_into(warnings)),
523 Err(inner_warnings) => {
524 warnings.extend(inner_warnings);
525 None
526 }
527 }
528 }
529}
530
531impl<T, K> GatherWarningKinds<T, K> for Vec<CaveatDeferred<T, K>>
533where
534 K: Kind,
535{
536 type Output = Vec<T>;
537
538 fn gather_warning_kinds_into<KA>(self, warnings: &mut SetDeferred<KA>) -> Self::Output
540 where
541 K: Into<KA>,
542 KA: Kind,
543 {
544 self.into_iter()
545 .map(|cv| cv.gather_warning_kinds_into(warnings))
546 .collect()
547 }
548}
549
550pub trait IntoCaveat: Sized {
554 fn into_caveat<K: Kind>(self, warnings: Set<K>) -> Caveat<Self, K>;
556}
557
558pub trait IntoCaveatDeferred: Sized {
562 fn into_caveat_deferred<K: Kind>(self, warnings: SetDeferred<K>) -> CaveatDeferred<Self, K>;
564}
565
566macro_rules! peel {
568 ($name:ident, $($other:ident,)*) => (into_caveat_tuple! { $($other,)* })
569}
570
571macro_rules! into_caveat_tuple {
574 () => ();
575 ( $($name:ident,)+ ) => (
576 impl<$($name),+> $crate::IntoCaveat for ($($name,)+) {
577 fn into_caveat<K: $crate::warning::Kind>(
578 self,
579 warnings: $crate::warning::Set<K>,
580 ) -> $crate::Caveat<Self, K> {
581 $crate::Caveat::new(self, warnings)
582 }
583 }
584
585 impl<$($name),+> $crate::warning::IntoCaveatDeferred for ($($name,)+) {
586 fn into_caveat_deferred<K: $crate::warning::Kind>(
587 self,
588 warnings: SetDeferred<K>,
589 ) -> $crate::warning::CaveatDeferred<Self, K> {
590 $crate::warning::CaveatDeferred::new(self, warnings)
591 }
592 }
593 peel! { $($name,)+ }
594 )
595}
596
597into_caveat_tuple! { T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
600
601into_caveat_all!(
603 (),
604 bool,
605 char,
606 u8,
607 u16,
608 u32,
609 u64,
610 u128,
611 i8,
612 i16,
613 i32,
614 i64,
615 i128
616);
617
618impl IntoCaveat for Cow<'_, str> {
620 fn into_caveat<K: Kind>(self, warnings: Set<K>) -> Caveat<Self, K> {
621 Caveat::new(self, warnings)
622 }
623}
624
625impl<T> IntoCaveat for Option<T>
627where
628 T: IntoCaveat,
629{
630 fn into_caveat<K: Kind>(self, warnings: Set<K>) -> Caveat<Self, K> {
631 Caveat::new(self, warnings)
632 }
633}
634
635impl<T> IntoCaveat for Vec<T>
637where
638 T: IntoCaveat,
639{
640 fn into_caveat<K: Kind>(self, warnings: Set<K>) -> Caveat<Self, K> {
641 Caveat::new(self, warnings)
642 }
643}
644
645impl<T> IntoCaveatDeferred for Vec<T>
647where
648 T: IntoCaveat,
649{
650 fn into_caveat_deferred<K: Kind>(self, warnings: SetDeferred<K>) -> CaveatDeferred<Self, K> {
651 CaveatDeferred::new(self, warnings)
652 }
653}
654
655pub trait VerdictExt<T, K: Kind> {
657 fn map_caveat<F, U>(self, op: F) -> Verdict<U, K>
660 where
661 F: FnOnce(T) -> U;
662
663 fn keep_cause(self, root: &json::Element<'_>) -> Result<Caveat<T, K>, Cause<K>>;
665}
666
667impl<T, K: Kind> VerdictExt<T, K> for Verdict<T, K>
668where
669 T: IntoCaveat,
670{
671 fn map_caveat<F, U>(self, op: F) -> Verdict<U, K>
672 where
673 F: FnOnce(T) -> U,
674 {
675 match self {
676 Ok(c) => Ok(c.map(op)),
677 Err(w) => Err(w),
678 }
679 }
680
681 fn keep_cause(self, root: &json::Element<'_>) -> Result<Caveat<T, K>, Cause<K>> {
682 match self {
683 Ok(c) => Ok(c),
684 Err(mut warnings) => {
685 let cause = warnings
686 .0
687 .pop()
688 .expect("A nonempty warning set is expected in a error path");
689
690 let Warning { kind, elem_id } = cause;
691 let elem = json::walk::DepthFirst::new(root)
692 .find(|elem| elem.id() == elem_id)
693 .expect("A");
694
695 Err(Cause {
696 kind,
697 elem: elem.path().to_string(),
698 })
699 }
700 }
701 }
702}
703
704#[derive(Debug)]
708pub struct Cause<K: Kind> {
709 kind: K,
711
712 elem: String,
714}
715
716impl<K: Kind> std::error::Error for Cause<K> {}
717
718impl<K: Kind> fmt::Display for Cause<K> {
719 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
720 write!(
721 f,
722 "A warning for element at `{}` was upgraded to an `error`: {}",
723 self.elem, self.kind
724 )
725 }
726}
727
728pub trait WithElement<T, K: Kind> {
730 fn with_element(self, elem: &json::Element<'_>) -> Verdict<T, K>;
731}
732
733impl<T, K: Kind> WithElement<T, K> for VerdictDeferred<T, K> {
734 fn with_element(self, elem: &json::Element<'_>) -> Verdict<T, K> {
736 match self {
737 Ok(v) => {
738 let CaveatDeferred { value, warnings } = v;
739 Ok(Caveat {
740 value,
741 warnings: Set::from_kind_vec(elem, warnings.0),
742 })
743 }
744 Err(warning_kinds) => Err(Set::from_kind_vec(elem, warning_kinds.0)),
745 }
746 }
747}
748
749pub trait OptionExt<T, K>
751where
752 K: Kind,
753{
754 fn exit_with_warning<F>(self, warnings: Set<K>, f: F) -> Verdict<T, K>
756 where
757 F: FnOnce() -> Warning<K>;
758}
759
760impl<T, K> OptionExt<T, K> for Option<T>
761where
762 T: IntoCaveat,
763 K: Kind,
764{
765 fn exit_with_warning<F>(self, mut warnings: Set<K>, f: F) -> Verdict<T, K>
766 where
767 F: FnOnce() -> Warning<K>,
768 {
769 if let Some(v) = self {
770 Ok(v.into_caveat(warnings))
771 } else {
772 warnings.push(f());
773 Err(warnings)
774 }
775 }
776}
777
778#[derive(Debug)]
785pub struct Warning<K: Kind> {
786 kind: K,
788
789 elem_id: json::ElemId,
791}
792
793pub struct SetWriter<'caller, 'buf, K: Kind> {
807 root_elem: &'caller json::Element<'buf>,
809
810 warnings: &'caller Set<K>,
812
813 indent: &'caller str,
815}
816
817impl<'caller, 'buf, K: Kind> SetWriter<'caller, 'buf, K> {
818 pub fn new(root_elem: &'caller json::Element<'buf>, warnings: &'caller Set<K>) -> Self {
820 Self {
821 root_elem,
822 warnings,
823 indent: " - ",
824 }
825 }
826
827 pub fn with_indent(
829 root_elem: &'caller json::Element<'buf>,
830 warnings: &'caller Set<K>,
831 indent: &'caller str,
832 ) -> Self {
833 Self {
834 root_elem,
835 warnings,
836 indent,
837 }
838 }
839}
840
841impl<K: Kind> fmt::Debug for SetWriter<'_, '_, K> {
842 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
843 fmt::Display::fmt(self, f)
844 }
845}
846
847impl<K: Kind> fmt::Display for SetWriter<'_, '_, K> {
848 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
849 let mut iter = self.warnings.group_by_elem(self.root_elem);
850
851 {
852 let Some(Group { element, warnings }) = iter.next() else {
854 return Ok(());
855 };
856
857 writeln!(f, "{}", element.path())?;
858
859 for warning in warnings {
860 write!(f, "{}{}", self.indent, warning)?;
861 }
862 }
863
864 for Group { element, warnings } in iter {
866 writeln!(f, "\n{}", element.path())?;
867
868 for warning in warnings {
869 write!(f, "{}{}", self.indent, warning)?;
870 }
871 }
872
873 Ok(())
874 }
875}
876
877impl<K: Kind> Warning<K> {
878 pub(crate) const fn with_elem(kind: K, elem: &json::Element<'_>) -> Warning<K> {
882 Warning {
883 kind,
884 elem_id: elem.id(),
885 }
886 }
887
888 pub fn id(&self) -> Cow<'static, str> {
890 self.kind.id()
891 }
892
893 pub fn kind(&self) -> &K {
895 &self.kind
896 }
897
898 pub fn into_kind(self) -> K {
900 self.kind
901 }
902}
903
904impl<K: Kind> fmt::Display for Warning<K> {
905 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
906 write!(f, "{}", self.kind)
907 }
908}
909
910pub trait Kind: Sized + fmt::Debug + fmt::Display + Send + Sync {
914 fn id(&self) -> Cow<'static, str>;
919}
920
921#[derive(Debug)]
930pub struct SetDeferred<K: Kind>(Vec<K>);
931
932impl<K: Kind> SetDeferred<K> {
933 pub(crate) fn new() -> Self {
935 Self(vec![])
936 }
937
938 pub(crate) fn with_warn(warning: K) -> Self {
940 Self(vec![warning])
941 }
942
943 pub(crate) fn bail<T>(mut self, warning: K) -> VerdictDeferred<T, K> {
947 self.0.push(warning);
948 Err(self)
949 }
950
951 pub(crate) fn into_set_deferred<KB>(self) -> SetDeferred<KB>
955 where
956 KB: Kind + From<K>,
957 {
958 let warnings = self.0.into_iter().map(Into::into).collect();
959
960 SetDeferred(warnings)
961 }
962
963 pub(crate) fn extend<KA>(&mut self, warnings: SetDeferred<KA>)
967 where
968 KA: Into<K> + Kind,
969 {
970 self.0.extend(warnings.0.into_iter().map(Into::into));
971 }
972}
973
974#[derive(Debug)]
976pub struct Set<K: Kind>(Vec<Warning<K>>);
977
978impl<K: Kind> Set<K> {
979 pub(crate) fn new() -> Self {
981 Self(vec![])
982 }
983
984 pub(crate) fn from_vec(warnings: Vec<Warning<K>>) -> Self {
986 Self(warnings)
987 }
988
989 pub(crate) fn from_kind_vec(elem: &json::Element<'_>, warning_kinds: Vec<K>) -> Self {
991 let warnings = warning_kinds
992 .into_iter()
993 .map(|kind| Warning::with_elem(kind, elem))
994 .collect();
995 Self(warnings)
996 }
997
998 fn push(&mut self, warning: Warning<K>) {
1000 self.0.push(warning);
1001 }
1002
1003 pub(crate) fn with_elem(&mut self, kind: K, elem: &json::Element<'_>) {
1005 self.push(Warning::with_elem(kind, elem));
1006 }
1007
1008 pub(crate) fn bail<T>(mut self, kind: K, elem: &json::Element<'_>) -> Verdict<T, K> {
1012 self.0.push(Warning::with_elem(kind, elem));
1013 Err(self)
1014 }
1015
1016 pub(crate) fn into_set<KB>(self) -> Set<KB>
1020 where
1021 KB: Kind + From<K>,
1022 {
1023 let warnings = self
1024 .0
1025 .into_iter()
1026 .map(|warn| {
1027 let Warning { kind, elem_id } = warn;
1028 Warning {
1029 kind: kind.into(),
1030 elem_id,
1031 }
1032 })
1033 .collect();
1034
1035 Set(warnings)
1036 }
1037
1038 pub(crate) fn map_warning<KU>(self) -> Set<KU>
1042 where
1043 KU: Kind + From<K>,
1044 {
1045 let warnings = self
1046 .0
1047 .into_iter()
1048 .map(|warn| {
1049 let Warning { kind, elem_id } = warn;
1050 Warning {
1051 kind: kind.into(),
1052 elem_id,
1053 }
1054 })
1055 .collect();
1056
1057 Set(warnings)
1058 }
1059
1060 pub(crate) fn extend<KA>(&mut self, warnings: Set<KA>)
1064 where
1065 KA: Into<K> + Kind,
1066 {
1067 self.0.extend(warnings.0.into_iter().map(|warn| {
1068 let Warning { kind, elem_id } = warn;
1069 Warning {
1070 kind: kind.into(),
1071 elem_id,
1072 }
1073 }));
1074 }
1075
1076 pub fn is_empty(&self) -> bool {
1078 self.0.is_empty()
1079 }
1080
1081 pub fn len(&self) -> usize {
1083 self.0.len()
1084 }
1085
1086 pub fn group_by_elem<'caller: 'buf, 'buf>(
1090 &'caller self,
1091 root: &'caller json::Element<'buf>,
1092 ) -> GroupByElem<'caller, 'buf, K> {
1093 let mut warnings = self.0.iter().collect::<Vec<_>>();
1094 warnings.sort_unstable_by_key(|warning| warning.elem_id);
1095
1096 GroupByElem {
1097 walker: json::walk::DepthFirst::new(root),
1098 warnings: warnings.into_iter().peekable(),
1099 }
1100 }
1101
1102 pub fn into_group_by_elem<'caller, 'buf>(
1106 self,
1107 root: &'caller json::Element<'buf>,
1108 ) -> IntoGroupByElem<'caller, 'buf, K> {
1109 let Self(mut warnings) = self;
1110 warnings.sort_unstable_by_key(|warning| warning.elem_id);
1111
1112 IntoGroupByElem {
1113 walker: json::walk::DepthFirst::new(root),
1114 warnings: warnings.into_iter().peekable(),
1115 }
1116 }
1117}
1118
1119pub struct IntoGroupByElem<'caller, 'buf, K>
1121where
1122 K: Kind,
1123{
1124 walker: json::walk::DepthFirst<'caller, 'buf>,
1126
1127 warnings: iter::Peekable<vec::IntoIter<Warning<K>>>,
1129}
1130
1131impl<K> IntoGroupByElem<'_, '_, K>
1132where
1133 K: Kind,
1134{
1135 pub fn into_kind_map(self) -> BTreeMap<String, Vec<K>> {
1137 self.map(IntoGroup::into_kinds).collect()
1138 }
1139
1140 pub fn into_id_map(self) -> BTreeMap<String, Vec<String>> {
1149 self.map(IntoGroup::into_str_ids).collect()
1150 }
1151
1152 pub fn into_msg_map(self) -> BTreeMap<String, Vec<String>> {
1158 self.map(IntoGroup::into_str_msgs).collect()
1159 }
1160}
1161
1162#[derive(Debug)]
1167pub struct IntoGroup<'caller, 'buf, K> {
1168 pub element: &'caller json::Element<'buf>,
1170
1171 pub warnings: Vec<K>,
1173}
1174
1175impl<K> IntoGroup<'_, '_, K>
1176where
1177 K: Kind,
1178{
1179 pub fn into_kinds(self) -> (String, Vec<K>) {
1184 let Self { element, warnings } = self;
1185 (element.path().to_string(), warnings)
1186 }
1187
1188 pub fn into_str_ids(self) -> (String, Vec<String>) {
1193 let Self { element, warnings } = self;
1194 (
1195 element.path().to_string(),
1196 warnings.iter().map(|kind| kind.id().to_string()).collect(),
1197 )
1198 }
1199
1200 pub fn into_str_msgs(self) -> (String, Vec<String>) {
1205 let Self { element, warnings } = self;
1206 (
1207 element.path().to_string(),
1208 warnings.iter().map(ToString::to_string).collect(),
1209 )
1210 }
1211}
1212
1213impl<'caller, 'buf, K: Kind> Iterator for IntoGroupByElem<'caller, 'buf, K> {
1214 type Item = IntoGroup<'caller, 'buf, K>;
1215
1216 fn next(&mut self) -> Option<Self::Item> {
1217 let warning = self.warnings.next()?;
1219
1220 let element = loop {
1222 let Some(element) = self.walker.next() else {
1223 error!("An Element with id: `{}` was not found", warning.elem_id);
1224 return None;
1225 };
1226
1227 if element.id() < warning.elem_id {
1228 continue;
1231 }
1232
1233 if element.id() > warning.elem_id {
1234 debug_assert!(
1235 element.id() <= warning.elem_id,
1236 "The elements or the warnings are not sorted."
1237 );
1238 return None;
1239 }
1240
1241 break element;
1243 };
1244
1245 let mut warnings_grouped = vec![warning.into_kind()];
1247
1248 loop {
1250 let warning = self.warnings.next_if(|w| w.elem_id == element.id());
1251 let Some(warning) = warning else {
1252 break;
1253 };
1254
1255 warnings_grouped.push(warning.into_kind());
1256 }
1257
1258 Some(IntoGroup {
1259 element,
1260 warnings: warnings_grouped,
1261 })
1262 }
1263}
1264
1265pub struct GroupByElem<'caller, 'buf, K>
1267where
1268 K: Kind,
1269{
1270 walker: json::walk::DepthFirst<'caller, 'buf>,
1272
1273 warnings: iter::Peekable<vec::IntoIter<&'caller Warning<K>>>,
1275}
1276
1277impl<K> GroupByElem<'_, '_, K>
1278where
1279 K: Kind,
1280{
1281 pub fn into_id_map(self) -> BTreeMap<String, Vec<String>> {
1290 self.map(Group::into_str_ids).collect()
1291 }
1292
1293 pub fn into_msg_map(self) -> BTreeMap<String, Vec<String>> {
1299 self.map(Group::into_str_msgs).collect()
1300 }
1301}
1302
1303#[derive(Debug)]
1308pub struct Group<'caller, 'buf, K> {
1309 pub element: &'caller json::Element<'buf>,
1311
1312 pub warnings: Vec<&'caller K>,
1314}
1315
1316impl<K> Group<'_, '_, K>
1317where
1318 K: Kind,
1319{
1320 pub fn into_str_ids(self) -> (String, Vec<String>) {
1325 let Self { element, warnings } = self;
1326 (
1327 element.path().to_string(),
1328 warnings.iter().map(|kind| kind.id().to_string()).collect(),
1329 )
1330 }
1331
1332 pub fn into_str_msgs(self) -> (String, Vec<String>) {
1337 let Self { element, warnings } = self;
1338 (
1339 element.path().to_string(),
1340 warnings.iter().map(ToString::to_string).collect(),
1341 )
1342 }
1343}
1344
1345impl<'caller, 'buf, K: Kind> Iterator for GroupByElem<'caller, 'buf, K> {
1346 type Item = Group<'caller, 'buf, K>;
1347
1348 fn next(&mut self) -> Option<Self::Item> {
1349 let warning = self.warnings.next()?;
1351
1352 let element = loop {
1354 let Some(element) = self.walker.next() else {
1355 error!("An Element with id: `{}` was not found", warning.elem_id);
1356 return None;
1357 };
1358
1359 if element.id() < warning.elem_id {
1360 continue;
1363 }
1364
1365 if element.id() > warning.elem_id {
1366 debug_assert!(
1367 element.id() <= warning.elem_id,
1368 "The elements or the warnings are not sorted."
1369 );
1370 return None;
1371 }
1372
1373 break element;
1375 };
1376
1377 let mut warnings_grouped = vec![warning.kind()];
1379
1380 loop {
1382 let warning = self.warnings.next_if(|w| w.elem_id == element.id());
1383 let Some(warning) = warning else {
1384 break;
1385 };
1386
1387 warnings_grouped.push(warning.kind());
1388 }
1389
1390 Some(Group {
1391 element,
1392 warnings: warnings_grouped,
1393 })
1394 }
1395}
1396
1397#[cfg(test)]
1398pub(crate) mod test {
1399 use std::{
1400 borrow::Cow,
1401 collections::{BTreeMap, BTreeSet},
1402 ops, slice,
1403 };
1404
1405 use assert_matches::assert_matches;
1406
1407 use crate::{
1408 json,
1409 test::{ExpectValue, Expectation},
1410 warning::CaveatDeferred,
1411 };
1412
1413 use super::{Caveat, Group, Kind, Set, Warning};
1414
1415 impl<K: Kind> Set<K> {
1416 pub fn into_vec(self) -> Vec<Warning<K>> {
1418 self.0
1419 }
1420
1421 pub fn into_parts_vec(self) -> Vec<(K, json::ElemId)> {
1422 self.0
1423 .into_iter()
1424 .map(|Warning { kind, elem_id }| (kind, elem_id))
1425 .collect()
1426 }
1427
1428 pub fn into_kind_vec(self) -> Vec<K> {
1432 self.0.into_iter().map(Warning::into_kind).collect()
1433 }
1434
1435 pub fn as_slice(&self) -> &[Warning<K>] {
1437 self.0.as_slice()
1438 }
1439
1440 pub fn iter(&self) -> slice::Iter<'_, Warning<K>> {
1442 self.0.iter()
1443 }
1444 }
1445
1446 impl<K: Kind> ops::Deref for Set<K> {
1447 type Target = [Warning<K>];
1448
1449 fn deref(&self) -> &[Warning<K>] {
1450 self.as_slice()
1451 }
1452 }
1453
1454 impl<K: Kind> IntoIterator for Set<K> {
1455 type Item = Warning<K>;
1456
1457 type IntoIter = <Vec<Self::Item> as IntoIterator>::IntoIter;
1458
1459 fn into_iter(self) -> Self::IntoIter {
1460 self.0.into_iter()
1461 }
1462 }
1463
1464 impl<'a, K: Kind> IntoIterator for &'a Set<K> {
1465 type Item = &'a Warning<K>;
1466
1467 type IntoIter = slice::Iter<'a, Warning<K>>;
1468
1469 fn into_iter(self) -> Self::IntoIter {
1470 self.0.iter()
1471 }
1472 }
1473
1474 impl<T, K> Caveat<T, K>
1475 where
1476 K: Kind,
1477 {
1478 pub fn unwrap(self) -> T {
1480 let Self { value, warnings } = self;
1481 assert_matches!(warnings.into_vec().as_slice(), []);
1482 value
1483 }
1484 }
1485
1486 impl<T, K> CaveatDeferred<T, K>
1487 where
1488 K: Kind,
1489 {
1490 pub fn unwrap(self) -> T {
1492 let Self { value, warnings } = self;
1493 assert_matches!(warnings.0.as_slice(), []);
1494 value
1495 }
1496 }
1497
1498 pub(crate) fn assert_warnings<K>(
1502 expect_file_name: &str,
1503 root: &json::Element<'_>,
1504 warnings: &Set<K>,
1505 expected: Expectation<BTreeMap<String, Vec<String>>>,
1506 ) where
1507 K: Kind,
1508 {
1509 let Expectation::Present(ExpectValue::Some(expected)) = expected else {
1510 assert!(
1511 warnings.is_empty(),
1512 "There is no `warnings` field in the `{expect_file_name}` file but the tariff has warnings;\n{:?}",
1513 warnings.group_by_elem(root).into_id_map()
1514 );
1515 return;
1516 };
1517
1518 {
1519 let warnings_grouped = warnings
1521 .group_by_elem(root)
1522 .map(|Group { element, warnings }| (element.path().to_string(), warnings))
1523 .collect::<BTreeMap<_, _>>();
1524
1525 let mut elems_in_expect_without_warning = vec![];
1526
1527 for elem_path in expected.keys() {
1528 if !warnings_grouped.contains_key(elem_path) {
1529 elems_in_expect_without_warning.push(elem_path);
1530 }
1531 }
1532
1533 assert!(elems_in_expect_without_warning.is_empty(),
1534 "The expect file `{expect_file_name}` has entries for elements that have no warnings:\n\
1535 {elems_in_expect_without_warning:#?}"
1536 );
1537 }
1538
1539 let mut elems_missing_from_expect = vec![];
1541 let mut unequal_warnings = vec![];
1544
1545 for group in warnings.group_by_elem(root) {
1546 let path_str = group.element.path().to_string();
1547 let Some(warnings_expected) = expected.get(&*path_str) else {
1548 elems_missing_from_expect.push(group);
1549 continue;
1550 };
1551
1552 let warnings_expected = warnings_expected
1554 .iter()
1555 .map(|s| Cow::Borrowed(&**s))
1556 .collect::<BTreeSet<_>>();
1557 let warnings = group
1558 .warnings
1559 .iter()
1560 .map(|w| w.id())
1561 .collect::<BTreeSet<_>>();
1562
1563 if warnings_expected != warnings {
1564 unequal_warnings.push(group);
1565 }
1566 }
1567
1568 if !elems_missing_from_expect.is_empty() || !unequal_warnings.is_empty() {
1569 let missing = elems_missing_from_expect
1570 .into_iter()
1571 .map(Group::into_str_ids)
1572 .collect::<BTreeMap<_, _>>();
1573
1574 let unequal = unequal_warnings
1575 .into_iter()
1576 .map(Group::into_str_ids)
1577 .collect::<BTreeMap<_, _>>();
1578
1579 match (!missing.is_empty(), !unequal.is_empty()) {
1580 (true, true) => panic!(
1581 "Elements with warnings but are not defined in the `{expect_file_name}` file:\n{missing:#?}\n\
1582 Elements that are in the `{expect_file_name}` file but the warnings list is not correct.\n\
1583 The warnings reported are: \n{unequal:#?}"
1584 ),
1585 (true, false) => panic!("Elements with warnings but are not defined in the `{expect_file_name}` file:\n{missing:#?}"),
1586 (false, true) => panic!(
1587 "Elements that are in the `{expect_file_name}` file but the warnings list is not correct.\n\
1588 The warnings reported are: \n{unequal:#?}"
1589 ),
1590 (false, false) => (),
1591 }
1592 }
1593 }
1594}
1595
1596#[cfg(test)]
1597mod test_group_by_elem {
1598 use std::fmt;
1599
1600 use assert_matches::assert_matches;
1601
1602 use crate::{json, test};
1603
1604 use super::{Group, IntoGroup, Kind, Set, Warning};
1605
1606 const JSON: &str = r#"{
1607 "field_one#": "one",
1608 "field_two": "two",
1609 "field_three": "three"
1610}"#;
1611
1612 #[derive(Debug)]
1613 enum WarningKind {
1614 Root,
1615 One,
1616 OneAgain,
1617 Three,
1618 }
1619
1620 impl Kind for WarningKind {
1621 fn id(&self) -> std::borrow::Cow<'static, str> {
1622 match self {
1623 WarningKind::Root => "root".into(),
1624 WarningKind::One => "one".into(),
1625 WarningKind::OneAgain => "one_again".into(),
1626 WarningKind::Three => "three".into(),
1627 }
1628 }
1629 }
1630
1631 impl fmt::Display for WarningKind {
1632 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1633 match self {
1634 WarningKind::Root => write!(f, "NopeRoot"),
1635 WarningKind::One => write!(f, "NopeOne"),
1636 WarningKind::OneAgain => write!(f, "NopeOneAgain"),
1637 WarningKind::Three => write!(f, "NopeThree"),
1638 }
1639 }
1640 }
1641
1642 #[test]
1643 fn should_group_by_elem() {
1644 test::setup();
1645
1646 let elem = parse(JSON);
1647 let mut warnings = Set::<WarningKind>::new();
1648
1649 warnings.push(Warning {
1652 kind: WarningKind::Root,
1653 elem_id: json::ElemId::from(0),
1654 });
1655 warnings.push(Warning {
1656 kind: WarningKind::One,
1657 elem_id: json::ElemId::from(1),
1658 });
1659 warnings.push(Warning {
1660 kind: WarningKind::Three,
1661 elem_id: json::ElemId::from(3),
1662 });
1663 warnings.push(Warning {
1664 kind: WarningKind::OneAgain,
1665 elem_id: json::ElemId::from(1),
1666 });
1667
1668 let mut iter = warnings.group_by_elem(&elem);
1669
1670 {
1671 let Group { element, warnings } = iter.next().unwrap();
1672
1673 assert!(
1674 element.value().is_object(),
1675 "The root object should be emitted first"
1676 );
1677 assert_eq!(
1678 element.id(),
1679 json::ElemId::from(0),
1680 "The root object should be emitted first"
1681 );
1682 assert_matches!(warnings.as_slice(), [WarningKind::Root]);
1683 }
1684
1685 {
1686 let Group { element, warnings } = iter.next().unwrap();
1687
1688 assert_eq!(element.value().as_raw_str().unwrap().as_raw(), "one");
1689 assert_eq!(element.id(), json::ElemId::from(1));
1690 assert_matches!(
1691 warnings.as_slice(),
1692 [WarningKind::One, WarningKind::OneAgain],
1693 "[`json::Element`] 1 should have two warnings"
1694 );
1695 }
1696
1697 {
1698 let Group { element, warnings } = iter.next().unwrap();
1700
1701 assert_eq!(element.value().as_raw_str().unwrap().as_raw(), "three");
1702 assert_eq!(element.id(), json::ElemId::from(3));
1703 assert_matches!(warnings.as_slice(), [WarningKind::Three]);
1704 }
1705 }
1706
1707 #[test]
1708 fn should_into_group_by_elem() {
1709 test::setup();
1710
1711 let elem = parse(JSON);
1712 let mut warnings = Set::<WarningKind>::new();
1713
1714 warnings.push(Warning {
1717 kind: WarningKind::Root,
1718 elem_id: json::ElemId::from(0),
1719 });
1720 warnings.push(Warning {
1721 kind: WarningKind::Three,
1722 elem_id: json::ElemId::from(3),
1723 });
1724 warnings.push(Warning {
1725 kind: WarningKind::One,
1726 elem_id: json::ElemId::from(1),
1727 });
1728 warnings.push(Warning {
1729 kind: WarningKind::OneAgain,
1730 elem_id: json::ElemId::from(1),
1731 });
1732
1733 let mut iter = warnings.into_group_by_elem(&elem);
1734
1735 {
1736 let IntoGroup { element, warnings } = iter.next().unwrap();
1737
1738 assert!(
1739 element.value().is_object(),
1740 "The root object should be emitted first"
1741 );
1742 assert_eq!(
1743 element.id(),
1744 json::ElemId::from(0),
1745 "The root object should be emitted first"
1746 );
1747 assert_matches!(warnings.as_slice(), [WarningKind::Root]);
1748 }
1749
1750 {
1751 let IntoGroup { element, warnings } = iter.next().unwrap();
1752
1753 assert_eq!(element.value().as_raw_str().unwrap().as_raw(), "one");
1754 assert_eq!(element.id(), json::ElemId::from(1));
1755 assert_matches!(
1756 warnings.as_slice(),
1757 [WarningKind::One, WarningKind::OneAgain],
1758 "[`json::Element`] 1 should have two warnings"
1759 );
1760 }
1761
1762 {
1763 let IntoGroup { element, warnings } = iter.next().unwrap();
1765
1766 assert_eq!(element.value().as_raw_str().unwrap().as_raw(), "three");
1767 assert_eq!(element.id(), json::ElemId::from(3));
1768 assert_matches!(warnings.as_slice(), [WarningKind::Three]);
1769 }
1770 }
1771
1772 fn parse(json: &str) -> json::Element<'_> {
1773 json::parse(json).unwrap()
1774 }
1775}