1use std::borrow::Cow;
2use std::error::Error;
3use std::fmt::{self, Display};
4
5use perf_event_open_sys::bindings::perf_event_attr;
6
7use crate::parse::{Parse, ParseBuf, ParseConfig, Parser};
8
9used_in_docs!(Parse, Parser, ParseBuf, ParseConfig);
10used_in_docs!(perf_event_attr);
11
12type BoxedError = Box<dyn Error + Send + Sync + 'static>;
13
14pub type ParseResult<T> = std::result::Result<T, ParseError>;
16
17#[derive(Debug)]
26pub struct ParseError {
27 code: ErrorKind,
28 source: Option<BoxedError>,
29}
30
31impl ParseError {
32 #[cold]
34 pub fn new<E>(error: E) -> Self
35 where
36 E: Into<BoxedError>,
37 {
38 Self {
39 code: ErrorKind::External,
40 source: Some(error.into()),
41 }
42 }
43
44 #[cold]
46 pub(crate) fn custom(kind: ErrorKind, msg: impl Message) -> Self {
47 Self::new(CustomMessageError::new(msg)).with_kind(kind)
48 }
49
50 #[inline]
52 pub fn kind(&self) -> ErrorKind {
53 self.code
54 }
55
56 #[inline]
57 const fn from_code(code: ErrorKind) -> Self {
58 Self { code, source: None }
59 }
60
61 pub(crate) fn with_kind(self, code: ErrorKind) -> Self {
62 Self { code, ..self }
63 }
64
65 #[cold]
67 pub fn eof() -> Self {
68 Self::from_code(ErrorKind::Eof)
69 }
70}
71
72#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
74#[non_exhaustive]
75pub enum ErrorKind {
76 Eof,
82
83 InvalidRecord,
89
90 UnsupportedConfig,
96
97 UnsupportedData,
103
104 External,
108}
109
110impl Display for ParseError {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 match self.code {
113 ErrorKind::Eof => f.write_str("unexpected EOF during parsing")?,
114 ErrorKind::InvalidRecord => f.write_str("invalid record")?,
115 ErrorKind::UnsupportedData => f.write_str("unsupported serialized data")?,
116 ErrorKind::UnsupportedConfig => f.write_str("unsupported config")?,
117 ErrorKind::External => {
118 if self.source.is_none() {
121 f.write_str("user-provided error")?;
122 }
123 }
124 }
125
126 if let Some(source) = &self.source {
127 if matches!(self.code, ErrorKind::External) {
128 f.write_str(": ")?;
129 }
130
131 source.fmt(f)?;
132 }
133
134 Ok(())
135 }
136}
137
138impl Error for ParseError {
139 fn source(&self) -> Option<&(dyn Error + 'static)> {
140 match &self.source {
141 Some(source) => Some(&**source),
142 None => None,
143 }
144 }
145}
146
147impl From<std::io::Error> for ParseError {
148 #[cold]
149 fn from(error: std::io::Error) -> Self {
150 match error.kind() {
151 std::io::ErrorKind::UnexpectedEof => Self::new(error).with_kind(ErrorKind::Eof),
152 _ => Self::new(error),
153 }
154 }
155}
156
157impl From<BoxedError> for ParseError {
158 #[cold]
159 fn from(error: BoxedError) -> Self {
160 Self {
161 code: ErrorKind::External,
162 source: Some(error),
163 }
164 }
165}
166
167pub(crate) trait Message: Display {
168 fn as_str(&self) -> Option<&'static str>;
169}
170
171impl Message for &'static str {
172 fn as_str(&self) -> Option<&'static str> {
173 Some(self)
174 }
175}
176
177impl Message for fmt::Arguments<'_> {
178 fn as_str(&self) -> Option<&'static str> {
179 self.as_str()
180 }
181}
182
183#[derive(Debug)]
184struct CustomMessageError(Cow<'static, str>);
185
186impl CustomMessageError {
187 fn new(msg: impl Message) -> Self {
188 Self(match msg.as_str() {
189 Some(s) => Cow::Borrowed(s),
190 None => msg.to_string().into(),
191 })
192 }
193}
194
195impl fmt::Display for CustomMessageError {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 f.write_str(&self.0)
198 }
199}
200
201impl Error for CustomMessageError {}