-
-
Notifications
You must be signed in to change notification settings - Fork 77
/
Copy pathutils.rs
136 lines (116 loc) · 3.63 KB
/
utils.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use std::cell::RefCell;
use std::mem;
use std::panic;
use std::thread;
type Error = Box<dyn std::error::Error + 'static>;
thread_local! {
pub static LAST_ERROR: RefCell<Option<Error>> = RefCell::new(None);
}
pub trait ForeignObject: Sized {
type RustObject;
#[inline]
unsafe fn from_rust(object: Self::RustObject) -> *mut Self {
Box::into_raw(Box::new(object)) as *mut Self
}
#[inline]
unsafe fn from_ref(object: &Self::RustObject) -> *const Self {
object as *const Self::RustObject as *const Self
}
#[inline]
#[allow(clippy::wrong_self_convention)]
unsafe fn as_rust<'a>(pointer: *const Self) -> &'a Self::RustObject {
&*(pointer as *const Self::RustObject)
}
#[inline]
#[allow(clippy::wrong_self_convention)]
unsafe fn as_rust_mut<'a>(pointer: *mut Self) -> &'a mut Self::RustObject {
&mut *(pointer as *mut Self::RustObject)
}
#[inline]
#[allow(clippy::wrong_self_convention)]
unsafe fn into_rust(pointer: *mut Self) -> Box<Self::RustObject> {
Box::from_raw(pointer as *mut Self::RustObject)
}
#[inline]
unsafe fn drop(pointer: *mut Self) {
if !pointer.is_null() {
drop(Self::into_rust(pointer));
}
}
}
/// An error thrown by `landingpad` in place of panics.
#[derive(Debug)]
pub struct Panic(String);
impl std::fmt::Display for Panic {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "symbolic panicked: {}", self.0)
}
}
impl std::error::Error for Panic {}
fn set_last_error(err: Error) {
LAST_ERROR.with(|e| {
*e.borrow_mut() = Some(err);
});
}
pub unsafe fn set_panic_hook() {
panic::set_hook(Box::new(|info| {
let thread = thread::current();
let thread = thread.name().unwrap_or("unnamed");
let message = match info.payload().downcast_ref::<&str>() {
Some(s) => *s,
None => match info.payload().downcast_ref::<String>() {
Some(s) => &**s,
None => "Box<Any>",
},
};
let description = match info.location() {
Some(location) => format!(
"thread '{}' panicked with '{}' at {}:{}",
thread,
message,
location.file(),
location.line()
),
None => format!("thread '{}' panicked with '{}'", thread, message),
};
set_last_error(Panic(description).into())
}));
}
pub unsafe fn landingpad<F, T>(f: F) -> T
where
F: FnOnce() -> Result<T, Error> + panic::UnwindSafe,
{
match panic::catch_unwind(f) {
Ok(Ok(result)) => result,
Ok(Err(err)) => {
set_last_error(err);
mem::zeroed()
}
Err(_) => mem::zeroed(),
}
}
macro_rules! ffi_fn {
// a function that catches patnics and returns a result (err goes to tls)
(
$(#[$attr:meta])*
unsafe fn $name:ident($($aname:ident: $aty:ty),* $(,)*) -> Result<$rv:ty> $body:block
) => {
#[no_mangle]
$(#[$attr])*
pub unsafe extern "C" fn $name($($aname: $aty,)*) -> $rv {
$crate::utils::landingpad(|| $body)
}
};
// a function that catches patnics and returns nothing (err goes to tls)
(
$(#[$attr:meta])*
unsafe fn $name:ident($($aname:ident: $aty:ty),* $(,)*) $body:block
) => {
#[no_mangle]
$(#[$attr])*
pub unsafe extern "C" fn $name($($aname: $aty,)*) {
// this silences panics and stuff
$crate::utils::landingpad(|| { $body; Ok(0 as std::os::raw::c_int) });
}
};
}