duration_str/
error.rs

1use std::fmt::{Debug, Display, Formatter};
2use thiserror::Error;
3use winnow::error::{ErrorKind, FromExternalError, ParserError};
4use winnow::stream::Stream;
5
6pub trait RawDebug {
7    fn raw(&self) -> String;
8}
9
10impl<A> RawDebug for A
11where
12    A: AsRef<str>,
13{
14    fn raw(&self) -> String {
15        self.as_ref().to_string()
16    }
17}
18
19#[derive(Error, Debug, PartialEq)]
20pub enum DError {
21    #[error("{0}")]
22    ParseError(String),
23    #[error("overflow error")]
24    OverflowError,
25}
26
27const PARTIAL_INPUT_MAX_LEN: usize = 11;
28
29#[derive(Debug, PartialEq, Eq)]
30pub struct PError<I> {
31    partial_input: I,
32    kind: ErrorKind,
33    cause: String,
34}
35
36impl<I> PError<I> {
37    fn new(input: I, kind: ErrorKind) -> Self {
38        PError {
39            partial_input: input,
40            kind,
41            cause: "".to_string(),
42        }
43    }
44
45    pub fn append_cause<C: AsRef<str>>(mut self, cause: C) -> Self {
46        self.cause = cause.as_ref().to_string();
47        self
48    }
49
50    pub fn partial_input(&self) -> String
51    where
52        I: RawDebug,
53    {
54        let raw = self.partial_input.raw();
55        if let Some(offset) = raw
56            .char_indices()
57            .enumerate()
58            .find_map(|(pos, (offset, _))| (PARTIAL_INPUT_MAX_LEN <= pos).then_some(offset))
59        {
60            format!("{}...", raw.split_at(offset).0)
61        } else {
62            raw
63        }
64    }
65}
66
67impl<I: Stream + Clone> ParserError<I> for PError<I> {
68    fn from_error_kind(input: &I, kind: ErrorKind) -> Self {
69        PError::new(input.clone(), kind)
70    }
71
72    fn append(self, _: &I, _: &<I as Stream>::Checkpoint, _: ErrorKind) -> Self {
73        self
74    }
75}
76
77impl<I: Clone, E: std::error::Error + Send + Sync + 'static> FromExternalError<I, E> for PError<I> {
78    #[inline]
79    fn from_external_error(input: &I, kind: ErrorKind, e: E) -> Self {
80        let mut err = Self::new(input.clone(), kind);
81        {
82            err.cause = e.to_string();
83        }
84        err
85    }
86}
87
88impl<I> Display for PError<I>
89where
90    I: Display,
91{
92    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
93        write!(f, "partial_input:{}", self.partial_input)?;
94        if !self.cause.is_empty() {
95            write!(f, ", {}", self.cause)?;
96        }
97        Ok(())
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104
105    #[test]
106    fn test_partial_input() {
107        let error = PError::new("1234567890abcde", ErrorKind::Complete);
108        let partial_input = error.partial_input();
109        assert_eq!(partial_input, "1234567890a...");
110
111        let error = PError::new("你好,龙骧虎步龙行龘龘龘", ErrorKind::Complete);
112        let partial_input = error.partial_input();
113        assert_eq!(partial_input, "你好,龙骧虎步龙行龘龘...");
114
115        let error = PError::new("hello,你好", ErrorKind::Complete);
116        let partial_input = error.partial_input();
117        assert_eq!(partial_input, "hello,你好");
118
119        let error = PError::new("1mins", ErrorKind::Complete);
120        let partial_input = error.partial_input();
121        assert_eq!(partial_input, "1mins");
122
123        let error = PError::new("MILLISECONDhah", ErrorKind::Complete);
124        let partial_input = error.partial_input();
125        assert_eq!(partial_input, "MILLISECOND...");
126
127        let error = PError::new("MILLISECOND", ErrorKind::Complete);
128        let partial_input = error.partial_input();
129        assert_eq!(partial_input, "MILLISECOND");
130    }
131}