Skip to main content

ocpi_tariffs/
warning.rs

1//! These types are the basis for writing functions that can emit a set of [`Warning`]s based on the value they are trying to create.
2//!
3//! The aim is for functions to be as resilient as possible while creating the value and emit commentary on their progress in the form of a growing set of [`Warning`]s.
4//!
5//! The caller of the function can use the set of [`Warning`]s to decide whether the operation was a success or failure and whether the value can be used or needs to be modified.
6//!  
7//! A concrete example is the conversion of a JSON [`json::Element`] into a `country::Code`. The [`json::Element`] may be the incorrect type and so the function issues a [`Warning`] and exits as it cannot continue with the given data. The signature of this fn is something like:
8//!
9//! ```rust ignore
10//! // file: country.rs
11//!  
12//! pub enum Warning {
13//!     InvalidType,
14//!     ...
15//! }
16//!
17//! pub enum Expect {
18//!     Alpha2,
19//!     Alpha3
20//! }
21//!
22//! pub enum Code {
23//!     fn from_json_element(json: json::Element, expect: Expect) -> Verdict<Code, Warning> {
24//!         ...
25//!     }
26//! }
27//! ```
28//!
29//! A [`Verdict`] is a [`Result`] where both the `Ok` and `Err` variants return a potential set of [`Warning`]s.
30//! The `Ok` variant is `Caveat<T>`, where a [`Caveat`] contains a value but potentially contains cautionary details to be taken into account when using the value.
31//! Hence, the name.
32//!
33//! The `Err` variant is `Warnings<W>`, a collection of [`Warning`]s. A [`Warning`] can be converted into an `Error` by the caller. A `Caveat<T>` is more completely described as `Caveat<T, W>` where the `Caveat` contains a value `T` and a set of `Warnings<W>`.
34//!
35//! All of this is to say that a resilient function can always return [`Warning`]s and the caller can gather them
36//! together into a new set or fail.
37//!
38//! Returning to the example of the [`country::Code`](crate::country::Code), if the [`json::Element`] is the expected string type, then processing continues.
39//! The string may contain control chars or escape chars and both these cases will emit a [`Warning`].
40//! The string may be made up of three chars when two were expected.
41//! This is the interesting case, as some [`country::Code`](crate::country::Code) fields are `alpha-3` where others are `alpha-2`.
42//! Processing can still continue, as an `alpha-3` code can be converted to an `alpha-2` simply, while emitting a [`Warning`].
43//!
44//! The caller can decide whether this is acceptable or not.
45
46use std::{borrow::Cow, collections::BTreeMap, fmt, ops::Deref, vec};
47
48use tracing::{debug, info};
49
50use crate::json;
51
52/// Implement `IntoCaveat` for the given type so that it can take part in the `Warning` system.
53#[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/// Implement `IntoCaveat` for all the given types so that it can take part in the `Warning` system.
88#[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            /// Convert from `Warning` A to B
102            impl From<$source_kind> for $target_kind {
103                fn from(warning: $source_kind) -> Self {
104                    $target_kind::$target_variant(warning)
105                }
106            }
107
108            /// Implement a conversion from `warning::Set<A>` to `warning::Set<B>` so that the `Err` variant
109            /// of a `Verdict<_, A>` can be converted using the `?` operator to `Verdict<_, B>`.
110            ///
111            /// `warning::Set::into_other` is used to perform the conversion between set `A` and `B`.
112            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            /// Implement a conversion from `warning::SetDeferred<A>` to `warning::SetDeferred<B>` so that the `Err` variant
119            /// of a `VerdictDeferred<_, A>` can be converted using the `?` operator to `VerdictDeferred<_, B>`.
120            ///
121            /// `warning::SetDeferred::into_other` is used to perform the conversion between set `A` and `B`.
122            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
181/// A `Verdict` is a standard [`Result`] with [`Warning`]s potentially issued for both the `Ok` and `Err` variants.
182pub type Verdict<T, W> = Result<Caveat<T, W>, ErrorSet<W>>;
183
184/// A `VerdictDeferred` is a standard [`Result`] with [`Warning`]s potentially issued for both the `Ok` and `Err` variants.
185///
186/// This verdict is considered deferred as the warnings still need to be associated with a [`json::Element`].
187///
188/// NOTE: The deferred types are used to avoid passing [`json::Element`] references
189/// to functions just to create [`Warning`]s.
190pub(crate) type VerdictDeferred<T, W> = Result<CaveatDeferred<T, W>, ErrorSetDeferred<W>>;
191
192/// A value that may have associated [`Warning`]s.
193///
194/// This caveat is considered deferred as the warning still need to be associated with
195/// a [`json::Element`] to become [`Warning`]s.
196///
197/// Even though the value has been created there may be certain caveats you should be aware of before using it.
198///
199/// NOTE: The deferred types are used to avoid passing [`json::Element`] references
200/// to functions just to create [`Warning`]s.
201#[derive(Debug)]
202pub struct CaveatDeferred<T, W: Warning> {
203    /// The value created by the function.
204    value: T,
205
206    /// A list of [`Warning`]s or caveats issued when creating the value.
207    warnings: SetDeferred<W>,
208}
209
210impl<T, W> CaveatDeferred<T, W>
211where
212    T: IntoCaveatDeferred,
213    W: Warning,
214{
215    /// The only way to create `CaveatDeferred<T>` is if `T` impls `IntoCaveatDeferred`.
216    pub(crate) fn new(value: T, warnings: SetDeferred<W>) -> Self {
217        Self { value, warnings }
218    }
219}
220
221/// A deferred Caveat is simply a value with associated [`Warning`]s that still need to be associated
222/// with a [`json::Element`].
223///
224/// Providing an `impl Deref` makes sense for given that it's an annotated value.
225///
226/// > The same advice applies to both deref traits. In general, deref traits
227/// > **should** be implemented if:
228/// >
229/// > 1. a value of the type transparently behaves like a value of the target
230/// >    type;
231/// > 1. the implementation of the deref function is cheap; and
232/// > 1. users of the type will not be surprised by any deref coercion behavior.
233///
234/// See: <https://doc.rust-lang.org/std/ops/trait.Deref.html#when-to-implement-deref-or-derefmut>
235impl<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    /// Return the value and any [`Warning`]s stored in the `CaveatDeferred`.
251    pub fn into_parts(self) -> (T, SetDeferred<W>) {
252        let Self { value, warnings } = self;
253        (value, warnings)
254    }
255
256    /// Return the value and drop any warnings contained within.
257    pub fn ignore_warnings(self) -> T {
258        self.value
259    }
260
261    /// Map the value to another target type while retaining the warnings about the source type.
262    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/// A value that may have associated [`Warning`]s.
272///
273/// Even though the value has been created there may be certain caveats you should be aware of before using it.
274#[derive(Debug)]
275pub struct Caveat<T, W: Warning> {
276    /// The value created by the function.
277    value: T,
278
279    /// A list of [`Warning`]s or caveats issued when creating the value.
280    warnings: Set<W>,
281}
282
283impl<T, W> Caveat<T, W>
284where
285    T: IntoCaveat,
286    W: Warning,
287{
288    /// The only way to create `Caveat<T>` is if `T` impls `IntoCaveat`.
289    pub(crate) fn new(value: T, warnings: Set<W>) -> Self {
290        Self { value, warnings }
291    }
292}
293
294/// A Caveat is simply a value with associated warnings.
295/// Providing an `impl Deref` makes sense for given that it's an annotated value.
296///
297/// > The same advice applies to both deref traits. In general, deref traits
298/// > **should** be implemented if:
299/// >
300/// > 1. a value of the type transparently behaves like a value of the target
301/// >    type;
302/// > 1. the implementation of the deref function is cheap; and
303/// > 1. users of the type will not be surprised by any deref coercion behavior.
304///
305/// See: <https://doc.rust-lang.org/std/ops/trait.Deref.html#when-to-implement-deref-or-derefmut>
306impl<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    /// Return the value and any [`Warning`]s stored in the `Caveat`.
322    pub fn into_parts(self) -> (T, Set<W>) {
323        let Self { value, warnings } = self;
324        (value, warnings)
325    }
326
327    /// Return the value and drop any warnings contained within.
328    pub fn ignore_warnings(self) -> T {
329        self.value
330    }
331
332    /// Map the value to another target type while retaining the warnings about the source type.
333    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
342/// Convert a `Caveat`-like type into a `T` by gathering up its [`Warning`]s.
343///
344/// Gathering warnings into a parent `warning::Set` move's the responsibility of alerting the
345/// caller to the existence of those warnings to the owner of the set.
346pub(crate) trait GatherWarnings<T, W>
347where
348    W: Warning,
349{
350    /// The output type of after all the warnings have been gathered.
351    type Output;
352
353    /// Convert a `Caveat`-like type into a `T` by gathering up its [`Warning`]s.
354    #[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
361/// Convert a `Caveat<T>` into `T` by gathering up its `Warning`s.
362impl<T, W> GatherWarnings<T, W> for Caveat<T, W>
363where
364    W: Warning,
365{
366    type Output = T;
367
368    /// Convert a `Caveat<T>` into `T` by gathering up its `Warning`s.
369    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
385/// Convert a `Option<Caveat<T>>` into `Option<T>` by gathering up its `Warning`s.
386impl<T, W> GatherWarnings<T, W> for Option<Caveat<T, W>>
387where
388    W: Warning,
389{
390    type Output = Option<T>;
391
392    /// Convert a `Caveat` related to type `T` into a `T` by gathering its [`Warning`]s.
393    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
405/// Convert a `Result<Caveat<T>>` into `Result<T>` by gathering up its `Warning`s.
406impl<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    /// Convert a `Caveat` related to type `T` into a `T` by gathering its [`Warning`]s.
414    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
426/// Convert a `Result<Caveat<T>>` into `Result<T>` by gathering up its `Warning`s.
427impl<T, W> GatherWarnings<T, W> for Verdict<T, W>
428where
429    W: Warning,
430{
431    type Output = Result<T, ErrorSet<W>>;
432
433    /// Convert a `Verdict` into an `Option` by collecting `Warnings` from the `Ok` and `Err` variants
434    /// and mapping `Ok` to `Some` and `Err` to `None`.
435    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
447/// Convert a `Result` that contains an `ErrorSet` into a `T` by gathering up its [`Warning`]s.
448///
449/// Gathering warnings into a parent `warning::Set` move's the responsibility of alerting the
450/// caller to the existence of those warnings to the owner of the set.
451pub(crate) trait DeescalateError<T, W>
452where
453    W: Warning,
454{
455    /// Convert a `Caveat`-like type into a `T` by gathering up its [`Warning`]s.
456    #[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
463/// Convert a `Result<Caveat<T>>` into `Option<T>` by deescalating its [`Error`] and gathering up its [`Warning`]s.
464impl<T, W> DeescalateError<T, W> for Verdict<T, W>
465where
466    W: Warning,
467{
468    /// Convert a `Verdict` into an `Option` by collecting `Warnings` from the `Ok` and `Err` variants
469    /// and mapping `Ok` to `Some` and `Err` to `None`.
470    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
485/// Convert a `Result<T>` into `Option<T>` by deescalating its [`Error`] and gathering up its [`Warning`]s.
486impl<T, W> DeescalateError<T, W> for Result<T, ErrorSet<W>>
487where
488    W: Warning,
489{
490    /// Convert a `Verdict` into an `Option` by collecting `Warnings` from the `Ok` and `Err` variants
491    /// and mapping `Ok` to `Some` and `Err` to `None`.
492    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
507/// Convert a `Vec<Caveat<T>>` into `Vec<T>` by gathering up each elements `Warning`s.
508impl<T, W> GatherWarnings<T, W> for Vec<Caveat<T, W>>
509where
510    W: Warning,
511{
512    type Output = Vec<T>;
513
514    /// Convert a `Caveat` related to type `T` into a `T` by gathering its [`Warning`]s.
515    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
526/// Convert a `Caveat`-like type into a `T` by gathering up its [`Warning`]s.
527///
528/// Gathering [`Warning`]s into a parent `warning::SetDeferred` move's the responsibility of alerting the
529/// caller to the existence of those [`Warning`]s to the owner of the set.
530pub(crate) trait GatherDeferredWarnings<T, W>
531where
532    W: Warning,
533{
534    /// The output type of after all the warnings have been gathered.
535    type Output;
536
537    /// Convert a `Caveat`-like type into a `T` by gathering up its [`Warning`]s.
538    #[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
545/// Convert a `CaveatDeferred<T>` into `T` by gathering up its [`Warning`]s.
546impl<T, W> GatherDeferredWarnings<T, W> for CaveatDeferred<T, W>
547where
548    W: Warning,
549{
550    type Output = T;
551
552    /// Convert a `Caveat<T>` into `T` by gathering up its `Warning`s.
553    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
569/// Convert a `Option<CaveatDeferred<T>>` into `Option<T>` by gathering up its warning `Warning`s.
570impl<T, W> GatherDeferredWarnings<T, W> for Option<CaveatDeferred<T, W>>
571where
572    W: Warning,
573{
574    type Output = Option<T>;
575
576    /// Convert a `Caveat` related to type `T` into a `T` by gathering its [`Warning`]s.
577    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
589/// Convert a `Result<CaveatDeferred<T>>` into `Result<T>` by gathering up its [`Warning`]s.
590impl<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    /// Convert a `Caveat` related to type `T` into a `T` by gathering its [`Warning`]s.
598    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
610/// Convert a `Result<CaveatDeferred<T>>` into `Result<T>` by gathering up its [`Warning`]s.
611impl<T, W> GatherDeferredWarnings<T, W> for VerdictDeferred<T, W>
612where
613    W: Warning,
614{
615    type Output = Result<T, ErrorSetDeferred<W>>;
616
617    /// Convert a `VerdictDeferred` into an `Option` by collecting [`Warning`]s from the `Ok` and `Err` variants
618    /// and mapping `Ok` to `Some` and `Err` to `None`.
619    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
631/// Convert a `Vec<CaveatDeferred<T>>` into `Vec<T>` by gathering up each elements [`Warning`]s.
632impl<T, W> GatherDeferredWarnings<T, W> for Vec<CaveatDeferred<T, W>>
633where
634    W: Warning,
635{
636    type Output = Vec<T>;
637
638    /// Convert a `CaveatDeferred` related to type `T` into a `T` by gathering its [`Warning`]s.
639    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
650/// Converts a value `T` into a `Caveat`.
651///
652/// Each module can use this to whitelist their types for conversion to `Caveat<T>`.
653pub trait IntoCaveat: Sized {
654    /// Any type can be converted to `Caveat<T>` by supplying a list of [`Warning`]s.
655    fn into_caveat<W: Warning>(self, warnings: Set<W>) -> Caveat<Self, W>;
656}
657
658/// Converts a value `T` into a `CaveatDeferred`.
659///
660/// Each module can use this to whitelist their types for conversion to `CaveatDeferred<T>`.
661pub trait IntoCaveatDeferred: Sized {
662    /// Any type can be converted to `CaveatDeferred<T>` by supplying a list of [`Warning`]s.
663    fn into_caveat_deferred<W: Warning>(self, warnings: SetDeferred<W>) -> CaveatDeferred<Self, W>;
664}
665
666// Peel an argument off the list and recurse into `into_caveat_tuple!`
667macro_rules! peel {
668    ($name:ident, $($other:ident,)*) => (into_caveat_tuple! { $($other,)* })
669}
670
671// Implement `IntoCaveat` and `IntoCaveatDeferred` for tuples of size N to 0.
672// Where N is the length of the given type names list.
673macro_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
697// Implement `IntoCaveat` and `IntoCaveatDeferred` for tuples of size N to 0.
698// Where N is the length of the given type names list.
699into_caveat_tuple! { T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
700
701// Implement `IntoCaveat` and `IntoCaveatDeferred` for all the given types.
702into_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
718/// Allow `Cow<'a, str>` to be converted into a `Caveat`.
719impl 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
725/// Allow `Option<T: IntoCaveat>` to be converted into a `Caveat`.
726impl<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
735/// Allow `Vec<T: IntoCaveat>` to be converted into a `Caveat`.
736impl<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
745/// Allow `Vec<T: IntoCaveat>` to be converted into a `CaveatDeferred`.
746impl<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
755/// `Verdict` specific extension methods for the `Result` type.
756pub trait VerdictExt<T, W: Warning> {
757    /// Maps a `Verdict<T, E>` to `Verdict<U, E>` by applying a function to a
758    /// contained [`Ok`] value, leaving an [`Err`] value untouched.
759    fn map_caveat<F, U>(self, op: F) -> Verdict<U, W>
760    where
761        F: FnOnce(T) -> U;
762
763    /// Discard all warnings in the `Err` variant and keep only the warning that caused the error.
764    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/// The warning that caused an operation to fail.
864///
865/// The [`Warning`] is referred to by the [`json::Element`]s path as a `String`.
866#[derive(Debug)]
867pub struct Error<W: Warning> {
868    /// The `Warning` of warning.
869    warning: W,
870
871    /// The path of the element that caused the [`Warning`].
872    element: Element,
873}
874
875impl<W: Warning> Error<W> {
876    /// Return reference to the `Warning`.
877    pub fn warning(&self) -> &W {
878        &self.warning
879    }
880
881    /// Consume the `Error` and return the `Warning`.
882    pub fn into_warning(self) -> W {
883        self.warning
884    }
885
886    /// Return a reference to the [`Element`] that caused the [`Warning`].
887    pub fn element(&self) -> &Element {
888        &self.element
889    }
890
891    /// Return the constituent parts.
892    pub fn parts(&self) -> (&W, &Element) {
893        (&self.warning, &self.element)
894    }
895
896    /// Consume the `Cause` and return the constituent parts.
897    pub fn into_parts(self) -> (W, Element) {
898        let Self { warning, element } = self;
899        (warning, element)
900    }
901
902    /// Converts `Error<W>` into `Error<WA>` using the `impl Into<WA> for W`.
903    ///
904    /// This is used by the [`from_warning_all`] macro.
905    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
930/// Associate a [`json::Element`] with a set of [`Warning`]s contained by a [`VerdictDeferred`].
931pub 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    /// Associate a [`json::Element`] with a set of [`Warning`]s.
937    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/// A representation of a JSON element that satisfies the needs of most consumers of a [`Warning`].
962///
963/// This representation avoids the complexity of needing to provide a `'buf` lifetime to the [`json::Element`].
964/// This would complicate all warnings types with that lifetime.
965///
966/// A consumer of warnings wants to group them by [`json::ElemId`] using `Warning::group_by_elem` and then
967/// display or report the warnings by path.
968///
969/// The linter report also wants to highlight the source JSON that a warning refers too.
970#[derive(Debug)]
971pub struct Element {
972    /// The Id of the element that caused the [`Warning`].
973    ///
974    /// This is used for sorting warnings and can be used to retrieve the [`json::Element`] object.
975    pub id: json::ElemId,
976
977    /// The `Span` that delimits the [`json::Element`].
978    pub span: json::parser::Span,
979
980    /// The elements path.
981    ///
982    /// Most consumers of warnings just want this data.
983    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
996/// A Display object for writing a set of warnings.
997///
998/// The warnings set is formatted as a tree with element paths on the first level
999/// and a list of warning ids on the second.
1000///
1001/// ```shell
1002/// $path.to.json.[0].field:
1003///   - list_of_warning_ids
1004///   - next_warning_id
1005///
1006/// $next.path.to.[1].json.field
1007///   - list_of_warning_ids
1008/// ```
1009pub struct SetWriter<'caller, W: Warning> {
1010    /// The list of warnings for the [`json::Element`].
1011    warnings: &'caller Set<W>,
1012
1013    /// The indent to prefix to each warning id.
1014    indent: &'caller str,
1015}
1016
1017impl<'caller, W: Warning> SetWriter<'caller, W> {
1018    /// Create a new `SetWriter` with a default warning id indent of `"  - "`.
1019    pub fn new(warnings: &'caller Set<W>) -> Self {
1020        Self {
1021            warnings,
1022            indent: "  - ",
1023        }
1024    }
1025
1026    /// Create a new `SetWriter` with a custom warning id indent.
1027    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            // Write the first group without an empty line prefix.
1044            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        // Write the rest of the Groups with am empty line padding.
1056        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
1068/// Each mod defines warnings for the type that it's trying to parse or lint from a [`json::Element`].
1069///
1070/// The `Warning` in the mod should impl this trait to take part in the [`Warning`] system.
1071pub trait Warning: Sized + fmt::Debug + fmt::Display + Send + Sync {
1072    /// Return the human readable identifier for the [`Warning`].
1073    ///
1074    /// This is used in the `auto_test` assertion system.
1075    /// Changing these strings may require updating `output_price__cdr.json` files.
1076    fn id(&self) -> Id;
1077}
1078
1079/// A set of [`Warning`]s transported through the system using a `VerdictDeferred` or `CaveatDeferred`.
1080///
1081///
1082/// This set is considered deferred as the [`Warning`]s need to be associated with a [`json::Element`]
1083/// to become [`Warning`]s.
1084///
1085/// NOTE: The deferred types are used to avoid passing [`json::Element`] references
1086/// to functions just to create [`Warning`]s.
1087#[derive(Debug)]
1088pub struct SetDeferred<W: Warning>(BTreeMap<json::ElemId, Group<W>>);
1089
1090impl<W: Warning> SetDeferred<W> {
1091    /// Create a new list of [`Warning`]s
1092    pub(crate) fn new() -> Self {
1093        Self(BTreeMap::new())
1094    }
1095
1096    /// Create and add a [`Warning`] to the set while consuming the set into a [`VerdictDeferred`].
1097    ///
1098    /// This is designed for use as the last [`Warning`] of a function. The function should exit with the `Err` returned.
1099    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    /// Return true if the [`Warning`] set is empty.
1108    pub fn is_empty(&self) -> bool {
1109        self.0.is_empty()
1110    }
1111
1112    /// Extend this set with the warnings of another.
1113    ///
1114    /// The other set's warnings will be converted if necessary.
1115    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/// A set of [`Warning`]s and a [`Warning`] that caused an operation to fail represented as an [`Error`].
1126///
1127/// This set is transported through the system using a [`VerdictDeferred`]s `Err` variant.
1128///
1129/// This set is considered deferred as the [`Warning`]s need to be associated with a [`json::Element`]
1130/// to become [`Warning`]s.
1131///
1132/// NOTE: The deferred types are used to avoid passing [`json::Element`] references
1133/// to functions just to create [`Warning`]s.
1134#[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    /// Create a new list of [`Warning`]s
1142    pub(crate) fn with_warn(warning: W) -> Self {
1143        Self {
1144            warnings: BTreeMap::new(),
1145            error: warning,
1146        }
1147    }
1148
1149    /// Converts `ErrorSetDeferred<W>` into `ErrorSetDeferred<WA>` using the `impl Into<WA> for W`.
1150    ///
1151    /// This is used by the [`from_warning_all`] macro.
1152    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/// A set of [`Warning`]s transported through the system using a [`Caveat`].
1170#[derive(Debug)]
1171pub struct Set<W: Warning>(BTreeMap<json::ElemId, Group<W>>);
1172
1173impl<W: Warning> Set<W> {
1174    /// Create a new list of [`Warning`]s
1175    pub(crate) fn new() -> Self {
1176        Self(BTreeMap::new())
1177    }
1178
1179    /// Insert a [`Warning`] defined in a domain module and it's associated [`json::Element`].
1180    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    /// Insert [`Warning`] defined in a domain module and it's associated [`Element`].
1185    ///
1186    /// Note: The [`Element`] is created lazily.
1187    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    /// Consume the set and insert a [`Warning`] while returning a [`Verdict`].
1208    ///
1209    /// This is designed for use as the last [`Warning`] of a function. The function should exit with the `Err` returned.
1210    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    /// Converts `Set<W>` into `Set<WA>` using the `impl Into<WA> for W`.
1223    ///
1224    /// This is used by the [`from_warning_all`] macro.
1225    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    /// Return true if the [`Warning`] set is empty.
1239    pub fn is_empty(&self) -> bool {
1240        self.0.is_empty()
1241    }
1242
1243    /// Return the amount of [`Element`]s in this set.
1244    ///
1245    /// Each [`Element`] can have many [`Warning`]s associated with it.
1246    pub fn len_elements(&self) -> usize {
1247        self.0.len()
1248    }
1249
1250    /// Return the total amount of [`Warning`]s in this set for all [`Element`]s.
1251    pub fn len_warnings(&self) -> usize {
1252        self.0
1253            .values()
1254            .fold(0, |acc, group| acc + group.warnings.len())
1255    }
1256
1257    /// Return an iterator of [`Warning`]s grouped by [`json::Element`].
1258    pub fn iter(&self) -> Iter<'_, W> {
1259        Iter {
1260            warnings: self.0.iter(),
1261        }
1262    }
1263
1264    /// Return a map of [`json::Element`] paths to a list of [`Warning`].
1265    ///
1266    /// This is designed to be used to print out maps of warnings associated with elements.
1267    /// You can use the debug alternate format `{:#?}` to print the map 'pretty' over multiple lines
1268    /// with indentation.
1269    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    /// Consume the `Set` and return a map of [`json::Element`] paths to a list of [`Warning`]s.
1277    ///
1278    /// This is designed to be used to print out maps of warnings associated with elements.
1279    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    /// Return a map of [`json::Element`] paths to a list of [`Warning`] ids as Strings.
1287    ///
1288    /// This is designed to be used to print out maps of warnings associated with elements.
1289    /// You can use the debug alternate format `{:#?}` to print the map 'pretty' over multiple lines
1290    /// with indentation.
1291    ///
1292    /// Note: This representation is also valid JSON and can be copied directly to
1293    /// a test expectation file.
1294    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    /// Return a map of [`json::Element`] paths to a list of [`Warning`] messages as Strings.
1305    ///
1306    /// This is designed to be used to print out maps of warnings associated with elements.
1307    /// You can use the debug alternate format `{:#?}` to print the map 'pretty' over multiple lines
1308    /// with indentation.
1309    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    /// Deescalate an [`Error`] by subsuming it back into a `Set`.
1320    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    /// Extend this set with the warnings of another.
1328    ///
1329    /// The other set's warnings will be converted if necessary.
1330    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/// A set of [`Warning`]s and a [`Warning`] that caused an operation to fail represented as an [`Error`].
1359///
1360/// This set is transported through the system using a [`Verdict`]s `Err` variant.
1361#[derive(Debug)]
1362pub struct ErrorSet<W: Warning> {
1363    /// The warning that caused an operation to fail.
1364    ///
1365    /// The warning is converted to an [`Error`] so it's ready to take part in Rust's error system.
1366    error: Box<Error<W>>,
1367
1368    /// The warnings accumulated up until the failure moment.
1369    ///
1370    /// This list does not included the warning that caused the operation to fail.
1371    warnings: BTreeMap<json::ElemId, Group<W>>,
1372}
1373
1374impl<W> ErrorSet<W>
1375where
1376    W: Warning,
1377{
1378    /// Consume the [`ErrorSet`] and return the [`Error`] and warnings as a `Set`.
1379    pub fn into_parts(self) -> (Error<W>, Set<W>) {
1380        let Self { error, warnings } = self;
1381        (*error, Set(warnings))
1382    }
1383
1384    /// Converts `ErrorSet<W>` into `ErrorSet<WA>` using the `impl Into<WA> for K`.
1385    ///
1386    /// This is used by the [`from_warning_all`] macro.
1387    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/// A group of warning `Warning`s associated with an `Element`.
1405///
1406/// This group is emitted from the `IntoGroupByElem` iterator.
1407/// The warning `Warning`s are owned and so can be moved to another location.
1408#[derive(Debug)]
1409pub struct Group<W> {
1410    /// The [`json::Element`] that has [`Warning`]s.
1411    pub element: Element,
1412
1413    /// The list of warnings for the [`json::Element`].
1414    pub warnings: Vec<W>,
1415}
1416
1417impl<W> Group<W>
1418where
1419    W: Warning,
1420{
1421    /// Converts `IntoGroup<W>` into `IntoGroup<WA>` using the `impl Into<WA> for K`.
1422    ///
1423    /// This is used by the [`from_warning_all`] macro.
1424    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
1435/// An iterator of borrowed [`Warning`]s grouped by [`json::Element`].
1436pub struct Iter<'caller, W>
1437where
1438    W: Warning,
1439{
1440    /// The iterator over every [`Warning`].
1441    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
1455/// An iterator of borrowed [`Warning`]s grouped by [`json::Element`].
1456pub struct IntoIter<W>
1457where
1458    W: Warning,
1459{
1460    /// The iterator over every [`Warning`].
1461    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    /// `Verdict` specific extension methods for the `Result` type.
1506    pub trait VerdictTestExt<T, W: Warning> {
1507        /// Discard all warnings in the `ErrorSet` variant and keep only the warning that caused the error.
1508        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        /// Return the value and assert there are no [`Warning`]s.
1531        ///
1532        /// # Panics
1533        ///
1534        /// Asserts that the warning is empty.
1535        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        /// Return the value and assert there are no [`Warning`]s.
1547        ///
1548        /// # Panics
1549        ///
1550        /// Asserts that the warning is empty.
1551        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        /// Convert the Group into String versions of its parts.
1563        ///
1564        /// The first tuple field is the [`json::Element`] path as a String.
1565        /// The second tuple field is a list of [`Warning`] ids.
1566        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        /// Consume the `Set` and return a map of [`json::Element`] paths to a list of [`Warning`]s.
1580        ///
1581        /// This is designed to be used to print out maps of warnings associated with elements.
1582        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    /// Assert that the warnings given are expected.
1591    ///
1592    /// Panic with print out of the warnings and the expectations if any warnings were unexpected.
1593    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            // Assert that the `expect` file doesn't have extraneous entries.
1611            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        // The elements that have warnings but have no entry for the elements path in the `expect` file.
1631        let mut elems_missing_from_expect = vec![];
1632        // The element that have warnings and an entry in the `expect` file, but the list of expected warnings
1633        // is not equal to the list of actual warnings.
1634        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            // Make two sets of actual and expected warnings.
1643            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        // Push warnings into the set out of order.
1733        // They should be sorted by `ElemId`.
1734        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            // [`json::Element`] 2 has no [`Warning`]s so we expect [`json::Element`] 3 next
1783            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        // Push warnings into the set out of order.
1797        // They should be sorted by `ElemId`.
1798        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            // [`json::Element`] 2 has no [`Warning`]s so we expect [`json::Element`] 3 next
1843            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}