    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65

    /// Violation of [`ArgMatches`][crate::ArgMatches] assumptions
    #[derive(Clone, Debug)]
    #[allow(missing_copy_implementations)] // We might add non-Copy types in the future
    #[non_exhaustive]
    pub enum MatchesError {
        /// Failed to downcast `AnyValue` to the specified type
        #[non_exhaustive]
        Downcast {
            /// Type for value stored in [`ArgMatches`][crate::ArgMatches]
            actual: super::AnyValueId,
            /// The target type to downcast to
            expected: super::AnyValueId,
        },
        /// Argument not defined in [`Command`][crate::Command]
        #[non_exhaustive]
        UnknownArgument {
            // Missing `id` but blocked on a public id type which will hopefully come with `unstable-v4`
        },
    }

    impl MatchesError {
        #[cfg_attr(debug_assertions, track_caller)]
        pub(crate) fn unwrap<T>(id: &str, r: Result<T, MatchesError>) -> T {
            let err = match r {
                Ok(t) => {
                    return t;
                }
                Err(err) => err,
            };
            panic!(
                "Mismatch between definition and access of `{}`. {}",
                id, err
            )
        }
    }

    impl std::error::Error for MatchesError {}

    impl std::fmt::Display for MatchesError {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
            match self {
                Self::Downcast { actual, expected } => {
                    writeln!(
                        f,
                        "Could not downcast to {:?}, need to downcast to {:?}",
                        expected, actual
                    )
                }
                Self::UnknownArgument {} => {
                    writeln!(f, "Unknown argument or group id.  Make sure you are using the argument id and not the short or long flags")
                }
            }
        }
    }

    #[test]
    fn check_auto_traits() {
        static_assertions::assert_impl_all!(
            MatchesError: Send,
            Sync,
            std::panic::RefUnwindSafe,
            std::panic::UnwindSafe,
            Unpin
        );
    }