1use std::ffi::{CStr, CString};
4use std::fmt;
5use std::sync::Arc;
6
7pub type Result<T, E = Error> = std::result::Result<T, E>;
9
10#[derive(Debug, Clone)]
12#[non_exhaustive]
13pub enum Error {
14 Java(JavaException),
16 Graal(i32),
19 InvalidArgument(String),
21 ShutDown,
23 InCallback,
25 Timeout,
27 IsolateCreated,
30 Io(Arc<std::io::Error>),
33}
34
35impl fmt::Display for Error {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 match self {
38 Error::Java(e) => e.fmt(f),
39 Error::Graal(code) => write!(f, "GraalVM isolate error {code}"),
40 Error::InvalidArgument(what) => write!(f, "invalid argument: {what}"),
41 Error::ShutDown => f.write_str("the SDK has been shut down"),
42 Error::InCallback => f.write_str("the call is not allowed inside an event listener"),
43 Error::Timeout => f.write_str("the wait timed out"),
44 Error::IsolateCreated => f.write_str("the isolate has already been created"),
45 Error::Io(_) => f.write_str("the output failed"),
46 }
47 }
48}
49
50impl std::error::Error for Error {
51 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
52 match self {
53 Error::Java(e) => e.source(),
54 Error::Io(e) => Some(&**e),
55 _ => None,
56 }
57 }
58}
59
60#[derive(Debug, Clone)]
62pub struct JavaException {
63 class_name: String,
64 message: String,
65 stack_trace: String,
66 cause: Option<Box<JavaException>>,
67}
68
69impl JavaException {
70 pub(crate) fn new(class_name: String, message: String, stack_trace: String, cause: Option<Box<Self>>) -> Self {
71 JavaException {
72 class_name,
73 message,
74 stack_trace,
75 cause,
76 }
77 }
78
79 pub(crate) fn from_message(message: &str) -> Self {
81 Self::new(String::new(), message.to_owned(), String::new(), None)
82 }
83
84 pub(crate) fn null_result() -> Self {
86 Self::from_message("the SDK returned NULL")
87 }
88
89 pub(crate) fn lost() -> Self {
91 Self::from_message("exception lost")
92 }
93
94 pub fn get_class_name(&self) -> &str {
96 &self.class_name
97 }
98
99 pub fn get_message(&self) -> &str {
101 &self.message
102 }
103
104 pub fn get_stack_trace(&self) -> &str {
106 &self.stack_trace
107 }
108
109 pub fn get_cause(&self) -> Option<&JavaException> {
111 self.cause.as_deref()
112 }
113}
114
115impl fmt::Display for JavaException {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 match (self.class_name.is_empty(), self.message.is_empty()) {
118 (false, false) => write!(f, "{}: {}", self.class_name, self.message),
119 (false, true) => f.write_str(&self.class_name),
120 _ => f.write_str(&self.message),
121 }
122 }
123}
124
125impl std::error::Error for JavaException {
126 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
127 self.cause.as_deref().map(|c| c as _)
128 }
129}
130
131#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
134#[non_exhaustive]
135pub enum JavaExceptionClass {
136 RuntimeException,
138 IllegalArgumentException,
140 IllegalStateException,
142 UnsupportedOperationException,
144 IOException,
146 CancellationException,
150 TimeoutException,
152}
153
154impl JavaExceptionClass {
155 pub fn get_name(self) -> &'static str {
157 match self {
158 JavaExceptionClass::RuntimeException => "java.lang.RuntimeException",
159 JavaExceptionClass::IllegalArgumentException => "java.lang.IllegalArgumentException",
160 JavaExceptionClass::IllegalStateException => "java.lang.IllegalStateException",
161 JavaExceptionClass::UnsupportedOperationException => "java.lang.UnsupportedOperationException",
162 JavaExceptionClass::IOException => "java.io.IOException",
163 JavaExceptionClass::CancellationException => "java.util.concurrent.CancellationException",
164 JavaExceptionClass::TimeoutException => "java.util.concurrent.TimeoutException",
165 }
166 }
167
168 pub(crate) fn c_name(self) -> &'static CStr {
170 match self {
171 JavaExceptionClass::RuntimeException => c"java.lang.RuntimeException",
172 JavaExceptionClass::IllegalArgumentException => c"java.lang.IllegalArgumentException",
173 JavaExceptionClass::IllegalStateException => c"java.lang.IllegalStateException",
174 JavaExceptionClass::UnsupportedOperationException => c"java.lang.UnsupportedOperationException",
175 JavaExceptionClass::IOException => c"java.io.IOException",
176 JavaExceptionClass::CancellationException => c"java.util.concurrent.CancellationException",
177 JavaExceptionClass::TimeoutException => c"java.util.concurrent.TimeoutException",
178 }
179 }
180}
181
182impl fmt::Display for JavaExceptionClass {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 f.write_str(self.get_name())
185 }
186}
187
188pub(crate) fn list_size(count: usize, what: &str) -> Result<i32> {
190 i32::try_from(count).map_err(|_| Error::InvalidArgument(format!("too many {what}: {count}")))
191}
192
193pub(crate) fn c_string(s: &str, what: &str) -> Result<CString> {
195 CString::new(s).map_err(|_| Error::InvalidArgument(format!("{what} contains a NUL byte")))
196}