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}