geam_core/host/
failure.rs1use ecow::EcoString;
2use std::fmt::{self, Display, Formatter};
3
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct HostFailure {
6 message: EcoString,
7}
8
9#[derive(Debug, PartialEq)]
10pub struct HostCallError {
11 kind: HostCallErrorKind,
12}
13
14#[derive(Debug, PartialEq)]
15pub(crate) enum HostCallErrorKind {
16 Failure(HostFailure),
17 Nested(crate::ExecutionError),
18}
19
20impl HostFailure {
21 pub fn new(message: impl Into<EcoString>) -> Self {
22 Self {
23 message: message.into(),
24 }
25 }
26
27 pub fn message(&self) -> &EcoString {
28 &self.message
29 }
30}
31
32impl HostCallError {
33 pub(crate) fn nested(error: crate::ExecutionError) -> Self {
34 Self {
35 kind: HostCallErrorKind::Nested(error),
36 }
37 }
38
39 pub(crate) fn into_kind(self) -> HostCallErrorKind {
40 self.kind
41 }
42}
43
44impl Display for HostFailure {
45 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
46 formatter.write_str(&self.message)
47 }
48}
49
50impl std::error::Error for HostFailure {}
51
52impl Display for HostCallError {
53 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
54 match &self.kind {
55 HostCallErrorKind::Failure(failure) => Display::fmt(failure, formatter),
56 HostCallErrorKind::Nested(error) => Display::fmt(error, formatter),
57 }
58 }
59}
60
61impl std::error::Error for HostCallError {}
62
63impl From<HostFailure> for HostCallError {
64 fn from(error: HostFailure) -> Self {
65 Self {
66 kind: HostCallErrorKind::Failure(error),
67 }
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::{HostCallError, HostFailure};
74 use crate::{ExecutionError, InvariantError, ValueType};
75
76 #[test]
77 fn host_failure_owns_and_displays_its_message() {
78 let failure = HostFailure::new("database unavailable");
79
80 assert_eq!(failure.message(), "database unavailable");
81 assert_eq!(failure.to_string(), "database unavailable");
82 }
83
84 #[test]
85 fn host_call_error_preserves_the_owned_host_failure() {
86 let local = HostCallError::from(HostFailure::new("invalid input"));
87
88 assert_eq!(local.to_string(), "invalid input");
89 assert_eq!(
90 local.into_kind(),
91 super::HostCallErrorKind::Failure(HostFailure::new("invalid input")),
92 );
93 }
94
95 #[test]
96 fn host_call_error_preserves_a_nested_execution_failure() {
97 let execution = ExecutionError::Invariant(InvariantError::ListIndexOutOfBounds {
98 item_type: ValueType::Int,
99 index: 1,
100 length: 0,
101 });
102 let nested = HostCallError::nested(execution.clone());
103
104 assert_eq!(
105 nested.to_string(),
106 "list index out of bounds for Int list (index 1, length 0)",
107 );
108 assert_eq!(
109 nested.into_kind(),
110 super::HostCallErrorKind::Nested(execution),
111 );
112 }
113}