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_path: elem.path().to_string(),
698 })
699 }
700 }
701 }
702}
703
704#[derive(Debug)]
708pub struct Cause<K: Kind> {
709 kind: K,
711
712 elem_path: String,
714}
715
716impl<K: Kind> Cause<K> {
717 pub fn kind(&self) -> &K {
719 &self.kind
720 }
721
722 pub fn elem_path(&self) -> &str {
724 &self.elem_path
725 }
726
727 pub fn as_parts(&self) -> (&K, &str) {
729 (&self.kind, &*self.elem_path)
730 }
731
732 pub fn into_parts(self) -> (K, String) {
734 let Self { kind, elem_path } = self;
735 (kind, elem_path)
736 }
737}
738
739impl<K: Kind> std::error::Error for Cause<K> {}
740
741impl<K: Kind> fmt::Display for Cause<K> {
742 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
743 write!(
744 f,
745 "A warning for element at `{}` was upgraded to an `error`: {}",
746 self.elem_path, self.kind
747 )
748 }
749}
750
751pub trait WithElement<T, K: Kind> {
753 fn with_element(self, elem: &json::Element<'_>) -> Verdict<T, K>;
754}
755
756impl<T, K: Kind> WithElement<T, K> for VerdictDeferred<T, K> {
757 fn with_element(self, elem: &json::Element<'_>) -> Verdict<T, K> {
759 match self {
760 Ok(v) => {
761 let CaveatDeferred { value, warnings } = v;
762 Ok(Caveat {
763 value,
764 warnings: Set::from_kind_vec(elem, warnings.0),
765 })
766 }
767 Err(warning_kinds) => Err(Set::from_kind_vec(elem, warning_kinds.0)),
768 }
769 }
770}
771
772pub trait OptionExt<T, K>
774where
775 K: Kind,
776{
777 fn exit_with_warning<F>(self, warnings: Set<K>, f: F) -> Verdict<T, K>
779 where
780 F: FnOnce() -> Warning<K>;
781}
782
783impl<T, K> OptionExt<T, K> for Option<T>
784where
785 T: IntoCaveat,
786 K: Kind,
787{
788 fn exit_with_warning<F>(self, mut warnings: Set<K>, f: F) -> Verdict<T, K>
789 where
790 F: FnOnce() -> Warning<K>,
791 {
792 if let Some(v) = self {
793 Ok(v.into_caveat(warnings))
794 } else {
795 warnings.push(f());
796 Err(warnings)
797 }
798 }
799}
800
801#[derive(Debug)]
808pub struct Warning<K: Kind> {
809 kind: K,
811
812 elem_id: json::ElemId,
814}
815
816pub struct SetWriter<'caller, 'buf, K: Kind> {
830 root_elem: &'caller json::Element<'buf>,
832
833 warnings: &'caller Set<K>,
835
836 indent: &'caller str,
838}
839
840impl<'caller, 'buf, K: Kind> SetWriter<'caller, 'buf, K> {
841 pub fn new(root_elem: &'caller json::Element<'buf>, warnings: &'caller Set<K>) -> Self {
843 Self {
844 root_elem,
845 warnings,
846 indent: " - ",
847 }
848 }
849
850 pub fn with_indent(
852 root_elem: &'caller json::Element<'buf>,
853 warnings: &'caller Set<K>,
854 indent: &'caller str,
855 ) -> Self {
856 Self {
857 root_elem,
858 warnings,
859 indent,
860 }
861 }
862}
863
864impl<K: Kind> fmt::Debug for SetWriter<'_, '_, K> {
865 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
866 fmt::Display::fmt(self, f)
867 }
868}
869
870impl<K: Kind> fmt::Display for SetWriter<'_, '_, K> {
871 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
872 let mut iter = self.warnings.group_by_elem(self.root_elem);
873
874 {
875 let Some(Group { element, warnings }) = iter.next() else {
877 return Ok(());
878 };
879
880 writeln!(f, "{}", element.path())?;
881
882 for warning in warnings {
883 write!(f, "{}{}", self.indent, warning)?;
884 }
885 }
886
887 for Group { element, warnings } in iter {
889 writeln!(f, "\n{}", element.path())?;
890
891 for warning in warnings {
892 write!(f, "{}{}", self.indent, warning)?;
893 }
894 }
895
896 Ok(())
897 }
898}
899
900impl<K: Kind> Warning<K> {
901 pub(crate) const fn with_elem(kind: K, elem: &json::Element<'_>) -> Warning<K> {
905 Warning {
906 kind,
907 elem_id: elem.id(),
908 }
909 }
910
911 pub fn id(&self) -> Cow<'static, str> {
913 self.kind.id()
914 }
915
916 pub fn kind(&self) -> &K {
918 &self.kind
919 }
920
921 pub fn into_kind(self) -> K {
923 self.kind
924 }
925}
926
927impl<K: Kind> fmt::Display for Warning<K> {
928 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
929 write!(f, "{}", self.kind)
930 }
931}
932
933pub trait Kind: Sized + fmt::Debug + fmt::Display + Send + Sync {
937 fn id(&self) -> Cow<'static, str>;
942}
943
944#[derive(Debug)]
953pub struct SetDeferred<K: Kind>(Vec<K>);
954
955impl<K: Kind> SetDeferred<K> {
956 pub(crate) fn new() -> Self {
958 Self(vec![])
959 }
960
961 pub(crate) fn with_warn(warning: K) -> Self {
963 Self(vec![warning])
964 }
965
966 pub(crate) fn bail<T>(mut self, warning: K) -> VerdictDeferred<T, K> {
970 self.0.push(warning);
971 Err(self)
972 }
973
974 pub(crate) fn into_set_deferred<KB>(self) -> SetDeferred<KB>
978 where
979 KB: Kind + From<K>,
980 {
981 let warnings = self.0.into_iter().map(Into::into).collect();
982
983 SetDeferred(warnings)
984 }
985
986 pub(crate) fn extend<KA>(&mut self, warnings: SetDeferred<KA>)
990 where
991 KA: Into<K> + Kind,
992 {
993 self.0.extend(warnings.0.into_iter().map(Into::into));
994 }
995}
996
997#[derive(Debug)]
999pub struct Set<K: Kind>(Vec<Warning<K>>);
1000
1001impl<K: Kind> Set<K> {
1002 pub(crate) fn new() -> Self {
1004 Self(vec![])
1005 }
1006
1007 pub(crate) fn from_vec(warnings: Vec<Warning<K>>) -> Self {
1009 Self(warnings)
1010 }
1011
1012 pub(crate) fn from_kind_vec(elem: &json::Element<'_>, warning_kinds: Vec<K>) -> Self {
1014 let warnings = warning_kinds
1015 .into_iter()
1016 .map(|kind| Warning::with_elem(kind, elem))
1017 .collect();
1018 Self(warnings)
1019 }
1020
1021 fn push(&mut self, warning: Warning<K>) {
1023 self.0.push(warning);
1024 }
1025
1026 pub(crate) fn with_elem(&mut self, kind: K, elem: &json::Element<'_>) {
1028 self.push(Warning::with_elem(kind, elem));
1029 }
1030
1031 pub(crate) fn bail<T>(mut self, kind: K, elem: &json::Element<'_>) -> Verdict<T, K> {
1035 self.0.push(Warning::with_elem(kind, elem));
1036 Err(self)
1037 }
1038
1039 pub(crate) fn into_set<KB>(self) -> Set<KB>
1043 where
1044 KB: Kind + From<K>,
1045 {
1046 let warnings = self
1047 .0
1048 .into_iter()
1049 .map(|warn| {
1050 let Warning { kind, elem_id } = warn;
1051 Warning {
1052 kind: kind.into(),
1053 elem_id,
1054 }
1055 })
1056 .collect();
1057
1058 Set(warnings)
1059 }
1060
1061 pub(crate) fn map_warning<KU>(self) -> Set<KU>
1065 where
1066 KU: Kind + From<K>,
1067 {
1068 let warnings = self
1069 .0
1070 .into_iter()
1071 .map(|warn| {
1072 let Warning { kind, elem_id } = warn;
1073 Warning {
1074 kind: kind.into(),
1075 elem_id,
1076 }
1077 })
1078 .collect();
1079
1080 Set(warnings)
1081 }
1082
1083 pub(crate) fn extend<KA>(&mut self, warnings: Set<KA>)
1087 where
1088 KA: Into<K> + Kind,
1089 {
1090 self.0.extend(warnings.0.into_iter().map(|warn| {
1091 let Warning { kind, elem_id } = warn;
1092 Warning {
1093 kind: kind.into(),
1094 elem_id,
1095 }
1096 }));
1097 }
1098
1099 pub fn is_empty(&self) -> bool {
1101 self.0.is_empty()
1102 }
1103
1104 pub fn len(&self) -> usize {
1106 self.0.len()
1107 }
1108
1109 pub fn group_by_elem<'caller: 'buf, 'buf>(
1113 &'caller self,
1114 root: &'caller json::Element<'buf>,
1115 ) -> GroupByElem<'caller, 'buf, K> {
1116 let mut warnings = self.0.iter().collect::<Vec<_>>();
1117 warnings.sort_unstable_by_key(|warning| warning.elem_id);
1118
1119 GroupByElem {
1120 walker: json::walk::DepthFirst::new(root),
1121 warnings: warnings.into_iter().peekable(),
1122 }
1123 }
1124
1125 pub fn into_group_by_elem<'caller, 'buf>(
1129 self,
1130 root: &'caller json::Element<'buf>,
1131 ) -> IntoGroupByElem<'caller, 'buf, K> {
1132 let Self(mut warnings) = self;
1133 warnings.sort_unstable_by_key(|warning| warning.elem_id);
1134
1135 IntoGroupByElem {
1136 walker: json::walk::DepthFirst::new(root),
1137 warnings: warnings.into_iter().peekable(),
1138 }
1139 }
1140}
1141
1142pub struct IntoGroupByElem<'caller, 'buf, K>
1144where
1145 K: Kind,
1146{
1147 walker: json::walk::DepthFirst<'caller, 'buf>,
1149
1150 warnings: iter::Peekable<vec::IntoIter<Warning<K>>>,
1152}
1153
1154impl<K> IntoGroupByElem<'_, '_, K>
1155where
1156 K: Kind,
1157{
1158 pub fn into_kind_map(self) -> BTreeMap<String, Vec<K>> {
1160 self.map(IntoGroup::into_kinds).collect()
1161 }
1162
1163 pub fn into_id_map(self) -> BTreeMap<String, Vec<String>> {
1172 self.map(IntoGroup::into_str_ids).collect()
1173 }
1174
1175 pub fn into_msg_map(self) -> BTreeMap<String, Vec<String>> {
1181 self.map(IntoGroup::into_str_msgs).collect()
1182 }
1183}
1184
1185#[derive(Debug)]
1190pub struct IntoGroup<'caller, 'buf, K> {
1191 pub element: &'caller json::Element<'buf>,
1193
1194 pub warnings: Vec<K>,
1196}
1197
1198impl<K> IntoGroup<'_, '_, K>
1199where
1200 K: Kind,
1201{
1202 pub fn into_kinds(self) -> (String, Vec<K>) {
1207 let Self { element, warnings } = self;
1208 (element.path().to_string(), warnings)
1209 }
1210
1211 pub fn into_str_ids(self) -> (String, Vec<String>) {
1216 let Self { element, warnings } = self;
1217 (
1218 element.path().to_string(),
1219 warnings.iter().map(|kind| kind.id().to_string()).collect(),
1220 )
1221 }
1222
1223 pub fn into_str_msgs(self) -> (String, Vec<String>) {
1228 let Self { element, warnings } = self;
1229 (
1230 element.path().to_string(),
1231 warnings.iter().map(ToString::to_string).collect(),
1232 )
1233 }
1234}
1235
1236impl<'caller, 'buf, K: Kind> Iterator for IntoGroupByElem<'caller, 'buf, K> {
1237 type Item = IntoGroup<'caller, 'buf, K>;
1238
1239 fn next(&mut self) -> Option<Self::Item> {
1240 let warning = self.warnings.next()?;
1242
1243 let element = loop {
1245 let Some(element) = self.walker.next() else {
1246 error!("An Element with id: `{}` was not found", warning.elem_id);
1247 return None;
1248 };
1249
1250 if element.id() < warning.elem_id {
1251 continue;
1254 }
1255
1256 if element.id() > warning.elem_id {
1257 debug_assert!(
1258 element.id() <= warning.elem_id,
1259 "The elements or the warnings are not sorted."
1260 );
1261 return None;
1262 }
1263
1264 break element;
1266 };
1267
1268 let mut warnings_grouped = vec![warning.into_kind()];
1270
1271 loop {
1273 let warning = self.warnings.next_if(|w| w.elem_id == element.id());
1274 let Some(warning) = warning else {
1275 break;
1276 };
1277
1278 warnings_grouped.push(warning.into_kind());
1279 }
1280
1281 Some(IntoGroup {
1282 element,
1283 warnings: warnings_grouped,
1284 })
1285 }
1286}
1287
1288pub struct GroupByElem<'caller, 'buf, K>
1290where
1291 K: Kind,
1292{
1293 walker: json::walk::DepthFirst<'caller, 'buf>,
1295
1296 warnings: iter::Peekable<vec::IntoIter<&'caller Warning<K>>>,
1298}
1299
1300impl<K> GroupByElem<'_, '_, K>
1301where
1302 K: Kind,
1303{
1304 pub fn into_id_map(self) -> BTreeMap<String, Vec<String>> {
1313 self.map(Group::into_str_ids).collect()
1314 }
1315
1316 pub fn into_msg_map(self) -> BTreeMap<String, Vec<String>> {
1322 self.map(Group::into_str_msgs).collect()
1323 }
1324}
1325
1326#[derive(Debug)]
1331pub struct Group<'caller, 'buf, K> {
1332 pub element: &'caller json::Element<'buf>,
1334
1335 pub warnings: Vec<&'caller K>,
1337}
1338
1339impl<K> Group<'_, '_, K>
1340where
1341 K: Kind,
1342{
1343 pub fn into_str_ids(self) -> (String, Vec<String>) {
1348 let Self { element, warnings } = self;
1349 (
1350 element.path().to_string(),
1351 warnings.iter().map(|kind| kind.id().to_string()).collect(),
1352 )
1353 }
1354
1355 pub fn into_str_msgs(self) -> (String, Vec<String>) {
1360 let Self { element, warnings } = self;
1361 (
1362 element.path().to_string(),
1363 warnings.iter().map(ToString::to_string).collect(),
1364 )
1365 }
1366}
1367
1368impl<'caller, 'buf, K: Kind> Iterator for GroupByElem<'caller, 'buf, K> {
1369 type Item = Group<'caller, 'buf, K>;
1370
1371 fn next(&mut self) -> Option<Self::Item> {
1372 let warning = self.warnings.next()?;
1374
1375 let element = loop {
1377 let Some(element) = self.walker.next() else {
1378 error!("An Element with id: `{}` was not found", warning.elem_id);
1379 return None;
1380 };
1381
1382 if element.id() < warning.elem_id {
1383 continue;
1386 }
1387
1388 if element.id() > warning.elem_id {
1389 debug_assert!(
1390 element.id() <= warning.elem_id,
1391 "The elements or the warnings are not sorted."
1392 );
1393 return None;
1394 }
1395
1396 break element;
1398 };
1399
1400 let mut warnings_grouped = vec![warning.kind()];
1402
1403 loop {
1405 let warning = self.warnings.next_if(|w| w.elem_id == element.id());
1406 let Some(warning) = warning else {
1407 break;
1408 };
1409
1410 warnings_grouped.push(warning.kind());
1411 }
1412
1413 Some(Group {
1414 element,
1415 warnings: warnings_grouped,
1416 })
1417 }
1418}
1419
1420#[cfg(test)]
1421pub(crate) mod test {
1422 use std::{
1423 borrow::Cow,
1424 collections::{BTreeMap, BTreeSet},
1425 ops, slice,
1426 };
1427
1428 use assert_matches::assert_matches;
1429
1430 use crate::{
1431 json,
1432 test::{ExpectValue, Expectation},
1433 warning::CaveatDeferred,
1434 };
1435
1436 use super::{Caveat, Group, Kind, Set, Warning};
1437
1438 impl<K: Kind> Set<K> {
1439 pub fn into_vec(self) -> Vec<Warning<K>> {
1441 self.0
1442 }
1443
1444 pub fn into_parts_vec(self) -> Vec<(K, json::ElemId)> {
1445 self.0
1446 .into_iter()
1447 .map(|Warning { kind, elem_id }| (kind, elem_id))
1448 .collect()
1449 }
1450
1451 pub fn into_kind_vec(self) -> Vec<K> {
1455 self.0.into_iter().map(Warning::into_kind).collect()
1456 }
1457
1458 pub fn as_slice(&self) -> &[Warning<K>] {
1460 self.0.as_slice()
1461 }
1462
1463 pub fn iter(&self) -> slice::Iter<'_, Warning<K>> {
1465 self.0.iter()
1466 }
1467 }
1468
1469 impl<K: Kind> ops::Deref for Set<K> {
1470 type Target = [Warning<K>];
1471
1472 fn deref(&self) -> &[Warning<K>] {
1473 self.as_slice()
1474 }
1475 }
1476
1477 impl<K: Kind> IntoIterator for Set<K> {
1478 type Item = Warning<K>;
1479
1480 type IntoIter = <Vec<Self::Item> as IntoIterator>::IntoIter;
1481
1482 fn into_iter(self) -> Self::IntoIter {
1483 self.0.into_iter()
1484 }
1485 }
1486
1487 impl<'a, K: Kind> IntoIterator for &'a Set<K> {
1488 type Item = &'a Warning<K>;
1489
1490 type IntoIter = slice::Iter<'a, Warning<K>>;
1491
1492 fn into_iter(self) -> Self::IntoIter {
1493 self.0.iter()
1494 }
1495 }
1496
1497 impl<T, K> Caveat<T, K>
1498 where
1499 K: Kind,
1500 {
1501 pub fn unwrap(self) -> T {
1503 let Self { value, warnings } = self;
1504 assert_matches!(warnings.into_vec().as_slice(), []);
1505 value
1506 }
1507 }
1508
1509 impl<T, K> CaveatDeferred<T, K>
1510 where
1511 K: Kind,
1512 {
1513 pub fn unwrap(self) -> T {
1515 let Self { value, warnings } = self;
1516 assert_matches!(warnings.0.as_slice(), []);
1517 value
1518 }
1519 }
1520
1521 pub(crate) fn assert_warnings<K>(
1525 expect_file_name: &str,
1526 root: &json::Element<'_>,
1527 warnings: &Set<K>,
1528 expected: Expectation<BTreeMap<String, Vec<String>>>,
1529 ) where
1530 K: Kind,
1531 {
1532 let Expectation::Present(ExpectValue::Some(expected)) = expected else {
1533 assert!(
1534 warnings.is_empty(),
1535 "There is no `warnings` field in the `{expect_file_name}` file but the tariff has warnings;\n{:?}",
1536 warnings.group_by_elem(root).into_id_map()
1537 );
1538 return;
1539 };
1540
1541 {
1542 let warnings_grouped = warnings
1544 .group_by_elem(root)
1545 .map(|Group { element, warnings }| (element.path().to_string(), warnings))
1546 .collect::<BTreeMap<_, _>>();
1547
1548 let mut elems_in_expect_without_warning = vec![];
1549
1550 for elem_path in expected.keys() {
1551 if !warnings_grouped.contains_key(elem_path) {
1552 elems_in_expect_without_warning.push(elem_path);
1553 }
1554 }
1555
1556 assert!(elems_in_expect_without_warning.is_empty(),
1557 "The expect file `{expect_file_name}` has entries for elements that have no warnings:\n\
1558 {elems_in_expect_without_warning:#?}"
1559 );
1560 }
1561
1562 let mut elems_missing_from_expect = vec![];
1564 let mut unequal_warnings = vec![];
1567
1568 for group in warnings.group_by_elem(root) {
1569 let path_str = group.element.path().to_string();
1570 let Some(warnings_expected) = expected.get(&*path_str) else {
1571 elems_missing_from_expect.push(group);
1572 continue;
1573 };
1574
1575 let warnings_expected = warnings_expected
1577 .iter()
1578 .map(|s| Cow::Borrowed(&**s))
1579 .collect::<BTreeSet<_>>();
1580 let warnings = group
1581 .warnings
1582 .iter()
1583 .map(|w| w.id())
1584 .collect::<BTreeSet<_>>();
1585
1586 if warnings_expected != warnings {
1587 unequal_warnings.push(group);
1588 }
1589 }
1590
1591 if !elems_missing_from_expect.is_empty() || !unequal_warnings.is_empty() {
1592 let missing = elems_missing_from_expect
1593 .into_iter()
1594 .map(Group::into_str_ids)
1595 .collect::<BTreeMap<_, _>>();
1596
1597 let unequal = unequal_warnings
1598 .into_iter()
1599 .map(Group::into_str_ids)
1600 .collect::<BTreeMap<_, _>>();
1601
1602 match (!missing.is_empty(), !unequal.is_empty()) {
1603 (true, true) => panic!(
1604 "Elements with warnings but are not defined in the `{expect_file_name}` file:\n{missing:#?}\n\
1605 Elements that are in the `{expect_file_name}` file but the warnings list is not correct.\n\
1606 The warnings reported are: \n{unequal:#?}"
1607 ),
1608 (true, false) => panic!("Elements with warnings but are not defined in the `{expect_file_name}` file:\n{missing:#?}"),
1609 (false, true) => panic!(
1610 "Elements that are in the `{expect_file_name}` file but the warnings list is not correct.\n\
1611 The warnings reported are: \n{unequal:#?}"
1612 ),
1613 (false, false) => (),
1614 }
1615 }
1616 }
1617}
1618
1619#[cfg(test)]
1620mod test_group_by_elem {
1621 use std::fmt;
1622
1623 use assert_matches::assert_matches;
1624
1625 use crate::{json, test};
1626
1627 use super::{Group, IntoGroup, Kind, Set, Warning};
1628
1629 const JSON: &str = r#"{
1630 "field_one#": "one",
1631 "field_two": "two",
1632 "field_three": "three"
1633}"#;
1634
1635 #[derive(Debug)]
1636 enum WarningKind {
1637 Root,
1638 One,
1639 OneAgain,
1640 Three,
1641 }
1642
1643 impl Kind for WarningKind {
1644 fn id(&self) -> std::borrow::Cow<'static, str> {
1645 match self {
1646 WarningKind::Root => "root".into(),
1647 WarningKind::One => "one".into(),
1648 WarningKind::OneAgain => "one_again".into(),
1649 WarningKind::Three => "three".into(),
1650 }
1651 }
1652 }
1653
1654 impl fmt::Display for WarningKind {
1655 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1656 match self {
1657 WarningKind::Root => write!(f, "NopeRoot"),
1658 WarningKind::One => write!(f, "NopeOne"),
1659 WarningKind::OneAgain => write!(f, "NopeOneAgain"),
1660 WarningKind::Three => write!(f, "NopeThree"),
1661 }
1662 }
1663 }
1664
1665 #[test]
1666 fn should_group_by_elem() {
1667 test::setup();
1668
1669 let elem = parse(JSON);
1670 let mut warnings = Set::<WarningKind>::new();
1671
1672 warnings.push(Warning {
1675 kind: WarningKind::Root,
1676 elem_id: json::ElemId::from(0),
1677 });
1678 warnings.push(Warning {
1679 kind: WarningKind::One,
1680 elem_id: json::ElemId::from(1),
1681 });
1682 warnings.push(Warning {
1683 kind: WarningKind::Three,
1684 elem_id: json::ElemId::from(3),
1685 });
1686 warnings.push(Warning {
1687 kind: WarningKind::OneAgain,
1688 elem_id: json::ElemId::from(1),
1689 });
1690
1691 let mut iter = warnings.group_by_elem(&elem);
1692
1693 {
1694 let Group { element, warnings } = iter.next().unwrap();
1695
1696 assert!(
1697 element.value().is_object(),
1698 "The root object should be emitted first"
1699 );
1700 assert_eq!(
1701 element.id(),
1702 json::ElemId::from(0),
1703 "The root object should be emitted first"
1704 );
1705 assert_matches!(warnings.as_slice(), [WarningKind::Root]);
1706 }
1707
1708 {
1709 let Group { element, warnings } = iter.next().unwrap();
1710
1711 assert_eq!(element.value().as_raw_str().unwrap().as_raw(), "one");
1712 assert_eq!(element.id(), json::ElemId::from(1));
1713 assert_matches!(
1714 warnings.as_slice(),
1715 [WarningKind::One, WarningKind::OneAgain],
1716 "[`json::Element`] 1 should have two warnings"
1717 );
1718 }
1719
1720 {
1721 let Group { element, warnings } = iter.next().unwrap();
1723
1724 assert_eq!(element.value().as_raw_str().unwrap().as_raw(), "three");
1725 assert_eq!(element.id(), json::ElemId::from(3));
1726 assert_matches!(warnings.as_slice(), [WarningKind::Three]);
1727 }
1728 }
1729
1730 #[test]
1731 fn should_into_group_by_elem() {
1732 test::setup();
1733
1734 let elem = parse(JSON);
1735 let mut warnings = Set::<WarningKind>::new();
1736
1737 warnings.push(Warning {
1740 kind: WarningKind::Root,
1741 elem_id: json::ElemId::from(0),
1742 });
1743 warnings.push(Warning {
1744 kind: WarningKind::Three,
1745 elem_id: json::ElemId::from(3),
1746 });
1747 warnings.push(Warning {
1748 kind: WarningKind::One,
1749 elem_id: json::ElemId::from(1),
1750 });
1751 warnings.push(Warning {
1752 kind: WarningKind::OneAgain,
1753 elem_id: json::ElemId::from(1),
1754 });
1755
1756 let mut iter = warnings.into_group_by_elem(&elem);
1757
1758 {
1759 let IntoGroup { element, warnings } = iter.next().unwrap();
1760
1761 assert!(
1762 element.value().is_object(),
1763 "The root object should be emitted first"
1764 );
1765 assert_eq!(
1766 element.id(),
1767 json::ElemId::from(0),
1768 "The root object should be emitted first"
1769 );
1770 assert_matches!(warnings.as_slice(), [WarningKind::Root]);
1771 }
1772
1773 {
1774 let IntoGroup { element, warnings } = iter.next().unwrap();
1775
1776 assert_eq!(element.value().as_raw_str().unwrap().as_raw(), "one");
1777 assert_eq!(element.id(), json::ElemId::from(1));
1778 assert_matches!(
1779 warnings.as_slice(),
1780 [WarningKind::One, WarningKind::OneAgain],
1781 "[`json::Element`] 1 should have two warnings"
1782 );
1783 }
1784
1785 {
1786 let IntoGroup { element, warnings } = iter.next().unwrap();
1788
1789 assert_eq!(element.value().as_raw_str().unwrap().as_raw(), "three");
1790 assert_eq!(element.id(), json::ElemId::from(3));
1791 assert_matches!(warnings.as_slice(), [WarningKind::Three]);
1792 }
1793 }
1794
1795 fn parse(json: &str) -> json::Element<'_> {
1796 json::parse(json).unwrap()
1797 }
1798}