]> git.proxmox.com Git - perlmod.git/blame - perlmod/src/ffi.rs
drop thiserror
[perlmod.git] / perlmod / src / ffi.rs
CommitLineData
7a433bb6 1//! Unsafe ffi code.
f7cc8c37
WB
2//!
3//! You should not use this code directly. This is used by the binding generator to implement xsubs
4//! for exported functions.
5
8a062e94 6/// Raw perl subroutine pointer value. This should not be used directly.
f7cc8c37
WB
7#[repr(C)]
8pub struct CV {
9 _ffi: usize,
10}
11
8a062e94 12/// Raw scalar-ish perl value. This should not be used directly.
f7cc8c37
WB
13#[repr(C)]
14pub struct SV {
15 _ffi: usize,
16}
17
8a062e94 18/// Raw perl array value. This should not be used directly.
f7cc8c37
WB
19#[repr(C)]
20pub struct AV {
21 _ffi: usize,
22}
23
8a062e94 24/// Raw perl hash value. This should not be used directly.
f7cc8c37
WB
25#[repr(C)]
26pub struct HV {
27 _ffi: usize,
28}
29
8a062e94 30/// Raw perl hash entry iterator. This should not be used directly.
f7cc8c37
WB
31#[repr(C)]
32pub struct HE {
33 _ffi: usize,
34}
35
36// in our glue:
37#[link(name = "glue", kind = "static")]
38extern "C" {
39 pub fn RSPL_StackMark_count(this: usize) -> usize;
40
41 pub fn RSPL_stack_get(offset: usize) -> *mut SV;
42
43 pub fn RSPL_croak_sv(sv: *mut SV) -> !;
44 pub fn RSPL_SvNV(sv: *mut SV) -> f64;
45 pub fn RSPL_SvIV(sv: *mut SV) -> isize;
46 pub fn RSPL_SvPVutf8(sv: *mut SV, len: *mut libc::size_t) -> *const libc::c_char;
47 pub fn RSPL_SvPV(sv: *mut SV, len: *mut libc::size_t) -> *const libc::c_char;
83147b11 48 /// This calls `sv_utf8_downgrade` first to avoid croaking, instead returns `NULL` on error.
f7cc8c37
WB
49 pub fn RSPL_SvPVbyte(sv: *mut SV, len: *mut libc::size_t) -> *const libc::c_char;
50 pub fn RSPL_sv_2mortal(sv: *mut SV) -> *mut SV;
51 pub fn RSPL_get_undef() -> *mut SV;
52 pub fn RSPL_get_yes() -> *mut SV;
53 pub fn RSPL_get_no() -> *mut SV;
54 pub fn RSPL_pop_markstack_ptr() -> usize;
55 pub fn RSPL_stack_resize_by(count: isize);
56 pub fn RSPL_stack_shrink_to(count: usize);
57 pub fn RSPL_stack_sp() -> *mut *mut SV;
58 pub fn RSPL_newRV_inc(sv: *mut SV) -> *mut SV;
59 pub fn RSPL_newSViv(v: isize) -> *mut SV;
60 pub fn RSPL_newSVuv(v: usize) -> *mut SV;
61 pub fn RSPL_newSVnv(v: f64) -> *mut SV;
62 pub fn RSPL_newSVpvn(v: *const libc::c_char, len: libc::size_t) -> *mut SV;
3f791730 63 pub fn RSPL_newSVpvn_utf8(v: *const libc::c_char, len: libc::size_t) -> *mut SV;
f7cc8c37
WB
64 pub fn RSPL_SvREFCNT_inc(sv: *mut SV) -> *mut SV;
65 pub fn RSPL_SvREFCNT_dec(sv: *mut SV);
66 pub fn RSPL_is_reference(sv: *mut SV) -> bool;
67 pub fn RSPL_dereference(sv: *mut SV) -> *mut SV;
68 pub fn RSPL_is_array(sv: *mut SV) -> bool;
69 pub fn RSPL_is_hash(sv: *mut SV) -> bool;
70 pub fn RSPL_type_flags(sv: *mut SV) -> u32;
71 pub fn RSPL_svtype(sv: *mut SV) -> u32;
b5c53f3d 72 pub fn RSPL_SvOK(sv: *mut SV) -> bool;
9acdb782 73 pub fn RSPL_SvANY(sv: *mut SV) -> bool;
f7cc8c37
WB
74 pub fn RSPL_SvTRUE(sv: *mut SV) -> bool;
75
9acdb782
WB
76 pub fn RSPL_is_defined(sv: *mut SV) -> bool;
77
f7cc8c37
WB
78 pub fn RSPL_newAV() -> *mut AV;
79 pub fn RSPL_av_extend(av: *mut AV, len: libc::ssize_t);
80 pub fn RSPL_av_push(av: *mut AV, sv: *mut SV);
81 pub fn RSPL_av_pop(av: *mut AV) -> *mut SV;
82 pub fn RSPL_av_len(av: *mut AV) -> usize;
83 pub fn RSPL_av_fetch(av: *mut AV, index: libc::ssize_t, lval: i32) -> *mut *mut SV;
84
85 pub fn RSPL_newHV() -> *mut HV;
86 pub fn RSPL_HvTOTALKEYS(hv: *mut HV) -> usize;
87 pub fn RSPL_hv_fetch(
88 hv: *mut HV,
89 key: *const libc::c_char,
90 klen: i32,
91 lval: i32,
92 ) -> *mut *mut SV;
93 /// Always consumes ownership of `value`.
94 pub fn RSPL_hv_store(hv: *mut HV, key: *const libc::c_char, klen: i32, value: *mut SV) -> bool;
95 pub fn RSPL_hv_store_ent(hv: *mut HV, key: *mut SV, value: *mut SV) -> bool;
96 pub fn RSPL_hv_iterinit(hv: *mut HV);
97 pub fn RSPL_hv_iternextsv(
98 hv: *mut HV,
99 key: *mut *mut libc::c_char,
100 retlen: *mut i32,
101 ) -> *mut SV;
102 pub fn RSPL_hv_iternext(hv: *mut HV) -> *mut HE;
103 pub fn RSPL_hv_iterkeysv(he: *mut HE) -> *mut SV;
104 pub fn RSPL_hv_iterval(hv: *mut HV, he: *mut HE) -> *mut SV;
87c10237
WB
105
106 pub fn RSPL_gv_stashsv(name: *const SV, flags: i32) -> *mut HV;
107 pub fn RSPL_sv_bless(sv: *mut SV, stash: *mut HV) -> *mut SV;
ccde914a
WB
108
109 pub fn RSPL_ENTER();
110 pub fn RSPL_SAVETMPS();
111 pub fn RSPL_FREETMPS();
112 pub fn RSPL_LEAVE();
89989b0f
WB
113
114 pub fn RSPL_sv_reftype(sv: *const SV, ob: libc::c_int) -> *const libc::c_char;
61143f5d
WB
115
116 pub fn RSPL_PVLV() -> u32;
117 pub fn RSPL_LvTARG(sv: *mut SV) -> *mut SV;
b5c53f3d 118 //pub fn RSPL_LvTYPE(sv: *mut SV) -> u8;
61143f5d 119 pub fn RSPL_vivify_defelem(sv: *mut SV);
b5c53f3d 120
9acdb782 121 //pub fn RSPL_SvFLAGS(sv: *mut SV) -> u32;
b5c53f3d 122 pub fn RSPL_SvGETMAGIC(sv: *mut SV) -> bool;
f7cc8c37
WB
123}
124
125/// Argument marker for the stack.
126pub struct StackMark(usize);
127
128impl StackMark {
129 pub fn count(&self) -> usize {
130 unsafe { RSPL_StackMark_count(self.0) }
131 }
132
133 pub fn iter(&self) -> StackIter {
134 StackIter {
135 at: self.0 + 1,
136 end: self.0 + 1 + self.count(),
137 }
138 }
139
f0475cd5
WB
140 /// Shrink the perl stack to this mark.
141 ///
142 /// # Safety
143 ///
144 /// This is only valid if the mark is still valid (smaller than `PL_stack_sp`) and all values
145 /// still remaining on the stack are mortal (which should normally be the case anyway).
f7cc8c37
WB
146 pub unsafe fn set_stack(self) {
147 RSPL_stack_shrink_to(self.0);
148 }
149}
150
8a062e94 151/// Iterator over the stack up to the [`StackMark`].
f7cc8c37
WB
152pub struct StackIter {
153 at: usize,
154 end: usize,
155}
156
157impl Iterator for StackIter {
158 type Item = crate::Scalar;
159
160 fn next(&mut self) -> Option<Self::Item> {
161 let at = self.at;
162 if at == self.end {
163 return None;
164 }
165 unsafe {
166 let ptr = RSPL_stack_get(self.at);
167 self.at += 1;
168 if ptr.is_null() {
169 None
170 } else {
171 Some(crate::Scalar::from_raw_ref(ptr))
172 }
173 }
174 }
175}
176
f0475cd5
WB
177/// Pop the current argument marker off of the argument marker stack.
178///
179/// # Safety
180///
181/// Read up on `PL_markstack_ptr` in perlguts. This is equivalent to `*PL_markstack_ptr--` in C.
f7cc8c37
WB
182pub unsafe fn pop_arg_mark() -> StackMark {
183 StackMark(RSPL_pop_markstack_ptr())
184}
185
f0475cd5
WB
186/// Push a value to the stack.
187///
188/// # Safety
189///
190/// Read up on mortals and the stack and when it is legal to put a value onto it. Typically a
191/// mortal value with no more references to it to avoid leaking if they aren't used later on.
f7cc8c37
WB
192pub unsafe fn stack_push_raw(value: *mut SV) {
193 RSPL_stack_resize_by(1);
194 *RSPL_stack_sp() = value;
195}
196
197pub fn stack_push(value: crate::Mortal) {
198 unsafe {
199 stack_push_raw(value.into_raw());
200 }
201}
202
f0475cd5
WB
203/// This calls perl's `croak_sv`.
204///
205/// # Safety
206///
207/// This seems to perform a `longjmp` and is thus never truly safe in rust code. You really want to
208/// limit this to the top entry point of your rust call stack in a separate `extern "C" fn` where
209/// no rust values with `Drop` handlers or anything similar are active.
210///
211/// The `perlmod_macro`'s `export` attribute typically creates 2 wrapper functions of the form:
212///
213/// ```no_run
214/// # use serde::Serialize;
215///
216/// # #[derive(Serialize)]
217/// # struct Output;
218///
219/// # fn code_to_extract_parameters() {}
893f7299 220/// # fn actual_rust_function(_arg: ()) -> Result<Output, String> { Ok(Output) }
f0475cd5
WB
221/// #[no_mangle]
222/// pub extern "C" fn exported_name(cv: &::perlmod::ffi::CV) {
223/// unsafe {
224/// match private_implementation_name(cv) {
225/// Ok(sv) => ::perlmod::ffi::stack_push_raw(sv),
226/// Err(sv) => ::perlmod::ffi::croak(sv),
227/// }
228/// }
229/// }
230///
231/// #[inline(never)]
232/// fn private_implementation_name(
233/// _cv: &::perlmod::ffi::CV,
234/// ) -> Result<*mut ::perlmod::ffi::SV, *mut ::perlmod::ffi::SV> {
235/// let args = code_to_extract_parameters();
236/// // ...
237/// let result = match actual_rust_function(args) {
238/// Ok(output) => output,
239/// Err(err) => {
240/// return Err(::perlmod::Value::new_string(&err.to_string())
241/// .into_mortal()
242/// .into_raw());
243/// }
244/// };
245///
246/// match ::perlmod::to_value(&result) {
247/// Ok(value) => Ok(value.into_mortal().into_raw()),
248/// Err(err) => Err(::perlmod::Value::new_string(&err.to_string())
249/// .into_mortal()
250/// .into_raw()),
251/// }
252/// }
253/// ```
254pub unsafe fn croak(sv: *mut SV) -> ! {
f7cc8c37
WB
255 RSPL_croak_sv(sv);
256}
ccde914a
WB
257
258/// Create a pseudo-block for mortals & temps to be freed after it.
259/// This calls `ENTER; SAVETMPS;` before and `FREETMPS; LEAVE;` after the provided closure.
260pub fn pseudo_block<F, R>(func: F) -> R
261where
262 F: FnOnce() -> R,
263{
264 unsafe {
265 RSPL_ENTER();
266 RSPL_SAVETMPS();
267 }
268
269 let res = func();
270
271 unsafe {
272 RSPL_FREETMPS();
273 RSPL_LEAVE();
274 }
275
276 res
277}