1use crate::derive::{Object, ObjectRef};
20use crate::object::{self, Object, ObjectArc, ObjectRefCore};
21use std::ffi::c_void;
22use tvm_ffi_sys::TVMFFIBacktraceUpdateMode::kTVMFFIBacktraceUpdateModeAppend;
23use tvm_ffi_sys::{
24 TVMFFIByteArray, TVMFFIErrorCell, TVMFFIErrorCreateWithCauseAndExtraContext,
25 TVMFFIErrorMoveFromRaised, TVMFFIErrorSetRaised, TVMFFIObjectHandle, TVMFFITypeIndex,
26};
27
28#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct ErrorKind<'a>(&'a str);
31
32impl<'a> ErrorKind<'a> {
33 pub fn as_str(&self) -> &str {
34 self.0
35 }
36}
37
38impl<'a> std::fmt::Display for ErrorKind<'a> {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 write!(f, "{}", self.0)
41 }
42}
43
44pub const VALUE_ERROR: ErrorKind = ErrorKind("ValueError");
45pub const TYPE_ERROR: ErrorKind = ErrorKind("TypeError");
46pub const RUNTIME_ERROR: ErrorKind = ErrorKind("RuntimeError");
47pub const ATTRIBUTE_ERROR: ErrorKind = ErrorKind("AttributeError");
48pub const KEY_ERROR: ErrorKind = ErrorKind("KeyError");
49pub const INDEX_ERROR: ErrorKind = ErrorKind("IndexError");
50pub const INTERNAL_ERROR: ErrorKind = ErrorKind("InternalError");
51
52#[repr(C)]
54#[derive(Object)]
55#[type_key = "ffi.Error"]
56#[type_index(TVMFFITypeIndex::kTVMFFIError)]
57pub struct ErrorObj {
58 object: Object,
59 cell: TVMFFIErrorCell,
60}
61
62#[derive(Clone, ObjectRef)]
64pub struct Error {
65 data: ObjectArc<ErrorObj>,
66}
67
68pub type Result<T, E = Error> = std::result::Result<T, E>;
70
71impl Error {
72 pub fn new(kind: ErrorKind<'_>, message: &str, traceback: &str) -> Self {
73 Self::new_with_cause_and_extra_context(kind, message, traceback, None, None)
74 }
75
76 pub fn new_with_cause_and_extra_context(
78 kind: ErrorKind<'_>,
79 message: &str,
80 traceback: &str,
81 cause_chain: Option<&Error>,
82 extra_context: Option<&object::ObjectRef>,
83 ) -> Self {
84 unsafe {
85 let kind_data = TVMFFIByteArray::from_str(kind.as_str());
86 let message_data = TVMFFIByteArray::from_str(message);
87 let traceback_data = TVMFFIByteArray::from_str(traceback);
88 let mut error_handle: TVMFFIObjectHandle = std::ptr::null_mut();
89 let ret = TVMFFIErrorCreateWithCauseAndExtraContext(
90 &kind_data,
91 &message_data,
92 &traceback_data,
93 cause_chain.map_or(std::ptr::null_mut(), |cause| {
94 ObjectArc::as_raw(&cause.data) as TVMFFIObjectHandle
95 }),
96 extra_context.map_or(std::ptr::null_mut(), |context| {
97 ObjectArc::as_raw(object::ObjectRef::data(context)) as TVMFFIObjectHandle
98 }),
99 &mut error_handle,
100 );
101 assert_eq!(ret, 0, "Failed to create error object");
102 let error_obj = ObjectArc::from_raw(error_handle as *const ErrorObj);
103 Self { data: error_obj }
104 }
105 }
106
107 pub fn from_raised() -> Self {
112 unsafe {
113 let mut error_handle: TVMFFIObjectHandle = std::ptr::null_mut();
114 TVMFFIErrorMoveFromRaised(&mut error_handle as *mut TVMFFIObjectHandle);
115 assert!(
116 !error_handle.is_null(),
117 "Calling Error::from_raised but no error was raised"
118 );
119 let error_obj = ObjectArc::from_raw(error_handle as *const ErrorObj);
120 Self { data: error_obj }
121 }
122 }
123
124 pub fn set_raised(error: &Self) {
129 unsafe {
130 TVMFFIErrorSetRaised(ObjectArc::as_raw(&error.data) as TVMFFIObjectHandle);
131 }
132 }
133
134 pub fn kind(&self) -> ErrorKind<'_> {
139 ErrorKind(&self.data.cell.kind.as_str())
140 }
141
142 pub fn message(&self) -> &str {
147 self.data.cell.message.as_str()
148 }
149
150 pub fn backtrace(&self) -> &str {
155 self.data.cell.backtrace.as_str()
156 }
157
158 pub fn cause_chain(&self) -> Option<Error> {
160 let handle = self.data.cell.cause_chain;
161 if handle.is_null() {
162 return None;
163 }
164 unsafe {
166 object::unsafe_::inc_ref(handle.cast());
167 Some(Self {
168 data: ObjectArc::from_raw(handle.cast()),
169 })
170 }
171 }
172
173 pub fn extra_context(&self) -> Option<object::ObjectRef> {
175 let handle = self.data.cell.extra_context;
176 if handle.is_null() {
177 return None;
178 }
179 unsafe {
180 object::unsafe_::inc_ref(handle.cast());
181 Some(object::ObjectRef::from_data(ObjectArc::from_raw(
182 handle.cast(),
183 )))
184 }
185 }
186
187 pub fn traceback_most_recent_call_last(&self) -> String {
192 let backtrace = self.backtrace();
193 let backtrace_lines = backtrace.split('\n');
194 let mut traceback = String::new();
195 for line in backtrace_lines.rev() {
196 traceback.push_str(line);
197 traceback.push('\n');
198 }
199 traceback
200 }
201
202 pub fn with_appended_backtrace(this: Self, backtrace: &str) -> Self {
211 if ObjectArc::strong_count(&this.data) == 1 {
212 unsafe {
215 let backtrace_data = TVMFFIByteArray::from_str(backtrace);
216 (this.data.cell.update_backtrace)(
217 ObjectArc::as_raw(&this.data) as *mut ErrorObj as *mut c_void,
218 &backtrace_data,
219 kTVMFFIBacktraceUpdateModeAppend as i32,
220 );
221 this
222 }
223 } else {
224 let mut new_backtrace = String::new();
227 new_backtrace.push_str(this.backtrace());
228 new_backtrace.push_str(backtrace);
229 Self::new_with_cause_and_extra_context(
230 this.kind(),
231 this.message(),
232 &new_backtrace,
233 this.cause_chain().as_ref(),
234 this.extra_context().as_ref(),
235 )
236 }
237 }
238}
239
240impl std::fmt::Display for Error {
241 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
242 write!(
243 f,
244 "Traceback (most recent call last):\n{}{}: {}",
245 self.traceback_most_recent_call_last(),
246 self.kind().as_str(),
247 self.message()
248 )
249 }
250}
251
252impl std::fmt::Debug for Error {
253 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
254 std::fmt::Display::fmt(self, f)
255 }
256}
257
258impl std::error::Error for Error {}