1use std::str::Utf8Error;
16
17use arrow_schema::ArrowError;
18use jni::{errors::Error as JniError, JNIEnv};
19use lance::error::Error as LanceError;
20use serde_json::Error as JsonError;
21
22#[derive(Debug, PartialEq, Eq)]
23pub enum JavaExceptionClass {
24 IllegalArgumentException,
25 IOException,
26 RuntimeException,
27 UnsupportedOperationException,
28 AlreadyInException,
29}
30
31impl JavaExceptionClass {
32 pub fn as_str(&self) -> &str {
33 match self {
34 Self::IllegalArgumentException => "java/lang/IllegalArgumentException",
35 Self::IOException => "java/io/IOException",
36 Self::RuntimeException => "java/lang/RuntimeException",
37 Self::UnsupportedOperationException => "java/lang/UnsupportedOperationException",
38 Self::AlreadyInException => "AlreadyInException",
40 }
41 }
42}
43
44#[derive(Debug)]
45pub struct Error {
46 message: String,
47 java_class: JavaExceptionClass,
48}
49
50impl Error {
51 pub fn new(message: String, java_class: JavaExceptionClass) -> Self {
52 Self {
53 message,
54 java_class,
55 }
56 }
57
58 pub fn runtime_error(message: String) -> Self {
59 Self {
60 message,
61 java_class: JavaExceptionClass::RuntimeException,
62 }
63 }
64
65 pub fn io_error(message: String) -> Self {
66 Self::new(message, JavaExceptionClass::IOException)
67 }
68
69 pub fn input_error(message: String) -> Self {
70 Self::new(message, JavaExceptionClass::IllegalArgumentException)
71 }
72
73 pub fn unsupported_error(message: String) -> Self {
74 Self::new(message, JavaExceptionClass::UnsupportedOperationException)
75 }
76
77 pub fn in_exception() -> Self {
78 Self {
79 message: String::default(),
80 java_class: JavaExceptionClass::AlreadyInException,
81 }
82 }
83
84 pub fn throw(&self, env: &mut JNIEnv) {
85 if self.java_class == JavaExceptionClass::AlreadyInException {
86 return;
88 }
89 if let Err(e) = env.throw_new(self.java_class.as_str(), &self.message) {
90 eprintln!("Error when throwing Java exception: {:?}", e.to_string());
91 panic!("Error when throwing Java exception: {:?}", e);
92 }
93 }
94}
95
96pub type Result<T> = std::result::Result<T, Error>;
97
98impl std::fmt::Display for Error {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 write!(f, "{}: {}", self.java_class.as_str(), self.message)
101 }
102}
103
104impl From<LanceError> for Error {
105 fn from(err: LanceError) -> Self {
106 match err {
107 LanceError::DatasetNotFound { .. }
108 | LanceError::DatasetAlreadyExists { .. }
109 | LanceError::CommitConflict { .. }
110 | LanceError::InvalidInput { .. } => Self::input_error(err.to_string()),
111 LanceError::IO { .. } => Self::io_error(err.to_string()),
112 LanceError::NotSupported { .. } => Self::unsupported_error(err.to_string()),
113 LanceError::NotFound { .. } => Self::io_error(err.to_string()),
114 _ => Self::runtime_error(err.to_string()),
115 }
116 }
117}
118
119impl From<ArrowError> for Error {
120 fn from(err: ArrowError) -> Self {
121 match err {
122 ArrowError::InvalidArgumentError { .. } => Self::input_error(err.to_string()),
123 ArrowError::IoError { .. } => Self::io_error(err.to_string()),
124 ArrowError::NotYetImplemented(_) => Self::unsupported_error(err.to_string()),
125 _ => Self::runtime_error(err.to_string()),
126 }
127 }
128}
129
130impl From<JsonError> for Error {
131 fn from(err: JsonError) -> Self {
132 Self::io_error(err.to_string())
133 }
134}
135
136impl From<JniError> for Error {
137 fn from(err: JniError) -> Self {
138 match err {
139 JniError::JavaException => Self::in_exception(),
142 _ => Self::runtime_error(err.to_string()),
143 }
144 }
145}
146
147impl From<Utf8Error> for Error {
148 fn from(err: Utf8Error) -> Self {
149 Self::input_error(err.to_string())
150 }
151}