dangerous/error/expected/
value.rs

1use crate::error::Value;
2use crate::error::{CoreContext, RetryRequirement, ToRetryRequirement};
3use crate::fmt;
4use crate::input::MaybeString;
5
6/// An error representing a failed exact value requirement of
7/// [`Input`](crate::Input).
8#[must_use = "error must be handled"]
9pub struct ExpectedValue<'i> {
10    pub(crate) expected: Value<'i>,
11    pub(crate) context: CoreContext,
12    pub(crate) input: MaybeString<'i>,
13}
14
15impl<'i> ExpectedValue<'i> {
16    /// The [`Input`](crate::Input) value that was expected.
17    #[inline(always)]
18    pub fn expected(&self) -> Value<'i> {
19        self.expected
20    }
21
22    /// The [`CoreContext`] around the error.
23    #[must_use]
24    #[inline(always)]
25    pub fn context(&self) -> CoreContext {
26        self.context
27    }
28
29    /// The [`Input`](crate::Input) provided in the context when the error occurred.
30    #[inline(always)]
31    pub fn input(&self) -> MaybeString<'i> {
32        self.input.clone()
33    }
34}
35
36impl<'i> fmt::Debug for ExpectedValue<'i> {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        f.debug_struct("ExpectedValue")
39            .field("expected", &self.expected())
40            .field("context", &self.context().debug_for(self.input()))
41            .field("input", &self.input())
42            .finish()
43    }
44}
45
46impl<'i> fmt::DisplayBase for ExpectedValue<'i> {
47    fn fmt(&self, w: &mut dyn fmt::Write) -> fmt::Result {
48        if self.is_fatal() {
49            w.write_str("found a different value to the exact expected")
50        } else {
51            w.write_str("not enough input to match expected value")
52        }
53    }
54}
55
56impl<'i> fmt::Display for ExpectedValue<'i> {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        fmt::DisplayBase::fmt(self, f)
59    }
60}
61
62impl<'i> ToRetryRequirement for ExpectedValue<'i> {
63    #[inline]
64    fn to_retry_requirement(&self) -> Option<RetryRequirement> {
65        if self.is_fatal() {
66            None
67        } else {
68            let needed = self.expected().as_bytes().len();
69            let had = self.context.span.len();
70            RetryRequirement::from_had_and_needed(had, needed)
71        }
72    }
73
74    /// Returns `true` if the value could never match and `false` if the matching
75    /// was incomplete.
76    #[inline]
77    fn is_fatal(&self) -> bool {
78        if self.input.is_bound() {
79            return true;
80        }
81        match self.context.span.of(self.input.as_dangerous_bytes()) {
82            Some(found) => !self.expected().as_bytes().starts_with(found),
83            None => true,
84        }
85    }
86}