use alloc::borrow::Cow;
use core::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DriverError {
stage: &'static str,
message: Cow<'static, str>,
}
impl DriverError {
#[must_use]
pub fn new(message: impl Into<Cow<'static, str>>) -> Self {
Self {
stage: "",
message: message.into(),
}
}
#[must_use]
#[inline]
pub fn stage(&self) -> &str {
self.stage
}
#[must_use]
#[inline]
pub fn message(&self) -> &str {
&self.message
}
#[must_use]
pub(crate) fn in_stage(mut self, name: &'static str) -> Self {
if self.stage.is_empty() {
self.stage = name;
}
self
}
}
impl fmt::Display for DriverError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.stage.is_empty() {
write!(f, "driver error: {}", self.message)
} else {
write!(f, "stage `{}` failed: {}", self.stage, self.message)
}
}
}
impl core::error::Error for DriverError {}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
use alloc::string::{String, ToString};
#[test]
fn test_new_accepts_literal_and_owned() {
assert_eq!(DriverError::new("x"), DriverError::new(String::from("x")));
}
#[test]
fn test_message_is_preserved() {
assert_eq!(DriverError::new("type error").message(), "type error");
}
#[test]
fn test_stage_is_empty_before_stamping() {
assert_eq!(DriverError::new("boom").stage(), "");
}
#[test]
fn test_in_stage_stamps_empty_name() {
let err = DriverError::new("boom").in_stage("parse");
assert_eq!(err.stage(), "parse");
assert_eq!(err.message(), "boom");
}
#[test]
fn test_in_stage_does_not_overwrite_existing_name() {
let err = DriverError::new("boom").in_stage("lex").in_stage("parse");
assert_eq!(err.stage(), "lex");
}
#[test]
fn test_display_without_stage() {
assert_eq!(DriverError::new("boom").to_string(), "driver error: boom");
}
#[test]
fn test_display_with_stage() {
let err = DriverError::new("boom").in_stage("codegen");
assert_eq!(err.to_string(), "stage `codegen` failed: boom");
}
#[test]
fn test_error_trait_is_implemented() {
fn assert_error<E: core::error::Error>(_: &E) {}
assert_error(&DriverError::new("boom"));
}
}