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
46#[cfg(test)]
47pub(crate) mod test;
48
49#[cfg(test)]
50mod test_group_by_elem;
51
52use std::{borrow::Cow, collections::BTreeMap, fmt, ops::Deref, vec};
53
54use tracing::{debug, info};
55
56use crate::json;
57
58#[doc(hidden)]
59#[macro_export]
60macro_rules! from_warning_all {
61    ($($source_kind:path => $target_kind:ident::$target_variant:ident),+) => {
62        $(
63            /// Convert from `Warning` A to B
64            impl From<$source_kind> for $target_kind {
65                fn from(warning: $source_kind) -> Self {
66                    $target_kind::$target_variant(warning)
67                }
68            }
69
70            /// Implement a conversion from `warning::Set<A>` to `warning::Set<B>` so that the `Err` variant
71            /// of a `Verdict<_, A>` can be converted using the `?` operator to `Verdict<_, B>`.
72            ///
73            /// `warning::Set::into_other` is used to perform the conversion between set `A` and `B`.
74            impl From<$crate::warning::ErrorSet<$source_kind>> for $crate::warning::ErrorSet<$target_kind> {
75                fn from(set_a: $crate::warning::ErrorSet<$source_kind>) -> Self {
76                    set_a.into_other()
77                }
78            }
79
80            /// Implement a conversion from `warning::SetDeferred<A>` to `warning::SetDeferred<B>` so that the `Err` variant
81            /// of a `VerdictDeferred<_, A>` can be converted using the `?` operator to `VerdictDeferred<_, B>`.
82            ///
83            /// `warning::SetDeferred::into_other` is used to perform the conversion between set `A` and `B`.
84            impl From<$crate::warning::ErrorSetDeferred<$source_kind>> for $crate::warning::ErrorSetDeferred<$target_kind> {
85                fn from(set_a: $crate::warning::ErrorSetDeferred<$source_kind>) -> Self {
86                    set_a.into_other()
87                }
88            }
89        )+
90    };
91}
92
93#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)]
94pub struct Id(Cow<'static, str>);
95
96impl Id {
97    pub(crate) fn from_static(s: &'static str) -> Self {
98        Self(s.into())
99    }
100
101    pub(crate) fn from_string(s: String) -> Self {
102        Self(s.into())
103    }
104
105    pub fn as_str(&self) -> &str {
106        &self.0
107    }
108}
109
110impl fmt::Debug for Id {
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        fmt::Debug::fmt(&self.0, f)
113    }
114}
115
116impl fmt::Display for Id {
117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118        fmt::Display::fmt(&self.0, f)
119    }
120}
121
122#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)]
123pub struct Path(String);
124
125impl Path {
126    pub fn as_str(&self) -> &str {
127        &self.0
128    }
129}
130
131impl fmt::Debug for Path {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        f.write_str(&self.0)
134    }
135}
136
137impl fmt::Display for Path {
138    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139        fmt::Display::fmt(&self.0, f)
140    }
141}
142
143/// A `Verdict` is a standard [`Result`] with [`Warning`]s potentially issued for both the `Ok` and `Err` variants.
144pub type Verdict<T, W> = Result<Caveat<T, W>, ErrorSet<W>>;
145
146/// A `VerdictDeferred` is a standard [`Result`] with [`Warning`]s potentially issued for both the `Ok` and `Err` variants.
147///
148/// This verdict is considered deferred as the warnings still need to be associated with a [`json::Element`].
149///
150/// NOTE: The deferred types are used to avoid passing [`json::Element`] references
151/// to functions just to create [`Warning`]s.
152pub(crate) type VerdictDeferred<T, W> = Result<CaveatDeferred<T, W>, ErrorSetDeferred<W>>;
153
154/// A value that may have associated [`Warning`]s.
155///
156/// This caveat is considered deferred as the warning still need to be associated with
157/// a [`json::Element`] to become [`Warning`]s.
158///
159/// Even though the value has been created there may be certain caveats you should be aware of before using it.
160///
161/// NOTE: The deferred types are used to avoid passing [`json::Element`] references
162/// to functions just to create [`Warning`]s.
163#[derive(Debug)]
164pub(crate) struct CaveatDeferred<T, W: Warning> {
165    /// The value created by the function.
166    value: T,
167
168    /// A list of [`Warning`]s or caveats issued when creating the value.
169    warnings: SetDeferred<W>,
170}
171
172impl<T, W> CaveatDeferred<T, W>
173where
174    W: Warning,
175{
176    /// The only way to create `CaveatDeferred<T>` is if `T` impls `IntoCaveatDeferred`.
177    pub(crate) fn new(value: T, warnings: SetDeferred<W>) -> Self {
178        Self { value, warnings }
179    }
180}
181
182/// A deferred Caveat is simply a value with associated [`Warning`]s that still need to be associated
183/// with a [`json::Element`].
184///
185/// Providing an `impl Deref` makes sense for given that it's an annotated value.
186///
187/// > The same advice applies to both `deref` traits. In general, `deref` traits
188/// > **should** be implemented if:
189/// >
190/// > 1. a value of the type transparently behaves like a value of the target
191/// >    type;
192/// > 1. the implementation of the `deref` function is cheap; and
193/// > 1. users of the type will not be surprised by any `deref` coercion behavior.
194///
195/// See: <https://doc.rust-lang.org/std/ops/trait.Deref.html#when-to-implement-deref-or-derefmut>
196impl<T, W> Deref for CaveatDeferred<T, W>
197where
198    W: Warning,
199{
200    type Target = T;
201
202    fn deref(&self) -> &T {
203        &self.value
204    }
205}
206
207impl<T, W> CaveatDeferred<T, W>
208where
209    W: Warning,
210{
211    /// Return the value and any [`Warning`]s stored in the `CaveatDeferred`.
212    pub fn into_parts(self) -> (T, SetDeferred<W>) {
213        let Self { value, warnings } = self;
214        (value, warnings)
215    }
216}
217
218/// A value that may have associated [`Warning`]s.
219///
220/// Even though the value has been created there may be certain caveats you should be aware of before using it.
221#[derive(Debug)]
222pub struct Caveat<T, W: Warning> {
223    /// The value created by the function.
224    value: T,
225
226    /// A list of [`Warning`]s or caveats issued when creating the value.
227    warnings: Set<W>,
228}
229
230impl<T, W> Caveat<T, W>
231where
232    W: Warning,
233{
234    /// The only way to create `Caveat<T>` is if `T` impls `IntoCaveat`.
235    pub(crate) fn new(value: T, warnings: Set<W>) -> Self {
236        Self { value, warnings }
237    }
238}
239
240/// A Caveat is simply a value with associated warnings.
241/// Providing an `impl Deref` makes sense for given that it's an annotated value.
242///
243/// > The same advice applies to both `deref` traits. In general, `deref` traits
244/// > **should** be implemented if:
245/// >
246/// > 1. a value of the type transparently behaves like a value of the target
247/// >    type;
248/// > 1. the implementation of the `deref` function is cheap; and
249/// > 1. users of the type will not be surprised by any `deref` coercion behavior.
250///
251/// See: <https://doc.rust-lang.org/std/ops/trait.Deref.html#when-to-implement-deref-or-derefmut>
252impl<T, W> Deref for Caveat<T, W>
253where
254    W: Warning,
255{
256    type Target = T;
257
258    fn deref(&self) -> &T {
259        &self.value
260    }
261}
262
263impl<T, W> Caveat<T, W>
264where
265    W: Warning,
266{
267    /// Return the value and any [`Warning`]s stored in the `Caveat`.
268    pub fn into_parts(self) -> (T, Set<W>) {
269        let Self { value, warnings } = self;
270        (value, warnings)
271    }
272
273    /// Return the value and drop any warnings contained within.
274    pub fn ignore_warnings(self) -> T {
275        self.value
276    }
277
278    /// Map the value to another target type while retaining the warnings about the source type.
279    pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Caveat<U, W> {
280        let Self { value, warnings } = self;
281        Caveat {
282            value: op(value),
283            warnings,
284        }
285    }
286}
287
288/// Convert a `Caveat`-like type into a `T` by gathering up its [`Warning`]s.
289///
290/// Gathering warnings into a parent `warning::Set` move's the responsibility of alerting the
291/// caller to the existence of those warnings to the owner of the set.
292pub(crate) trait GatherWarnings<T, W>
293where
294    W: Warning,
295{
296    /// The output type of after all the warnings have been gathered.
297    type Output;
298
299    /// Convert a `Caveat`-like type into a `T` by gathering up its [`Warning`]s.
300    #[must_use = "If you want to ignore the value use `let _ =`"]
301    fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
302    where
303        W: Into<WA>,
304        WA: Warning;
305}
306
307/// Convert a `Caveat<T>` into `T` by gathering up its `Warning`s.
308impl<T, W> GatherWarnings<T, W> for Caveat<T, W>
309where
310    W: Warning,
311{
312    type Output = T;
313
314    /// Convert a `Caveat<T>` into `T` by gathering up its `Warning`s.
315    fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
316    where
317        W: Into<WA>,
318        WA: Warning,
319    {
320        let Self {
321            value,
322            warnings: inner_warnings,
323        } = self;
324
325        let Set(inner_warnings) = inner_warnings;
326        let inner_warnings = inner_warnings
327            .into_iter()
328            .map(|(elem_id, group)| (elem_id, group.into_other()));
329
330        warnings.extend(inner_warnings);
331
332        value
333    }
334}
335
336/// Convert a `Option<Caveat<T>>` into `Option<T>` by gathering up its `Warning`s.
337impl<T, W> GatherWarnings<T, W> for Option<Caveat<T, W>>
338where
339    W: Warning,
340{
341    type Output = Option<T>;
342
343    /// Convert a `Caveat` related to type `T` into a `T` by gathering its [`Warning`]s.
344    fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
345    where
346        W: Into<WA>,
347        WA: Warning,
348    {
349        match self {
350            Some(cv) => Some(cv.gather_warnings_into(warnings)),
351            None => None,
352        }
353    }
354}
355
356/// Convert a `Result<Caveat<T>>` into `Result<T>` by gathering up its `Warning`s.
357impl<T, W, E> GatherWarnings<T, W> for Result<Caveat<T, W>, E>
358where
359    W: Warning,
360    E: std::error::Error,
361{
362    type Output = Result<T, E>;
363
364    /// Convert a `Caveat` related to type `T` into a `T` by gathering its [`Warning`]s.
365    fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
366    where
367        W: Into<WA>,
368        WA: Warning,
369    {
370        match self {
371            Ok(cv) => Ok(cv.gather_warnings_into(warnings)),
372            Err(err) => Err(err),
373        }
374    }
375}
376
377/// Convert a `Result<Caveat<T>>` into `Result<T>` by gathering up its `Warning`s.
378impl<T, W> GatherWarnings<T, W> for Verdict<T, W>
379where
380    W: Warning,
381{
382    type Output = Result<T, ErrorSet<W>>;
383
384    /// Convert a `Verdict` into an `Option` by collecting `Warnings` from the `Ok` and `Err` variants
385    /// and mapping `Ok` to `Some` and `Err` to `None`.
386    fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
387    where
388        W: Into<WA>,
389        WA: Warning,
390    {
391        match self {
392            Ok(cv) => Ok(cv.gather_warnings_into(warnings)),
393            Err(err_set) => Err(err_set),
394        }
395    }
396}
397
398/// Convert a `Result` that contains an `ErrorSet` into a `T` by gathering up its [`Warning`]s.
399///
400/// Gathering warnings into a parent `warning::Set` move's the responsibility of alerting the
401/// caller to the existence of those warnings to the owner of the set.
402pub(crate) trait DeescalateError<T, W>
403where
404    W: Warning,
405{
406    /// Convert a `Caveat`-like type into a `T` by gathering up its [`Warning`]s.
407    #[must_use = "If you want to ignore the value use `let _ =`"]
408    fn deescalate_error_into<WA>(self, warnings: &mut Set<WA>) -> Option<T>
409    where
410        W: Into<WA>,
411        WA: Warning;
412}
413
414/// Convert a `Result<Caveat<T>>` into `Option<T>` by deescalating its [`Error`] and gathering up its [`Warning`]s.
415impl<T, W> DeescalateError<T, W> for Verdict<T, W>
416where
417    W: Warning,
418{
419    /// Convert a `Verdict` into an `Option` by collecting `Warnings` from the `Ok` and `Err` variants
420    /// and mapping `Ok` to `Some` and `Err` to `None`.
421    fn deescalate_error_into<WA>(self, warnings: &mut Set<WA>) -> Option<T>
422    where
423        W: Into<WA>,
424        WA: Warning,
425    {
426        match self {
427            Ok(cv) => Some(cv.gather_warnings_into(warnings)),
428            Err(err_set) => {
429                warnings.deescalate_error(err_set.into_other());
430                None
431            }
432        }
433    }
434}
435
436/// Convert a `Result<T>` into `Option<T>` by deescalating its [`Error`] and gathering up its [`Warning`]s.
437impl<T, W> DeescalateError<T, W> for Result<T, ErrorSet<W>>
438where
439    W: Warning,
440{
441    /// Convert a `Verdict` into an `Option` by collecting `Warnings` from the `Ok` and `Err` variants
442    /// and mapping `Ok` to `Some` and `Err` to `None`.
443    fn deescalate_error_into<WA>(self, warnings: &mut Set<WA>) -> Option<T>
444    where
445        W: Into<WA>,
446        WA: Warning,
447    {
448        match self {
449            Ok(cv) => Some(cv),
450            Err(err_set) => {
451                warnings.deescalate_error(err_set.into_other());
452                None
453            }
454        }
455    }
456}
457
458/// Convert a `Vec<Caveat<T>>` into `Vec<T>` by gathering up each elements `Warning`s.
459impl<T, W> GatherWarnings<T, W> for Vec<Caveat<T, W>>
460where
461    W: Warning,
462{
463    type Output = Vec<T>;
464
465    /// Convert a `Caveat` related to type `T` into a `T` by gathering its [`Warning`]s.
466    fn gather_warnings_into<WA>(self, warnings: &mut Set<WA>) -> Self::Output
467    where
468        W: Into<WA>,
469        WA: Warning,
470    {
471        self.into_iter()
472            .map(|cv| cv.gather_warnings_into(warnings))
473            .collect()
474    }
475}
476
477/// Convert a `Caveat`-like type into a `T` by gathering up its [`Warning`]s.
478///
479/// Gathering [`Warning`]s into a parent `warning::SetDeferred` move's the responsibility of alerting the
480/// caller to the existence of those [`Warning`]s to the owner of the set.
481pub(crate) trait GatherDeferredWarnings<T, W>
482where
483    W: Warning,
484{
485    /// The output type of after all the warnings have been gathered.
486    type Output;
487
488    /// Convert a `Caveat`-like type into a `T` by gathering up its [`Warning`]s.
489    #[must_use = "If you want to ignore the value use `let _ =`"]
490    fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
491    where
492        W: Into<WA>,
493        WA: Warning;
494}
495
496/// Convert a `CaveatDeferred<T>` into `T` by gathering up its [`Warning`]s.
497impl<T, W> GatherDeferredWarnings<T, W> for CaveatDeferred<T, W>
498where
499    W: Warning,
500{
501    type Output = T;
502
503    /// Convert a `Caveat<T>` into `T` by gathering up its `Warning`s.
504    fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
505    where
506        W: Into<WA>,
507        WA: Warning,
508    {
509        let Self {
510            value,
511            warnings: inner_warnings,
512        } = self;
513
514        warnings.extend(inner_warnings);
515
516        value
517    }
518}
519
520/// Convert a `Option<CaveatDeferred<T>>` into `Option<T>` by gathering up its warning `Warning`s.
521impl<T, W> GatherDeferredWarnings<T, W> for Option<CaveatDeferred<T, W>>
522where
523    W: Warning,
524{
525    type Output = Option<T>;
526
527    /// Convert a `Caveat` related to type `T` into a `T` by gathering its [`Warning`]s.
528    fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
529    where
530        W: Into<WA>,
531        WA: Warning,
532    {
533        match self {
534            Some(cv) => Some(cv.gather_deferred_warnings_into(warnings)),
535            None => None,
536        }
537    }
538}
539
540/// Convert a `Result<CaveatDeferred<T>>` into `Result<T>` by gathering up its [`Warning`]s.
541impl<T, W, E> GatherDeferredWarnings<T, W> for Result<CaveatDeferred<T, W>, E>
542where
543    W: Warning,
544    E: std::error::Error,
545{
546    type Output = Result<T, E>;
547
548    /// Convert a `Caveat` related to type `T` into a `T` by gathering its [`Warning`]s.
549    fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
550    where
551        W: Into<WA>,
552        WA: Warning,
553    {
554        match self {
555            Ok(cv) => Ok(cv.gather_deferred_warnings_into(warnings)),
556            Err(err) => Err(err),
557        }
558    }
559}
560
561/// Convert a `Result<CaveatDeferred<T>>` into `Result<T>` by gathering up its [`Warning`]s.
562impl<T, W> GatherDeferredWarnings<T, W> for VerdictDeferred<T, W>
563where
564    W: Warning,
565{
566    type Output = Result<T, ErrorSetDeferred<W>>;
567
568    /// Convert a `VerdictDeferred` into an `Option` by collecting [`Warning`]s from the `Ok` and `Err` variants
569    /// and mapping `Ok` to `Some` and `Err` to `None`.
570    fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
571    where
572        W: Into<WA>,
573        WA: Warning,
574    {
575        match self {
576            Ok(cv) => Ok(cv.gather_deferred_warnings_into(warnings)),
577            Err(err_set) => Err(err_set),
578        }
579    }
580}
581
582/// Convert a `Vec<CaveatDeferred<T>>` into `Vec<T>` by gathering up each elements [`Warning`]s.
583impl<T, W> GatherDeferredWarnings<T, W> for Vec<CaveatDeferred<T, W>>
584where
585    W: Warning,
586{
587    type Output = Vec<T>;
588
589    /// Convert a `CaveatDeferred` related to type `T` into a `T` by gathering its [`Warning`]s.
590    fn gather_deferred_warnings_into<WA>(self, warnings: &mut SetDeferred<WA>) -> Self::Output
591    where
592        W: Into<WA>,
593        WA: Warning,
594    {
595        self.into_iter()
596            .map(|cv| cv.gather_deferred_warnings_into(warnings))
597            .collect()
598    }
599}
600
601/// Converts a value `T` into a `Caveat`.
602///
603/// Each module can use this to whitelist their types for conversion to `Caveat<T>`.
604pub trait IntoCaveat: Sized {
605    /// Any type can be converted to `Caveat<T>` by supplying a list of [`Warning`]s.
606    fn into_caveat<W: Warning>(self, warnings: Set<W>) -> Caveat<Self, W>;
607}
608
609/// Converts a value `T` into a `CaveatDeferred`.
610///
611/// Each module can use this to whitelist their types for conversion to `CaveatDeferred<T>`.
612pub(crate) trait IntoCaveatDeferred: Sized {
613    /// Any type can be converted to `CaveatDeferred<T>` by supplying a list of [`Warning`]s.
614    fn into_caveat_deferred<W: Warning>(self, warnings: SetDeferred<W>) -> CaveatDeferred<Self, W>;
615}
616
617/// Allow all types to be converted into `Caveat<T>`.
618impl<T> IntoCaveat for T {
619    fn into_caveat<W: Warning>(self, warnings: Set<W>) -> Caveat<Self, W> {
620        Caveat::new(self, warnings)
621    }
622}
623
624/// Allow `Vec<T: IntoCaveat>` to be converted into a `CaveatDeferred`.
625impl<T> IntoCaveatDeferred for T {
626    fn into_caveat_deferred<W: Warning>(self, warnings: SetDeferred<W>) -> CaveatDeferred<Self, W> {
627        CaveatDeferred::new(self, warnings)
628    }
629}
630
631/// `Verdict` specific extension methods for the `Result` type.
632pub trait VerdictExt<T, W: Warning> {
633    /// Maps a `Verdict<T, E>` to `Verdict<U, E>` by applying a function to a
634    /// contained [`Ok`] value, leaving an [`Err`] value untouched.
635    fn map_caveat<F, U>(self, op: F) -> Verdict<U, W>
636    where
637        F: FnOnce(T) -> U;
638
639    /// Discard all warnings in the `Err` variant and keep only the warning that caused the error.
640    fn only_error(self) -> Result<Caveat<T, W>, Error<W>>;
641}
642
643#[allow(dead_code, reason = "for debugging")]
644pub(crate) trait VerdictTrace<T, W: Warning> {
645    fn info_verdict(self, msg: &'static str) -> Self;
646    fn debug_verdict(self, msg: &'static str) -> Self;
647}
648
649#[allow(dead_code, reason = "for debugging")]
650pub(crate) trait ResultTrace<T, W: Warning> {
651    fn info_result(self, msg: &'static str) -> Self;
652    fn debug_result(self, msg: &'static str) -> Self;
653}
654
655impl<T, W: Warning> VerdictExt<T, W> for Verdict<T, W> {
656    fn map_caveat<F, U>(self, op: F) -> Verdict<U, W>
657    where
658        F: FnOnce(T) -> U,
659    {
660        match self {
661            Ok(c) => Ok(c.map(op)),
662            Err(w) => Err(w),
663        }
664    }
665
666    fn only_error(self) -> Result<Caveat<T, W>, Error<W>> {
667        match self {
668            Ok(c) => Ok(c),
669            Err(err_set) => {
670                let ErrorSet { error, warnings: _ } = err_set;
671                Err(*error)
672            }
673        }
674    }
675}
676
677impl<T, W: Warning> VerdictTrace<T, W> for Verdict<T, W>
678where
679    T: fmt::Debug,
680{
681    fn info_verdict(self, msg: &'static str) -> Self {
682        match self {
683            Ok(c) => {
684                info!("{msg}: {c:#?}");
685                Ok(c)
686            }
687            Err(err_set) => {
688                info!("{msg}: {err_set:#?}");
689                Err(err_set)
690            }
691        }
692    }
693
694    fn debug_verdict(self, msg: &'static str) -> Self {
695        match self {
696            Ok(c) => {
697                debug!("{msg}: {c:#?}");
698                Ok(c)
699            }
700            Err(err_set) => {
701                debug!("{msg}: {err_set:#?}");
702                Err(err_set)
703            }
704        }
705    }
706}
707
708impl<T, W: Warning> ResultTrace<T, W> for Result<T, ErrorSet<W>>
709where
710    T: fmt::Debug,
711{
712    fn info_result(self, msg: &'static str) -> Self {
713        match self {
714            Ok(c) => {
715                info!("{msg}: {c:#?}");
716                Ok(c)
717            }
718            Err(err_set) => {
719                info!("{msg}: {err_set:#?}");
720                Err(err_set)
721            }
722        }
723    }
724
725    fn debug_result(self, msg: &'static str) -> Self {
726        match self {
727            Ok(c) => {
728                debug!("{msg}: {c:#?}");
729                Ok(c)
730            }
731            Err(err_set) => {
732                debug!("{msg}: {err_set:#?}");
733                Err(err_set)
734            }
735        }
736    }
737}
738
739/// The warning that caused an operation to fail.
740///
741/// The [`Warning`] is referred to by the [`json::Element`]s path as a `String`.
742#[derive(Debug)]
743pub struct Error<W: Warning> {
744    /// The `Warning` of warning.
745    warning: W,
746
747    /// The path of the element that caused the [`Warning`].
748    element: Element,
749}
750
751impl<W: Warning> Error<W> {
752    /// Return reference to the `Warning`.
753    pub fn warning(&self) -> &W {
754        &self.warning
755    }
756
757    /// Consume the `Error` and return the `Warning`.
758    pub fn into_warning(self) -> W {
759        self.warning
760    }
761
762    /// Return a reference to the [`Element`] that caused the [`Warning`].
763    pub fn element(&self) -> &Element {
764        &self.element
765    }
766
767    /// Return the constituent parts.
768    pub fn parts(&self) -> (&W, &Element) {
769        (&self.warning, &self.element)
770    }
771
772    /// Consume the `Cause` and return the constituent parts.
773    pub fn into_parts(self) -> (W, Element) {
774        let Self { warning, element } = self;
775        (warning, element)
776    }
777
778    /// Converts `Error<W>` into `Error<WA>` using the `impl Into<WA> for W`.
779    ///
780    /// This is used by the [`from_warning_all`] macro.
781    fn into_other<WA>(self) -> Error<WA>
782    where
783        W: Into<WA>,
784        WA: Warning,
785    {
786        let Self { warning, element } = self;
787        Error {
788            warning: warning.into(),
789            element,
790        }
791    }
792}
793
794impl<W: Warning> std::error::Error for Error<W> {}
795
796impl<W: Warning> fmt::Display for Error<W> {
797    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
798        write!(
799            f,
800            "A warning for element at `{}` was upgraded to an `error`: {}",
801            self.element.path, self.warning
802        )
803    }
804}
805
806/// Associate a [`json::Element`] with a set of [`Warning`]s contained by a [`VerdictDeferred`].
807pub trait WithElement<T, W: Warning> {
808    fn with_element(self, element: &json::Element<'_>) -> Verdict<T, W>;
809}
810
811impl<T, W: Warning> WithElement<T, W> for VerdictDeferred<T, W> {
812    /// Associate a [`json::Element`] with a set of [`Warning`]s.
813    fn with_element(self, element: &json::Element<'_>) -> Verdict<T, W> {
814        match self {
815            Ok(v) => {
816                let CaveatDeferred { value, warnings } = v;
817                let SetDeferred(warnings) = warnings;
818                let warnings = if warnings.is_empty() {
819                    BTreeMap::new()
820                } else {
821                    let warnings = Group {
822                        element: element.into(),
823                        warnings,
824                    };
825                    BTreeMap::from([(element.id(), warnings)])
826                };
827
828                Ok(Caveat {
829                    value,
830                    warnings: Set(warnings),
831                })
832            }
833            Err(set) => {
834                let ErrorSetDeferred { error, warnings } = set;
835                // An `ErrorSetDeferred` should have at least one warning in it.
836                let warnings = Group {
837                    element: element.into(),
838                    warnings,
839                };
840                let warnings = BTreeMap::from([(element.id(), warnings)]);
841                Err(ErrorSet {
842                    error: Box::new(Error {
843                        warning: error,
844                        element: Element::from(element),
845                    }),
846                    warnings,
847                })
848            }
849        }
850    }
851}
852
853/// A representation of a JSON element that satisfies the needs of most consumers of a [`Warning`].
854///
855/// This representation avoids the complexity of needing to provide a `'buf` lifetime to the [`json::Element`].
856/// This would complicate all warnings types with that lifetime.
857///
858/// A consumer of warnings wants to group them by [`json::ElemId`] using `Warning::group_by_elem` and then
859/// display or report the warnings by path.
860///
861/// The linter report also wants to highlight the source JSON that a warning refers too.
862#[derive(Debug)]
863pub struct Element {
864    /// The Id of the element that caused the [`Warning`].
865    ///
866    /// This is used for sorting warnings and can be used to retrieve the [`json::Element`] object.
867    id: json::ElemId,
868
869    /// The `Span` that delimits the [`json::Element`].
870    span: json::parser::Span,
871
872    /// The elements path.
873    ///
874    /// Most consumers of warnings just want this data.
875    path: Path,
876}
877
878impl Element {
879    pub fn span(&self) -> json::parser::Span {
880        self.span
881    }
882
883    pub fn path(&self) -> &Path {
884        &self.path
885    }
886
887    pub fn into_parts(self) -> (json::parser::Span, Path) {
888        let Self { id: _, span, path } = self;
889        (span, path)
890    }
891}
892
893impl<'buf> From<&json::Element<'buf>> for Element {
894    fn from(elem: &json::Element<'buf>) -> Self {
895        Self {
896            id: elem.id(),
897            span: elem.span(),
898            path: Path(elem.path().to_string()),
899        }
900    }
901}
902
903/// A warning printer that constructs a human-readable report from the source JSON.
904pub struct SourceReportIter<'caller, 'buf, W: Warning> {
905    /// An iterator of `Element`s and their associated warnings.
906    report_iter: Iter<'caller, W>,
907
908    /// The source JSON.
909    json: &'buf str,
910}
911
912impl<'caller, 'buf, W: Warning> SourceReportIter<'caller, 'buf, W> {
913    pub fn new(json: &'buf str, report_iter: Iter<'caller, W>) -> Self {
914        Self { report_iter, json }
915    }
916}
917
918impl<'caller, 'buf, W: Warning> Iterator for SourceReportIter<'caller, 'buf, W> {
919    type Item = ElementReport<'caller, 'buf, W>;
920
921    #[expect(
922        clippy::string_slice,
923        reason = "The disconnection between the source JSON and the `Element` will be fixed in a future PR"
924    )]
925    fn next(&mut self) -> Option<Self::Item> {
926        let group = self.report_iter.next()?;
927        let (element, warnings) = group.to_parts();
928
929        // Slice up to the start of the span to calculate line and col numbers.
930        let lead_in = &self.json[..element.span.start];
931        // We can start the newline check from this byte index the next time.
932        let json::LineCol { line, col } = json::line_col(lead_in);
933        let json = &self.json[element.span.start..element.span.end];
934
935        Some(ElementReport {
936            element_path: element.path(),
937            warnings,
938            json,
939            location: json::LineCol {
940                line,
941                col: col.saturating_add(1),
942            },
943        })
944    }
945}
946
947#[derive(Debug)]
948pub struct ElementReport<'caller, 'buf, W: Warning> {
949    /// The [`json::Element`] that has the warnings.
950    pub element_path: &'caller Path,
951
952    /// The list of warnings for the [`json::Element`].
953    pub warnings: Vec<&'caller W>,
954
955    /// The string from the source JSON.
956    pub json: &'buf str,
957
958    /// The location of the string in the source JSON.
959    pub location: json::LineCol,
960}
961
962/// A Display object for writing a set of warnings.
963///
964/// The warnings set is formatted as a tree with element paths on the first level
965/// and a list of warning ids on the second.
966///
967/// ```shell
968/// $path.to.json.[0].field:
969///   - list_of_warning_ids
970///   - next_warning_id
971///
972/// $next.path.to.[1].json.field
973///   - list_of_warning_ids
974/// ```
975pub struct SetWriter<'caller, W: Warning> {
976    /// The list of warnings for the [`json::Element`].
977    warnings: &'caller Set<W>,
978
979    /// The indent to prefix to each warning id.
980    indent: &'caller str,
981}
982
983impl<'caller, W: Warning> SetWriter<'caller, W> {
984    /// Create a new `SetWriter` with a default warning id indent of `"  - "`.
985    pub fn new(warnings: &'caller Set<W>) -> Self {
986        Self {
987            warnings,
988            indent: "  - ",
989        }
990    }
991
992    /// Create a new `SetWriter` with a custom warning id indent.
993    pub fn with_indent(warnings: &'caller Set<W>, indent: &'caller str) -> Self {
994        Self { warnings, indent }
995    }
996}
997
998impl<W: Warning> fmt::Debug for SetWriter<'_, W> {
999    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1000        fmt::Display::fmt(self, f)
1001    }
1002}
1003
1004impl<W: Warning> fmt::Display for SetWriter<'_, W> {
1005    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1006        let mut iter = self.warnings.iter();
1007
1008        {
1009            // Write the first group without an empty line prefix.
1010            let Some((element, warnings)) = iter.next().map(|g| g.to_parts()) else {
1011                return Ok(());
1012            };
1013
1014            writeln!(f, "{}", element.path)?;
1015
1016            for warning in warnings {
1017                write!(f, "{}{}", self.indent, warning)?;
1018            }
1019        }
1020
1021        // Write the rest of the Groups with am empty line padding.
1022        for (element, warnings) in iter.map(|g| g.to_parts()) {
1023            writeln!(f, "\n{}", element.path)?;
1024
1025            for warning in warnings {
1026                write!(f, "{}{}", self.indent, warning)?;
1027            }
1028        }
1029
1030        Ok(())
1031    }
1032}
1033
1034/// Each mod defines warnings for the type that it's trying to parse or lint from a [`json::Element`].
1035///
1036/// The `Warning` in the mod should impl this trait to take part in the [`Warning`] system.
1037pub trait Warning: Sized + fmt::Debug + fmt::Display + Send + Sync {
1038    /// Return the human readable identifier for the [`Warning`].
1039    ///
1040    /// This is used in the `auto_test` assertion system.
1041    /// Changing these strings may require updating `output_price__cdr.json` files.
1042    fn id(&self) -> Id;
1043}
1044
1045/// A transparent container that stores the source line where the `Warning` occurred in a test build;
1046#[derive(Debug)]
1047struct Source<W: Warning> {
1048    #[cfg(test)]
1049    /// The line in the source code where this `Warning` occurred.
1050    location: &'static std::panic::Location<'static>,
1051
1052    /// The warning.
1053    warning: W,
1054}
1055
1056impl<W: Warning> Source<W> {
1057    #[track_caller]
1058    fn new(warning: W) -> Self {
1059        #[cfg(test)]
1060        {
1061            Self {
1062                location: std::panic::Location::caller(),
1063                warning,
1064            }
1065        }
1066
1067        #[expect(
1068            clippy::cfg_not_test,
1069            reason = "This is code that is designed for use in tests"
1070        )]
1071        #[cfg(not(test))]
1072        {
1073            Self { warning }
1074        }
1075    }
1076
1077    /// Discard the debug info and return the inner `Warning`.
1078    fn into_warning(self) -> W {
1079        self.warning
1080    }
1081
1082    /// Convert the inner `Warning` into another type of `Warning`.
1083    fn into_other<WA>(self) -> Source<WA>
1084    where
1085        W: Into<WA>,
1086        WA: Warning,
1087    {
1088        self.map(Into::into)
1089    }
1090
1091    /// Convert the inner `Warning` into another type of `Warning`.
1092    fn map<F, WA>(self, mut f: F) -> Source<WA>
1093    where
1094        F: FnMut(W) -> WA,
1095        WA: Warning,
1096    {
1097        #[cfg(test)]
1098        {
1099            let Self {
1100                location: source,
1101                warning,
1102            } = self;
1103            Source {
1104                location: source,
1105                warning: f(warning),
1106            }
1107        }
1108
1109        #[expect(
1110            clippy::cfg_not_test,
1111            reason = "This is code that is designed for use in tests"
1112        )]
1113        #[cfg(not(test))]
1114        {
1115            let Self { warning } = self;
1116            Source {
1117                warning: f(warning),
1118            }
1119        }
1120    }
1121}
1122
1123impl<W: Warning> Deref for Source<W> {
1124    type Target = W;
1125
1126    fn deref(&self) -> &Self::Target {
1127        &self.warning
1128    }
1129}
1130
1131/// A set of [`Warning`]s transported through the system using a `VerdictDeferred` or `CaveatDeferred`.
1132///
1133///
1134/// This set is considered deferred as the [`Warning`]s need to be associated with a [`json::Element`]
1135/// to become [`Warning`]s.
1136///
1137/// NOTE: The deferred types are used to avoid passing [`json::Element`] references
1138/// to functions just to create [`Warning`]s.
1139#[derive(Debug)]
1140pub(crate) struct SetDeferred<W: Warning>(Vec<Source<W>>);
1141
1142impl<W: Warning> SetDeferred<W> {
1143    /// Create a new set of [`Warning`]s
1144    pub(crate) fn new() -> Self {
1145        Self(Vec::new())
1146    }
1147
1148    /// Create and add a [`Warning`] to the set while consuming the set into a [`VerdictDeferred`].
1149    ///
1150    /// This is designed for use as the last [`Warning`] of a function. The function should exit with the `Err` returned.
1151    #[track_caller]
1152    pub(crate) fn bail<T>(self, warning: W) -> VerdictDeferred<T, W> {
1153        let Self(warnings) = self;
1154        Err(ErrorSetDeferred {
1155            error: warning,
1156            warnings,
1157        })
1158    }
1159
1160    /// Extend this set with the warnings of another.
1161    ///
1162    /// The other set's warnings will be converted if necessary.
1163    fn extend<WA>(&mut self, warnings: SetDeferred<WA>)
1164    where
1165        WA: Into<W> + Warning,
1166    {
1167        let SetDeferred(warnings) = warnings;
1168        self.0.extend(warnings.into_iter().map(Source::into_other));
1169    }
1170}
1171
1172/// A set of [`Warning`]s and a [`Warning`] that caused an operation to fail to be represented as an [`Error`].
1173///
1174/// This set is transported through the system using a [`VerdictDeferred`]s `Err` variant.
1175///
1176/// This set is considered deferred as the [`Warning`]s need to be associated with a [`json::Element`]
1177/// to become [`Warning`]s.
1178///
1179/// NOTE: The deferred types are used to avoid passing [`json::Element`] references
1180/// to functions just to create [`Warning`]s.
1181#[derive(Debug)]
1182pub struct ErrorSetDeferred<W: Warning> {
1183    error: W,
1184    warnings: Vec<Source<W>>,
1185}
1186
1187impl<W: Warning> ErrorSetDeferred<W> {
1188    /// Create a new list of [`Warning`]s
1189    pub(crate) fn with_warn(warning: W) -> Self {
1190        Self {
1191            warnings: Vec::new(),
1192            error: warning,
1193        }
1194    }
1195
1196    /// Converts `ErrorSetDeferred<W>` into `ErrorSetDeferred<WA>` using the `impl Into<WA> for W`.
1197    ///
1198    /// This is used by the [`from_warning_all`] macro.
1199    pub(crate) fn into_other<WA>(self) -> ErrorSetDeferred<WA>
1200    where
1201        W: Into<WA>,
1202        WA: Warning,
1203    {
1204        let Self { error, warnings } = self;
1205        let warnings = warnings.into_iter().map(Source::into_other).collect();
1206        ErrorSetDeferred {
1207            error: error.into(),
1208            warnings,
1209        }
1210    }
1211}
1212
1213/// A set of [`Warning`]s transported through the system using a [`Caveat`].
1214#[derive(Debug)]
1215pub struct Set<W: Warning>(BTreeMap<json::ElemId, Group<W>>);
1216
1217impl<W: Warning> Set<W> {
1218    /// Create a new list of [`Warning`]s
1219    pub(crate) fn new() -> Self {
1220        Self(BTreeMap::new())
1221    }
1222
1223    pub(crate) fn into_inner(self) -> BTreeMap<json::ElemId, Group<W>> {
1224        self.0
1225    }
1226
1227    /// Insert a [`Warning`] defined in a domain module and it's associated [`json::Element`].
1228    #[track_caller]
1229    pub(crate) fn insert(&mut self, warning: W, element: &json::Element<'_>) {
1230        self.insert_warning(warning, element.id(), || Element::from(element));
1231    }
1232
1233    /// Insert [`Warning`] defined in a domain module and it's associated [`Element`].
1234    ///
1235    /// Note: The [`Element`] is created lazily.
1236    #[track_caller]
1237    fn insert_warning<F>(&mut self, warning: W, elem_id: json::ElemId, f: F)
1238    where
1239        F: FnOnce() -> Element,
1240    {
1241        use std::collections::btree_map::Entry;
1242
1243        match self.0.entry(elem_id) {
1244            Entry::Vacant(entry) => {
1245                let element = f();
1246                entry.insert_entry(Group {
1247                    element,
1248                    warnings: vec![Source::new(warning)],
1249                });
1250            }
1251            Entry::Occupied(mut entry) => {
1252                entry.get_mut().warnings.push(Source::new(warning));
1253            }
1254        }
1255    }
1256
1257    /// Consume the set and insert a [`Warning`] while returning a [`Verdict`].
1258    ///
1259    /// This is designed for use as the last [`Warning`] of a function. The function should exit with the `Err` returned.
1260    #[track_caller]
1261    pub(crate) fn bail<T>(self, warning: W, element: &json::Element<'_>) -> Verdict<T, W> {
1262        let Self(warnings) = self;
1263
1264        Err(ErrorSet {
1265            error: Box::new(Error {
1266                warning,
1267                element: Element::from(element),
1268            }),
1269            warnings,
1270        })
1271    }
1272
1273    /// Converts `Set<W>` into `Set<WA>` using the `impl Into<WA> for W`.
1274    ///
1275    /// This is used by the [`from_warning_all`] macro.
1276    pub(crate) fn into_other<WA>(self) -> Set<WA>
1277    where
1278        W: Into<WA>,
1279        WA: Warning,
1280    {
1281        let Set(warnings) = self;
1282        let warnings = warnings
1283            .into_iter()
1284            .map(|(elem_id, group)| (elem_id, group.into_other()))
1285            .collect();
1286        Set(warnings)
1287    }
1288
1289    /// Return true if the [`Warning`] set is empty.
1290    pub fn is_empty(&self) -> bool {
1291        self.0.is_empty()
1292    }
1293
1294    /// Return the amount of [`Element`]s in this set.
1295    ///
1296    /// Each [`Element`] can have many [`Warning`]s associated with it.
1297    pub fn len_elements(&self) -> usize {
1298        self.0.len()
1299    }
1300
1301    /// Return the total amount of [`Warning`]s in this set for all [`Element`]s.
1302    pub fn len_warnings(&self) -> usize {
1303        self.0
1304            .values()
1305            .fold(0, |acc, group| acc.saturating_add(group.warnings.len()))
1306    }
1307
1308    /// Return an iterator of [`Warning`]s grouped by [`json::Element`].
1309    pub fn iter(&self) -> Iter<'_, W> {
1310        Iter {
1311            warnings: self.0.iter(),
1312        }
1313    }
1314
1315    /// Return a map of [`json::Element`] paths to a list of [`Warning`].
1316    ///
1317    /// This is designed to be used to print out maps of warnings associated with elements.
1318    /// You can use the debug alternate format `{:#?}` to print the map 'pretty' over multiple lines
1319    /// with indentation.
1320    pub fn path_map(&self) -> BTreeMap<&str, Vec<&W>> {
1321        self.0
1322            .values()
1323            .map(|Group { element, warnings }| {
1324                let path = element.path.as_str();
1325                let warnings = warnings.iter().map(|w| &**w).collect();
1326                (path, warnings)
1327            })
1328            .collect()
1329    }
1330
1331    /// Consume the `Set` and return a map of [`json::Element`] paths to a list of [`Warning`]s.
1332    ///
1333    /// This is designed to be used to print out maps of warnings associated with elements.
1334    pub fn into_path_map(self) -> BTreeMap<Path, Vec<W>> {
1335        self.0
1336            .into_values()
1337            .map(|Group { element, warnings }| {
1338                let warnings = warnings.into_iter().map(Source::into_warning).collect();
1339                (element.path, warnings)
1340            })
1341            .collect()
1342    }
1343
1344    /// Return a map of [`json::Element`] paths to a list of [`Warning`] ids as Strings.
1345    ///
1346    /// This is designed to be used to print out maps of warnings associated with elements.
1347    /// You can use the debug alternate format `{:#?}` to print the map 'pretty' over multiple lines
1348    /// with indentation.
1349    ///
1350    /// Note: This representation is also valid JSON and can be copied directly to
1351    /// a test expectation file.
1352    pub fn path_id_map(&self) -> BTreeMap<&str, Vec<Id>> {
1353        self.0
1354            .values()
1355            .map(|group| {
1356                let warnings = group.warnings.iter().map(|w| w.id()).collect();
1357                (group.element.path.as_str(), warnings)
1358            })
1359            .collect()
1360    }
1361
1362    /// Return a map of [`json::Element`] paths to a list of [`Warning`] messages as Strings.
1363    ///
1364    /// This is designed to be used to print out maps of warnings associated with elements.
1365    /// You can use the debug alternate format `{:#?}` to print the map 'pretty' over multiple lines
1366    /// with indentation.
1367    pub fn path_msg_map(&self) -> BTreeMap<&str, Vec<String>> {
1368        self.0
1369            .values()
1370            .map(|group| {
1371                let warnings = group.warnings.iter().map(|w| w.to_string()).collect();
1372                (group.element.path.as_str(), warnings)
1373            })
1374            .collect()
1375    }
1376
1377    /// Deescalate an [`Error`] by subsuming it back into a `Set`.
1378    pub(crate) fn deescalate_error(&mut self, err_set: ErrorSet<W>) {
1379        let ErrorSet { error, warnings } = err_set;
1380        let Error { warning, element } = *error;
1381        self.0.extend(warnings);
1382        self.insert_warning(warning, element.id, || element);
1383    }
1384
1385    /// Extend this set with the warnings of another.
1386    ///
1387    /// The other set's warnings will be converted if necessary.
1388    pub(crate) fn extend(&mut self, warnings: impl Iterator<Item = (json::ElemId, Group<W>)>) {
1389        use std::collections::btree_map::Entry;
1390
1391        for (elem_id, group) in warnings {
1392            match self.0.entry(elem_id) {
1393                Entry::Vacant(entry) => {
1394                    entry.insert_entry(group);
1395                }
1396                Entry::Occupied(mut entry) => {
1397                    let Group {
1398                        element: _,
1399                        warnings,
1400                    } = group;
1401                    entry.get_mut().warnings.extend(warnings);
1402                }
1403            }
1404        }
1405    }
1406}
1407
1408/// A set of [`Warning`]s and a [`Warning`] that caused an operation to fail to be represented as an [`Error`].
1409///
1410/// This set is transported through the system using a [`Verdict`]s `Err` variant.
1411#[derive(Debug)]
1412pub struct ErrorSet<W: Warning> {
1413    /// The warning that caused an operation to fail.
1414    ///
1415    /// The warning is converted to an [`Error`] so it's ready to take part in Rust's error system.
1416    error: Box<Error<W>>,
1417
1418    /// The warnings accumulated up until the failure moment.
1419    ///
1420    /// This list does not included the warning that caused the operation to fail.
1421    warnings: BTreeMap<json::ElemId, Group<W>>,
1422}
1423
1424impl<W> ErrorSet<W>
1425where
1426    W: Warning,
1427{
1428    /// Create a new set of [`Warning`]s
1429    pub(crate) fn with_warn(warning: W, element: &json::Element<'_>) -> Self {
1430        Self {
1431            warnings: BTreeMap::new(),
1432            error: Box::new(Error {
1433                warning,
1434                element: Element::from(element),
1435            }),
1436        }
1437    }
1438
1439    /// Consume the [`ErrorSet`] and return the [`Error`] and warnings as a `Set`.
1440    pub fn into_parts(self) -> (Error<W>, Set<W>) {
1441        let Self { error, warnings } = self;
1442        (*error, Set(warnings))
1443    }
1444
1445    /// Converts `ErrorSet<W>` into `ErrorSet<WA>` using the `impl Into<WA> for K`.
1446    ///
1447    /// This is used by the [`from_warning_all`] macro.
1448    pub(crate) fn into_other<WA>(self) -> ErrorSet<WA>
1449    where
1450        W: Into<WA>,
1451        WA: Warning,
1452    {
1453        let Self { error, warnings } = self;
1454        let warnings = warnings
1455            .into_iter()
1456            .map(|(elem_id, group)| (elem_id, group.into_other()))
1457            .collect();
1458        ErrorSet {
1459            error: Box::new(Error::into_other(*error)),
1460            warnings,
1461        }
1462    }
1463}
1464
1465/// A group of warning `Warning`s associated with an `Element`.
1466///
1467/// This group is emitted from the `IntoGroupByElem` iterator.
1468/// The warning `Warning`s are owned and so can be moved to another location.
1469#[derive(Debug)]
1470pub struct Group<W: Warning> {
1471    /// The [`json::Element`] that has [`Warning`]s.
1472    element: Element,
1473
1474    /// The list of warnings for the [`json::Element`].
1475    warnings: Vec<Source<W>>,
1476}
1477
1478impl<W> Group<W>
1479where
1480    W: Warning,
1481{
1482    /// Consume the `Group` and return the constituent parts.
1483    pub fn into_parts(self) -> (Element, Vec<W>) {
1484        let Self { element, warnings } = self;
1485        let warnings = warnings.into_iter().map(Source::into_warning).collect();
1486        (element, warnings)
1487    }
1488
1489    /// Map the `Warning` contained in the `Group` to another `Warning` type.
1490    pub(crate) fn map<F, WA>(self, mut f: F) -> Group<WA>
1491    where
1492        F: FnMut(W) -> WA,
1493        WA: Warning,
1494    {
1495        let Self { element, warnings } = self;
1496        let warnings = warnings
1497            .into_iter()
1498            .map(|source| source.map(&mut f))
1499            .collect();
1500        Group { element, warnings }
1501    }
1502
1503    pub fn to_parts(&self) -> (&Element, Vec<&W>) {
1504        let Self { element, warnings } = self;
1505        let warnings = warnings.iter().map(|w| &**w).collect();
1506        (element, warnings)
1507    }
1508
1509    pub fn warnings(&self) -> Vec<&W> {
1510        self.warnings.iter().map(|w| &**w).collect()
1511    }
1512
1513    pub fn into_warnings(self) -> Vec<W> {
1514        let Self {
1515            element: _,
1516            warnings,
1517        } = self;
1518        warnings.into_iter().map(Source::into_warning).collect()
1519    }
1520
1521    /// Converts `IntoGroup<W>` into `IntoGroup<WA>` using the `impl Into<WA> for K`.
1522    ///
1523    /// This is used by the [`from_warning_all`] macro.
1524    fn into_other<WA>(self) -> Group<WA>
1525    where
1526        W: Into<WA>,
1527        WA: Warning,
1528    {
1529        let Self { element, warnings } = self;
1530        let warnings = warnings.into_iter().map(Source::into_other).collect();
1531        Group { element, warnings }
1532    }
1533}
1534
1535/// An iterator of borrowed [`Warning`]s grouped by [`json::Element`].
1536pub struct Iter<'caller, W>
1537where
1538    W: Warning,
1539{
1540    /// The iterator over every [`Warning`].
1541    warnings: std::collections::btree_map::Iter<'caller, json::ElemId, Group<W>>,
1542}
1543
1544impl<W> Iter<'_, W> where W: Warning {}
1545
1546impl<'caller, W: Warning> Iterator for Iter<'caller, W> {
1547    type Item = &'caller Group<W>;
1548
1549    fn next(&mut self) -> Option<Self::Item> {
1550        let (_elem_id, group) = self.warnings.next()?;
1551        Some(group)
1552    }
1553}
1554
1555/// An iterator of borrowed [`Warning`]s grouped by [`json::Element`].
1556pub struct IntoIter<W>
1557where
1558    W: Warning,
1559{
1560    /// The iterator over every [`Warning`].
1561    warnings: std::collections::btree_map::IntoIter<json::ElemId, Group<W>>,
1562}
1563
1564impl<W: Warning> Iterator for IntoIter<W> {
1565    type Item = Group<W>;
1566
1567    fn next(&mut self) -> Option<Self::Item> {
1568        let (_elem_id, group) = self.warnings.next()?;
1569        Some(group)
1570    }
1571}
1572
1573impl<W: Warning> IntoIterator for Set<W> {
1574    type Item = Group<W>;
1575    type IntoIter = IntoIter<W>;
1576
1577    fn into_iter(self) -> Self::IntoIter {
1578        let Set(warnings) = self;
1579        IntoIter {
1580            warnings: warnings.into_iter(),
1581        }
1582    }
1583}
1584
1585impl<'a, W: Warning> IntoIterator for &'a Set<W> {
1586    type Item = &'a Group<W>;
1587    type IntoIter = Iter<'a, W>;
1588
1589    fn into_iter(self) -> Self::IntoIter {
1590        self.iter()
1591    }
1592}