use std::ops::Deref;
use std::{
fmt::{Debug, Formatter},
io,
};
use biome_console::fmt;
use crate::{
diagnostic::internal::AsDiagnostic, Category, Diagnostic, DiagnosticTags, Location, Severity,
Visit,
};
pub struct Error {
inner: Box<Box<dyn Diagnostic + Send + Sync + 'static>>,
}
impl Error {
pub fn category(&self) -> Option<&'static Category> {
self.as_diagnostic().category()
}
pub fn severity(&self) -> Severity {
self.as_diagnostic().severity()
}
pub fn description(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_diagnostic().description(fmt)
}
pub fn message(&self, fmt: &mut fmt::Formatter<'_>) -> io::Result<()> {
self.as_diagnostic().message(fmt)
}
pub fn advices(&self, visitor: &mut dyn Visit) -> io::Result<()> {
self.as_diagnostic().advices(visitor)
}
pub fn verbose_advices(&self, visitor: &mut dyn Visit) -> io::Result<()> {
self.as_diagnostic().verbose_advices(visitor)
}
pub fn location(&self) -> Location<'_> {
self.as_diagnostic().location()
}
pub fn tags(&self) -> DiagnosticTags {
self.as_diagnostic().tags()
}
pub fn source(&self) -> Option<&dyn Diagnostic> {
self.as_diagnostic().source()
}
}
impl<T> From<T> for Error
where
T: Diagnostic + Send + Sync + 'static,
{
fn from(diag: T) -> Self {
Self {
inner: Box::new(Box::new(diag)),
}
}
}
impl AsDiagnostic for Error {
type Diagnostic = dyn Diagnostic;
fn as_diagnostic(&self) -> &Self::Diagnostic {
&**self.inner
}
fn as_dyn(&self) -> &dyn Diagnostic {
self.as_diagnostic()
}
}
impl AsRef<dyn Diagnostic + 'static> for Error {
fn as_ref(&self) -> &(dyn Diagnostic + 'static) {
self.as_diagnostic()
}
}
impl Deref for Error {
type Target = dyn Diagnostic + 'static;
fn deref(&self) -> &Self::Target {
self.as_diagnostic()
}
}
impl Debug for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Debug::fmt(self.as_diagnostic(), f)
}
}
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[cfg(test)]
mod tests {
use std::{
mem::size_of,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
};
use crate::{Diagnostic, Error, Result};
#[derive(Debug)]
struct TestDiagnostic(Arc<AtomicBool>);
impl Diagnostic for TestDiagnostic {}
impl Drop for TestDiagnostic {
fn drop(&mut self) {
let was_dropped = self.0.swap(true, Ordering::Relaxed);
assert!(!was_dropped);
}
}
#[test]
fn test_drop() {
let drop_flag = AtomicBool::new(false);
let drop_flag = Arc::new(drop_flag);
let diag = TestDiagnostic(drop_flag.clone());
let error = Error::from(diag);
drop(error);
assert!(drop_flag.load(Ordering::Relaxed));
}
#[test]
fn test_error_size() {
assert_eq!(size_of::<Error>(), size_of::<usize>());
}
#[test]
fn test_result_size() {
assert_eq!(size_of::<Result<()>>(), size_of::<usize>());
}
}