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}
77
78#[doc(hidden)]
80#[macro_export]
81macro_rules! into_caveat_all {
82 ($($kind:ty),+) => {
83 $(impl $crate::IntoCaveat for $kind {
84 fn into_caveat<K: $crate::warning::Kind>(
85 self,
86 warnings: $crate::warning::Set<K>,
87 ) -> $crate::Caveat<Self, K> {
88 $crate::Caveat::new(self, warnings)
89 }
90 })+
91 };
92}
93
94pub type Verdict<T, K> = Result<Caveat<T, K>, Set<K>>;
96
97#[derive(Debug)]
101pub struct Caveat<T, K: Kind> {
102 value: T,
104
105 warnings: Set<K>,
107}
108
109impl<T, K> Caveat<T, K>
110where
111 T: IntoCaveat,
112 K: Kind,
113{
114 pub(crate) fn new(value: T, warnings: Set<K>) -> Self {
116 Self { value, warnings }
117 }
118}
119
120impl<T, K> Deref for Caveat<T, K>
132where
133 K: Kind,
134{
135 type Target = T;
136
137 fn deref(&self) -> &T {
138 &self.value
139 }
140}
141
142impl<T, K> Caveat<T, K>
143where
144 K: Kind,
145{
146 pub fn into_parts(self) -> (T, Set<K>) {
148 let Self { value, warnings } = self;
149 (value, warnings)
150 }
151
152 pub fn ignore_warnings(self) -> T {
154 self.value
155 }
156
157 pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Caveat<U, K> {
159 let Self { value, warnings } = self;
160 Caveat {
161 value: op(value),
162 warnings,
163 }
164 }
165}
166
167pub(crate) trait GatherWarnings<T, K>
172where
173 K: Kind,
174{
175 type Output;
177
178 fn gather_warnings_into<KA>(self, warnings: &mut Set<KA>) -> Self::Output
180 where
181 K: Into<KA>,
182 KA: Kind;
183}
184
185impl<T, K> GatherWarnings<T, K> for Caveat<T, K>
187where
188 K: Kind,
189{
190 type Output = T;
191
192 fn gather_warnings_into<KA>(self, warnings: &mut Set<KA>) -> Self::Output
194 where
195 K: Into<KA>,
196 KA: Kind,
197 {
198 let Self {
199 value,
200 warnings: inner_warnings,
201 } = self;
202
203 warnings.extend(inner_warnings);
204
205 value
206 }
207}
208
209impl<T, K> GatherWarnings<T, K> for Option<Caveat<T, K>>
211where
212 K: Kind,
213{
214 type Output = Option<T>;
215
216 fn gather_warnings_into<KA>(self, warnings: &mut Set<KA>) -> Self::Output
218 where
219 K: Into<KA>,
220 KA: Kind,
221 {
222 match self {
223 Some(cv) => Some(cv.gather_warnings_into(warnings)),
224 None => None,
225 }
226 }
227}
228
229impl<T, K, E> GatherWarnings<T, K> for Result<Caveat<T, K>, E>
231where
232 K: Kind,
233 E: std::error::Error,
234{
235 type Output = Result<T, E>;
236
237 fn gather_warnings_into<KA>(self, warnings: &mut Set<KA>) -> Self::Output
239 where
240 K: Into<KA>,
241 KA: Kind,
242 {
243 match self {
244 Ok(cv) => Ok(cv.gather_warnings_into(warnings)),
245 Err(err) => Err(err),
246 }
247 }
248}
249
250impl<T, K> GatherWarnings<T, K> for Vec<Caveat<T, K>>
252where
253 K: Kind,
254{
255 type Output = Vec<T>;
256
257 fn gather_warnings_into<KA>(self, warnings: &mut Set<KA>) -> Self::Output
259 where
260 K: Into<KA>,
261 KA: Kind,
262 {
263 self.into_iter()
264 .map(|cv| cv.gather_warnings_into(warnings))
265 .collect()
266 }
267}
268
269pub trait IntoCaveat: Sized {
273 fn into_caveat<K: Kind>(self, warnings: Set<K>) -> Caveat<Self, K>;
275}
276
277into_caveat_all!(
278 (),
279 bool,
280 char,
281 u8,
282 u16,
283 u32,
284 u64,
285 u128,
286 i8,
287 i16,
288 i32,
289 i64,
290 i128
291);
292
293impl IntoCaveat for Cow<'_, str> {
295 fn into_caveat<K: Kind>(self, warnings: Set<K>) -> Caveat<Self, K> {
296 Caveat::new(self, warnings)
297 }
298}
299
300impl<T> IntoCaveat for Option<T>
302where
303 T: IntoCaveat,
304{
305 fn into_caveat<K: Kind>(self, warnings: Set<K>) -> Caveat<Self, K> {
306 Caveat::new(self, warnings)
307 }
308}
309
310pub trait VerdictExt<T, K: Kind> {
312 fn ok_caveat(self) -> Caveat<Option<T>, K>;
316
317 fn map_caveat<F, U>(self, op: F) -> Verdict<U, K>
320 where
321 F: FnOnce(T) -> U;
322}
323
324impl<T, K: Kind> VerdictExt<T, K> for Verdict<T, K>
325where
326 T: IntoCaveat,
327{
328 fn ok_caveat(self) -> Caveat<Option<T>, K> {
329 match self {
330 Ok(v) => {
331 let (v, warnings) = v.into_parts();
332 Some(v).into_caveat(warnings)
333 }
334 Err(warnings) => None.into_caveat(warnings),
335 }
336 }
337
338 fn map_caveat<F, U>(self, op: F) -> Verdict<U, K>
339 where
340 F: FnOnce(T) -> U,
341 {
342 match self {
343 Ok(c) => Ok(c.map(op)),
344 Err(w) => Err(w),
345 }
346 }
347}
348
349#[macro_export]
354#[doc(hidden)]
355macro_rules! from_warning_set_to {
356 ($kind_a:path => $kind_b:path) => {
357 impl From<$crate::warning::Set<$kind_a>> for $crate::warning::Set<$kind_b> {
358 fn from(set_a: warning::Set<$kind_a>) -> Self {
359 set_a.into_set()
360 }
361 }
362 };
363}
364
365pub trait OptionExt<T, K>
367where
368 K: Kind,
369{
370 fn exit_with_warning<F>(self, warnings: Set<K>, f: F) -> Verdict<T, K>
372 where
373 F: FnOnce() -> Warning<K>;
374}
375
376impl<T, K> OptionExt<T, K> for Option<T>
377where
378 T: IntoCaveat,
379 K: Kind,
380{
381 fn exit_with_warning<F>(self, mut warnings: Set<K>, f: F) -> Verdict<T, K>
382 where
383 F: FnOnce() -> Warning<K>,
384 {
385 if let Some(v) = self {
386 Ok(v.into_caveat(warnings))
387 } else {
388 warnings.push(f());
389 Err(warnings)
390 }
391 }
392}
393
394#[derive(Debug)]
398pub struct Warning<K: Kind> {
399 kind: K,
401
402 elem_id: json::ElemId,
404}
405
406pub struct SetWriter<'caller, 'buf, K: Kind> {
420 root_elem: &'caller json::Element<'buf>,
422
423 warnings: &'caller Set<K>,
425
426 indent: &'caller str,
428}
429
430impl<'caller, 'buf, K: Kind> SetWriter<'caller, 'buf, K> {
431 pub fn new(root_elem: &'caller json::Element<'buf>, warnings: &'caller Set<K>) -> Self {
433 Self {
434 root_elem,
435 warnings,
436 indent: " - ",
437 }
438 }
439
440 pub fn with_indent(
442 root_elem: &'caller json::Element<'buf>,
443 warnings: &'caller Set<K>,
444 indent: &'caller str,
445 ) -> Self {
446 Self {
447 root_elem,
448 warnings,
449 indent,
450 }
451 }
452}
453
454impl<K: Kind> fmt::Debug for SetWriter<'_, '_, K> {
455 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
456 fmt::Display::fmt(self, f)
457 }
458}
459
460impl<K: Kind> fmt::Display for SetWriter<'_, '_, K> {
461 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
462 let mut iter = self.warnings.group_by_elem(self.root_elem);
463
464 {
465 let Some(Group { element, warnings }) = iter.next() else {
467 return Ok(());
468 };
469
470 writeln!(f, "{}", element.path())?;
471
472 for warning in warnings {
473 write!(f, "{}{}", self.indent, warning)?;
474 }
475 }
476
477 for Group { element, warnings } in iter {
479 writeln!(f, "\n{}", element.path())?;
480
481 for warning in warnings {
482 write!(f, "{}{}", self.indent, warning)?;
483 }
484 }
485
486 Ok(())
487 }
488}
489
490impl<K: Kind> Warning<K> {
491 pub(crate) const fn with_elem(kind: K, elem: &json::Element<'_>) -> Warning<K> {
495 Warning {
496 kind,
497 elem_id: elem.id(),
498 }
499 }
500
501 pub fn id(&self) -> Cow<'static, str> {
503 self.kind.id()
504 }
505
506 pub fn kind(&self) -> &K {
508 &self.kind
509 }
510
511 pub fn into_kind(self) -> K {
513 self.kind
514 }
515}
516
517impl<K: Kind> fmt::Display for Warning<K> {
518 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
519 write!(f, "{}", self.kind)
520 }
521}
522
523pub trait Kind: Sized + fmt::Debug + fmt::Display {
527 fn id(&self) -> Cow<'static, str>;
532}
533
534#[derive(Debug)]
536pub struct Set<K: Kind>(Vec<Warning<K>>);
537
538impl<K: Kind> Set<K> {
539 pub(crate) fn new() -> Self {
541 Self(vec![])
542 }
543
544 pub(crate) fn from_vec(warnings: Vec<Warning<K>>) -> Self {
545 Self(warnings)
546 }
547
548 fn push(&mut self, warning: Warning<K>) {
550 self.0.push(warning);
551 }
552
553 pub(crate) fn with_elem(&mut self, kind: K, elem: &json::Element<'_>) {
555 self.push(Warning::with_elem(kind, elem));
556 }
557
558 pub(crate) fn into_set<KB>(self) -> Set<KB>
562 where
563 KB: Kind + From<K>,
564 {
565 let warnings = self
566 .0
567 .into_iter()
568 .map(|warn| {
569 let Warning { kind, elem_id } = warn;
570 Warning {
571 kind: kind.into(),
572 elem_id,
573 }
574 })
575 .collect();
576
577 Set(warnings)
578 }
579
580 pub(crate) fn map_warning<KU>(self) -> Set<KU>
584 where
585 KU: Kind + From<K>,
586 {
587 let warnings = self
588 .0
589 .into_iter()
590 .map(|warn| {
591 let Warning { kind, elem_id } = warn;
592 Warning {
593 kind: kind.into(),
594 elem_id,
595 }
596 })
597 .collect();
598
599 Set(warnings)
600 }
601
602 pub(crate) fn extend<KA>(&mut self, warnings: Set<KA>)
606 where
607 KA: Into<K> + Kind,
608 {
609 self.0.extend(warnings.0.into_iter().map(|warn| {
610 let Warning { kind, elem_id } = warn;
611 Warning {
612 kind: kind.into(),
613 elem_id,
614 }
615 }));
616 }
617
618 pub fn is_empty(&self) -> bool {
620 self.0.is_empty()
621 }
622
623 pub fn len(&self) -> usize {
625 self.0.len()
626 }
627
628 pub fn group_by_elem<'caller: 'buf, 'buf>(
632 &'caller self,
633 root: &'caller json::Element<'buf>,
634 ) -> GroupByElem<'caller, 'buf, K> {
635 let mut warnings = self.0.iter().collect::<Vec<_>>();
636 warnings.sort_unstable_by_key(|warning| warning.elem_id);
637
638 GroupByElem {
639 walker: json::walk::DepthFirst::new(root),
640 warnings: warnings.into_iter().peekable(),
641 }
642 }
643
644 pub fn into_group_by_elem<'caller, 'buf>(
648 self,
649 root: &'caller json::Element<'buf>,
650 ) -> IntoGroupByElem<'caller, 'buf, K> {
651 let Self(mut warnings) = self;
652 warnings.sort_unstable_by_key(|warning| warning.elem_id);
653
654 IntoGroupByElem {
655 walker: json::walk::DepthFirst::new(root),
656 warnings: warnings.into_iter().peekable(),
657 }
658 }
659}
660
661pub struct IntoGroupByElem<'caller, 'buf, K>
663where
664 K: Kind,
665{
666 walker: json::walk::DepthFirst<'caller, 'buf>,
668
669 warnings: iter::Peekable<vec::IntoIter<Warning<K>>>,
671}
672
673#[derive(Debug)]
678pub struct IntoGroup<'caller, 'buf, K> {
679 pub element: &'caller json::Element<'buf>,
681
682 pub warnings: Vec<K>,
684}
685
686impl<'caller, 'buf, K: Kind> Iterator for IntoGroupByElem<'caller, 'buf, K> {
687 type Item = IntoGroup<'caller, 'buf, K>;
688
689 fn next(&mut self) -> Option<Self::Item> {
690 let warning = self.warnings.next()?;
692
693 let element = loop {
695 let Some(element) = self.walker.next() else {
696 error!("An Element with id: `{}` was not found", warning.elem_id);
697 return None;
698 };
699
700 if element.id() < warning.elem_id {
701 continue;
704 }
705
706 if element.id() > warning.elem_id {
707 debug_assert!(
708 element.id() <= warning.elem_id,
709 "The elements or the warnings are not sorted."
710 );
711 return None;
712 }
713
714 break element;
716 };
717
718 let mut warnings_grouped = vec![warning.into_kind()];
720
721 loop {
723 let warning = self.warnings.next_if(|w| w.elem_id == element.id());
724 let Some(warning) = warning else {
725 break;
726 };
727
728 warnings_grouped.push(warning.into_kind());
729 }
730
731 Some(IntoGroup {
732 element,
733 warnings: warnings_grouped,
734 })
735 }
736}
737
738pub struct GroupByElem<'caller, 'buf, K>
740where
741 K: Kind,
742{
743 walker: json::walk::DepthFirst<'caller, 'buf>,
745
746 warnings: iter::Peekable<vec::IntoIter<&'caller Warning<K>>>,
748}
749
750impl<K> GroupByElem<'_, '_, K>
751where
752 K: Kind,
753{
754 pub fn into_stringified_map(self) -> BTreeMap<String, Vec<String>> {
761 self.map(Group::stringify).collect()
762 }
763}
764
765#[derive(Debug)]
770pub struct Group<'caller, 'buf, K> {
771 pub element: &'caller json::Element<'buf>,
773
774 pub warnings: Vec<&'caller K>,
776}
777
778impl<K> Group<'_, '_, K>
779where
780 K: Kind,
781{
782 pub fn stringify(self) -> (String, Vec<String>) {
784 let Self { element, warnings } = self;
785 (
786 element.path().to_string(),
787 warnings.iter().map(|kind| kind.id().to_string()).collect(),
788 )
789 }
790}
791
792impl<'caller, 'buf, K: Kind> Iterator for GroupByElem<'caller, 'buf, K> {
793 type Item = Group<'caller, 'buf, K>;
794
795 fn next(&mut self) -> Option<Self::Item> {
796 let warning = self.warnings.next()?;
798
799 let element = loop {
801 let Some(element) = self.walker.next() else {
802 error!("An Element with id: `{}` was not found", warning.elem_id);
803 return None;
804 };
805
806 if element.id() < warning.elem_id {
807 continue;
810 }
811
812 if element.id() > warning.elem_id {
813 debug_assert!(
814 element.id() <= warning.elem_id,
815 "The elements or the warnings are not sorted."
816 );
817 return None;
818 }
819
820 break element;
822 };
823
824 let mut warnings_grouped = vec![warning.kind()];
826
827 loop {
829 let warning = self.warnings.next_if(|w| w.elem_id == element.id());
830 let Some(warning) = warning else {
831 break;
832 };
833
834 warnings_grouped.push(warning.kind());
835 }
836
837 Some(Group {
838 element,
839 warnings: warnings_grouped,
840 })
841 }
842}
843
844#[cfg(test)]
845pub(crate) mod test {
846 use std::{
847 borrow::Cow,
848 collections::{BTreeMap, BTreeSet},
849 ops, slice,
850 };
851
852 use assert_matches::assert_matches;
853
854 use crate::{
855 json,
856 test::{ExpectValue, Expectation},
857 };
858
859 use super::{Caveat, Group, Kind, Set, Warning};
860
861 impl<K: Kind> Set<K> {
862 pub fn into_vec(self) -> Vec<Warning<K>> {
864 self.0
865 }
866
867 pub fn into_parts_vec(self) -> Vec<(K, json::ElemId)> {
868 self.0
869 .into_iter()
870 .map(|Warning { kind, elem_id }| (kind, elem_id))
871 .collect()
872 }
873
874 pub fn into_kind_vec(self) -> Vec<K> {
878 self.0.into_iter().map(Warning::into_kind).collect()
879 }
880
881 pub fn as_slice(&self) -> &[Warning<K>] {
883 self.0.as_slice()
884 }
885
886 pub fn iter(&self) -> slice::Iter<'_, Warning<K>> {
888 self.0.iter()
889 }
890 }
891
892 impl<K: Kind> ops::Deref for Set<K> {
893 type Target = [Warning<K>];
894
895 fn deref(&self) -> &[Warning<K>] {
896 self.as_slice()
897 }
898 }
899
900 impl<K: Kind> IntoIterator for Set<K> {
901 type Item = Warning<K>;
902
903 type IntoIter = <Vec<Self::Item> as IntoIterator>::IntoIter;
904
905 fn into_iter(self) -> Self::IntoIter {
906 self.0.into_iter()
907 }
908 }
909
910 impl<'a, K: Kind> IntoIterator for &'a Set<K> {
911 type Item = &'a Warning<K>;
912
913 type IntoIter = slice::Iter<'a, Warning<K>>;
914
915 fn into_iter(self) -> Self::IntoIter {
916 self.0.iter()
917 }
918 }
919
920 impl<T, K> Caveat<T, K>
921 where
922 K: Kind,
923 {
924 pub fn unwrap(self) -> T {
926 let Self { value, warnings } = self;
927 assert_matches!(warnings.into_vec().as_slice(), []);
928 value
929 }
930 }
931
932 pub(crate) fn assert_warnings<K>(
936 expect_file_name: &str,
937 root: &json::Element<'_>,
938 warnings: &Set<K>,
939 expected: Expectation<BTreeMap<String, Vec<String>>>,
940 ) where
941 K: Kind,
942 {
943 let Expectation::Present(ExpectValue::Some(expected)) = expected else {
944 assert!(
945 warnings.is_empty(),
946 "There is no `warnings` field in the `{expect_file_name}` file but the tariff has warnings;\n{:?}",
947 warnings.group_by_elem(root).into_stringified_map()
948 );
949 return;
950 };
951
952 {
953 let warnings_grouped = warnings
955 .group_by_elem(root)
956 .map(|Group { element, warnings }| (element.path().to_string(), warnings))
957 .collect::<BTreeMap<_, _>>();
958
959 let mut elems_in_expect_without_warning = vec![];
960
961 for elem_path in expected.keys() {
962 if !warnings_grouped.contains_key(elem_path) {
963 elems_in_expect_without_warning.push(elem_path);
964 }
965 }
966
967 assert!(elems_in_expect_without_warning.is_empty(),
968 "The expect file `{expect_file_name}` has entries for elements that have no warnings:\n\
969 {elems_in_expect_without_warning:#?}"
970 );
971 }
972
973 let mut elems_missing_from_expect = vec![];
975 let mut unequal_warnings = vec![];
978
979 for group in warnings.group_by_elem(root) {
980 let path_str = group.element.path().to_string();
981 let Some(warnings_expected) = expected.get(&*path_str) else {
982 elems_missing_from_expect.push(group);
983 continue;
984 };
985
986 let warnings_expected = warnings_expected
988 .iter()
989 .map(|s| Cow::Borrowed(&**s))
990 .collect::<BTreeSet<_>>();
991 let warnings = group
992 .warnings
993 .iter()
994 .map(|w| w.id())
995 .collect::<BTreeSet<_>>();
996
997 if warnings_expected != warnings {
998 unequal_warnings.push(group);
999 }
1000 }
1001
1002 if !elems_missing_from_expect.is_empty() || !unequal_warnings.is_empty() {
1003 let missing = elems_missing_from_expect
1004 .into_iter()
1005 .map(Group::stringify)
1006 .collect::<BTreeMap<_, _>>();
1007
1008 let unequal = unequal_warnings
1009 .into_iter()
1010 .map(Group::stringify)
1011 .collect::<BTreeMap<_, _>>();
1012
1013 match (!missing.is_empty(), !unequal.is_empty()) {
1014 (true, true) => panic!(
1015 "Elements with warnings but are not defined in the `{expect_file_name}` file:\n{missing:#?}\n\
1016 Elements that are in the `{expect_file_name}` file but the warnings list is not correct.\n\
1017 The warnings reported are: \n{unequal:#?}"
1018 ),
1019 (true, false) => panic!("Elements with warnings but are not defined in the `{expect_file_name}` file:\n{missing:#?}"),
1020 (false, true) => panic!(
1021 "Elements that are in the `{expect_file_name}` file but the warnings list is not correct.\n\
1022 The warnings reported are: \n{unequal:#?}"
1023 ),
1024 (false, false) => (),
1025 }
1026 }
1027 }
1028}
1029
1030#[cfg(test)]
1031mod test_group_by_elem {
1032 use std::fmt;
1033
1034 use assert_matches::assert_matches;
1035
1036 use crate::{json, test};
1037
1038 use super::{Group, IntoGroup, Kind, Set, Warning};
1039
1040 const JSON: &str = r#"{
1041 "field_one#": "one",
1042 "field_two": "two",
1043 "field_three": "three"
1044}"#;
1045
1046 #[derive(Debug)]
1047 enum WarningKind {
1048 Root,
1049 One,
1050 OneAgain,
1051 Three,
1052 }
1053
1054 impl Kind for WarningKind {
1055 fn id(&self) -> std::borrow::Cow<'static, str> {
1056 match self {
1057 WarningKind::Root => "root".into(),
1058 WarningKind::One => "one".into(),
1059 WarningKind::OneAgain => "one_again".into(),
1060 WarningKind::Three => "three".into(),
1061 }
1062 }
1063 }
1064
1065 impl fmt::Display for WarningKind {
1066 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1067 match self {
1068 WarningKind::Root => write!(f, "NopeRoot"),
1069 WarningKind::One => write!(f, "NopeOne"),
1070 WarningKind::OneAgain => write!(f, "NopeOneAgain"),
1071 WarningKind::Three => write!(f, "NopeThree"),
1072 }
1073 }
1074 }
1075
1076 #[test]
1077 fn should_group_by_elem() {
1078 test::setup();
1079
1080 let elem = parse(JSON);
1081 let mut warnings = Set::<WarningKind>::new();
1082
1083 warnings.push(Warning {
1086 kind: WarningKind::Root,
1087 elem_id: json::ElemId::from(0),
1088 });
1089 warnings.push(Warning {
1090 kind: WarningKind::One,
1091 elem_id: json::ElemId::from(1),
1092 });
1093 warnings.push(Warning {
1094 kind: WarningKind::Three,
1095 elem_id: json::ElemId::from(3),
1096 });
1097 warnings.push(Warning {
1098 kind: WarningKind::OneAgain,
1099 elem_id: json::ElemId::from(1),
1100 });
1101
1102 let mut iter = warnings.group_by_elem(&elem);
1103
1104 {
1105 let Group { element, warnings } = iter.next().unwrap();
1106
1107 assert!(
1108 element.value().is_object(),
1109 "The root object should be emitted first"
1110 );
1111 assert_eq!(
1112 element.id(),
1113 json::ElemId::from(0),
1114 "The root object should be emitted first"
1115 );
1116 assert_matches!(warnings.as_slice(), [WarningKind::Root]);
1117 }
1118
1119 {
1120 let Group { element, warnings } = iter.next().unwrap();
1121
1122 assert_eq!(element.value().as_raw_str().unwrap().as_raw(), "one");
1123 assert_eq!(element.id(), json::ElemId::from(1));
1124 assert_matches!(
1125 warnings.as_slice(),
1126 [WarningKind::One, WarningKind::OneAgain],
1127 "[`json::Element`] 1 should have two warnings"
1128 );
1129 }
1130
1131 {
1132 let Group { element, warnings } = iter.next().unwrap();
1134
1135 assert_eq!(element.value().as_raw_str().unwrap().as_raw(), "three");
1136 assert_eq!(element.id(), json::ElemId::from(3));
1137 assert_matches!(warnings.as_slice(), [WarningKind::Three]);
1138 }
1139 }
1140
1141 #[test]
1142 fn should_into_group_by_elem() {
1143 test::setup();
1144
1145 let elem = parse(JSON);
1146 let mut warnings = Set::<WarningKind>::new();
1147
1148 warnings.push(Warning {
1151 kind: WarningKind::Root,
1152 elem_id: json::ElemId::from(0),
1153 });
1154 warnings.push(Warning {
1155 kind: WarningKind::Three,
1156 elem_id: json::ElemId::from(3),
1157 });
1158 warnings.push(Warning {
1159 kind: WarningKind::One,
1160 elem_id: json::ElemId::from(1),
1161 });
1162 warnings.push(Warning {
1163 kind: WarningKind::OneAgain,
1164 elem_id: json::ElemId::from(1),
1165 });
1166
1167 let mut iter = warnings.into_group_by_elem(&elem);
1168
1169 {
1170 let IntoGroup { element, warnings } = iter.next().unwrap();
1171
1172 assert!(
1173 element.value().is_object(),
1174 "The root object should be emitted first"
1175 );
1176 assert_eq!(
1177 element.id(),
1178 json::ElemId::from(0),
1179 "The root object should be emitted first"
1180 );
1181 assert_matches!(warnings.as_slice(), [WarningKind::Root]);
1182 }
1183
1184 {
1185 let IntoGroup { element, warnings } = iter.next().unwrap();
1186
1187 assert_eq!(element.value().as_raw_str().unwrap().as_raw(), "one");
1188 assert_eq!(element.id(), json::ElemId::from(1));
1189 assert_matches!(
1190 warnings.as_slice(),
1191 [WarningKind::One, WarningKind::OneAgain],
1192 "[`json::Element`] 1 should have two warnings"
1193 );
1194 }
1195
1196 {
1197 let IntoGroup { element, warnings } = iter.next().unwrap();
1199
1200 assert_eq!(element.value().as_raw_str().unwrap().as_raw(), "three");
1201 assert_eq!(element.id(), json::ElemId::from(3));
1202 assert_matches!(warnings.as_slice(), [WarningKind::Three]);
1203 }
1204 }
1205
1206 fn parse(json: &str) -> json::Element<'_> {
1207 json::parse(json).unwrap()
1208 }
1209}