kodept_macros/error/
traits.rs

1use crate::error::report::{Report, ReportMessage};
2use crate::error::ErrorReported;
3use codespan_reporting::diagnostic::{Diagnostic, Severity};
4use codespan_reporting::files::{Error, Files};
5use codespan_reporting::term::termcolor::WriteColor;
6use codespan_reporting::term::Config;
7use extend::ext;
8use kodept_core::file_relative::{CodePath, FileRelative};
9
10#[derive(Clone)]
11pub struct CodespanSettings<S> {
12    pub config: Config,
13    pub stream: S,
14}
15
16pub trait Reportable {
17    type FileId;
18
19    fn emit<'f, W: WriteColor, F: Files<'f, FileId = Self::FileId>>(
20        self,
21        settings: &mut CodespanSettings<W>,
22        source: &'f F,
23    ) -> Result<(), Error>;
24}
25
26impl<FileId> Reportable for Diagnostic<FileId> {
27    type FileId = FileId;
28
29    fn emit<'f, W: WriteColor, F: Files<'f, FileId = Self::FileId>>(
30        self,
31        settings: &mut CodespanSettings<W>,
32        source: &'f F,
33    ) -> Result<(), Error> {
34        codespan_reporting::term::emit(&mut settings.stream, &settings.config, source, &self)
35    }
36}
37
38impl Reportable for Report {
39    type FileId = ();
40
41    fn emit<'f, W: WriteColor, F: Files<'f, FileId = Self::FileId>>(
42        self,
43        settings: &mut CodespanSettings<W>,
44        source: &'f F,
45    ) -> Result<(), Error> {
46        self.into_diagnostic().emit(settings, source)
47    }
48}
49
50impl<E: std::error::Error> Reportable for FileRelative<&E> {
51    type FileId = ();
52
53    fn emit<'f, W: WriteColor, F: Files<'f, FileId = Self::FileId>>(
54        self,
55        settings: &mut CodespanSettings<W>,
56        source: &'f F,
57    ) -> Result<(), Error> {
58        let report = Report::new(
59            &self.filepath,
60            vec![],
61            ReportMessage::new(Severity::Error, "external", self.value.to_string()),
62        );
63        report.emit(settings, source)
64    }
65}
66
67impl<R: Reportable> Reportable for Vec<R> {
68    type FileId = R::FileId;
69
70    fn emit<'f, W: WriteColor, F: Files<'f, FileId = Self::FileId>>(
71        self,
72        settings: &mut CodespanSettings<W>,
73        source: &'f F,
74    ) -> Result<(), Error> {
75        self.into_iter()
76            .try_for_each(|it| it.emit(settings, source))
77    }
78}
79
80#[ext]
81pub impl<T, R: Reportable> Result<T, R> {
82    fn or_emit<'f, W: WriteColor, F: Files<'f, FileId = R::FileId>>(
83        self,
84        settings: &mut CodespanSettings<W>,
85        source: &'f F,
86    ) -> Result<T, ErrorReported> {
87        match self {
88            Ok(x) => Ok(x),
89            Err(e) => {
90                e.emit(settings, source).expect("Cannot emit diagnostics");
91                Err(ErrorReported::new())
92            }
93        }
94    }
95}
96
97#[ext]
98pub impl<T, E: std::error::Error + Send + Sync + 'static> Result<T, E> {
99    fn or_emit<'f, W: WriteColor, F: Files<'f, FileId = ()>>(
100        self,
101        settings: &mut CodespanSettings<W>,
102        source: &'f F,
103        filepath: CodePath,
104    ) -> Result<T, ErrorReported> {
105        match self {
106            Ok(x) => Ok(x),
107            Err(e) => {
108                let file_relative = FileRelative {
109                    value: &e,
110                    filepath,
111                };
112                file_relative
113                    .emit(settings, source)
114                    .expect("Cannot emit diagnostics");
115                Err(ErrorReported::with_cause(e))
116            }
117        }
118    }
119}