1use crate::hir::types::Span;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum HirError {
12 Malformed { code: &'static str, message: String },
14 IncompatibleProtocol { expected: String, received: String },
17 UnsupportedNode { kind: String, span: Option<Span> },
19 Invalid {
21 code: &'static str,
22 message: String,
23 span: Option<Span>,
24 },
25}
26
27impl HirError {
28 pub fn code(&self) -> &'static str {
30 match self {
31 HirError::Malformed { code, .. } | HirError::Invalid { code, .. } => code,
32 HirError::IncompatibleProtocol { .. } => "incompatible-protocol",
33 HirError::UnsupportedNode { .. } => "unsupported-node",
34 }
35 }
36
37 pub fn message(&self) -> String {
39 match self {
40 HirError::Malformed { message, .. } | HirError::Invalid { message, .. } => {
41 message.clone()
42 }
43 HirError::IncompatibleProtocol { expected, received } => {
44 format!("incompatible protocol: expected {expected}, received {received}")
45 }
46 HirError::UnsupportedNode { kind, .. } => {
47 format!("unsupported node kind '{kind}'")
48 }
49 }
50 }
51
52 pub fn span(&self) -> Option<&Span> {
54 match self {
55 HirError::UnsupportedNode { span, .. } | HirError::Invalid { span, .. } => {
56 span.as_ref()
57 }
58 _ => None,
59 }
60 }
61}
62
63impl std::fmt::Display for HirError {
64 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65 write!(f, "{}: {}", self.code(), self.message())
66 }
67}
68
69impl std::error::Error for HirError {}
70
71impl From<serde_json::Error> for HirError {
72 fn from(error: serde_json::Error) -> Self {
73 HirError::Malformed {
74 code: "malformed-payload",
75 message: error.to_string(),
76 }
77 }
78}
79
80pub(crate) fn invalid(
82 code: &'static str,
83 message: impl Into<String>,
84 span: Option<Span>,
85) -> HirError {
86 HirError::Invalid {
87 code,
88 message: message.into(),
89 span,
90 }
91}