use std::borrow::Cow;
use std::error::Error;
use std::fmt::{self, Display};
use perf_event_open_sys::bindings::perf_event_attr;
use crate::parse::{Parse, ParseBuf, ParseConfig, Parser};
used_in_docs!(Parse, Parser, ParseBuf, ParseConfig);
used_in_docs!(perf_event_attr);
type BoxedError = Box<dyn Error + Send + Sync + 'static>;
pub type ParseResult<T> = std::result::Result<T, ParseError>;
#[derive(Debug)]
pub struct ParseError {
code: ErrorKind,
source: Option<BoxedError>,
}
impl ParseError {
#[cold]
pub fn new<E>(error: E) -> Self
where
E: Into<BoxedError>,
{
Self {
code: ErrorKind::External,
source: Some(error.into()),
}
}
#[cold]
pub(crate) fn custom(kind: ErrorKind, msg: impl Message) -> Self {
Self::new(CustomMessageError::new(msg)).with_kind(kind)
}
#[inline]
pub fn kind(&self) -> ErrorKind {
self.code
}
#[inline]
const fn from_code(code: ErrorKind) -> Self {
Self { code, source: None }
}
pub(crate) fn with_kind(self, code: ErrorKind) -> Self {
Self { code, ..self }
}
#[cold]
pub fn eof() -> Self {
Self::from_code(ErrorKind::Eof)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[non_exhaustive]
pub enum ErrorKind {
Eof,
InvalidRecord,
UnsupportedConfig,
UnsupportedData,
External,
}
impl Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.code {
ErrorKind::Eof => f.write_str("unexpected EOF during parsing")?,
ErrorKind::InvalidRecord => f.write_str("invalid record")?,
ErrorKind::UnsupportedData => f.write_str("unsupported serialized data")?,
ErrorKind::UnsupportedConfig => f.write_str("unsupported config")?,
ErrorKind::External => {
if self.source.is_none() {
f.write_str("user-provided error")?;
}
}
}
if let Some(source) = &self.source {
if matches!(self.code, ErrorKind::External) {
f.write_str(": ")?;
}
source.fmt(f)?;
}
Ok(())
}
}
impl Error for ParseError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.source {
Some(source) => Some(&**source),
None => None,
}
}
}
impl From<std::io::Error> for ParseError {
#[cold]
fn from(error: std::io::Error) -> Self {
match error.kind() {
std::io::ErrorKind::UnexpectedEof => Self::new(error).with_kind(ErrorKind::Eof),
_ => Self::new(error),
}
}
}
impl From<BoxedError> for ParseError {
#[cold]
fn from(error: BoxedError) -> Self {
Self {
code: ErrorKind::External,
source: Some(error),
}
}
}
pub(crate) trait Message: Display {
fn as_str(&self) -> Option<&'static str>;
}
impl Message for &'static str {
fn as_str(&self) -> Option<&'static str> {
Some(self)
}
}
impl Message for fmt::Arguments<'_> {
fn as_str(&self) -> Option<&'static str> {
self.as_str()
}
}
#[derive(Debug)]
struct CustomMessageError(Cow<'static, str>);
impl CustomMessageError {
fn new(msg: impl Message) -> Self {
Self(match msg.as_str() {
Some(s) => Cow::Borrowed(s),
None => msg.to_string().into(),
})
}
}
impl fmt::Display for CustomMessageError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl Error for CustomMessageError {}