]> git.proxmox.com Git - perlmod.git/blame - perlmod/src/ffi.rs
clippy fixes
[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
6f26c2da
WB
36/// Raw perl MAGIC struct, we don't actually make its contents available.
37#[repr(C)]
38pub struct MAGIC {
39 _ffi: usize,
40}
41
e5a46a38 42#[allow(clippy::len_without_is_empty)]
6f26c2da
WB
43impl MAGIC {
44 pub fn vtbl(&self) -> Option<&MGVTBL> {
45 unsafe { RSPL_MAGIC_virtual(self as *const MAGIC).as_ref() }
46 }
47
48 pub fn ptr(&self) -> *const libc::c_char {
49 unsafe { RSPL_MAGIC_ptr(self as *const MAGIC) }
50 }
51
52 pub fn len(&self) -> isize {
53 unsafe { RSPL_MAGIC_len(self as *const MAGIC) }
54 }
55}
56
1e46bfbe
WB
57#[repr(C)]
58pub struct Unsupported {
59 _ffi: usize,
60}
61
62#[cfg(perlmod = "multiplicity")]
63#[repr(C)]
64pub struct Interpreter {
65 _ffi: usize,
66}
67
68#[cfg(perlmod = "multiplicity")]
69mod vtbl_types_impl {
70 use super::{Interpreter, MAGIC, SV};
71 use libc::c_int;
72
73 pub type Get = extern "C" fn(_perl: *const Interpreter, sv: *mut SV, mg: *mut MAGIC) -> c_int;
74 pub type Set = extern "C" fn(_perl: *const Interpreter, sv: *mut SV, mg: *mut MAGIC) -> c_int;
75 pub type Len = extern "C" fn(_perl: *const Interpreter, sv: *mut SV, mg: *mut MAGIC) -> u32;
76 pub type Clear = extern "C" fn(_perl: *const Interpreter, sv: *mut SV, mg: *mut MAGIC) -> c_int;
77 pub type Free = extern "C" fn(_perl: *const Interpreter, sv: *mut SV, mg: *mut MAGIC) -> c_int;
78 pub type Copy = extern "C" fn(
79 _perl: *const Interpreter,
80 sv: *mut SV,
81 mg: *mut MAGIC,
82 nsv: *mut SV,
83 name: *const libc::c_char,
84 namelen: i32,
85 ) -> c_int;
86 pub type Dup = extern "C" fn(
87 _perl: *const Interpreter,
88 sv: *mut SV,
89 mg: *mut MAGIC,
90 clone_parms: *mut super::Unsupported,
91 ) -> c_int;
92 pub type Local = extern "C" fn(_perl: *const Interpreter, sv: *mut SV, mg: *mut MAGIC) -> c_int;
93
94 #[macro_export]
95 macro_rules! perl_fn {
96 ($(
97 $(#[$attr:meta])*
98 extern "C" fn $name:ident ($($args:tt)*) $(-> $re:ty)? {
99 $($code:tt)*
100 }
101 )*) => {$(
102 $(#[$attr])*
103 extern "C" fn $name (_perl: *const $crate::ffi::Interpreter, $($args)*) $(-> $re)? {
104 $($code)*
105 }
106 )*};
107 }
108}
109
110#[cfg(not(perlmod = "multiplicity"))]
111mod vtbl_types_impl {
112 use super::{Interpreter, MAGIC, SV};
113 use libc::c_int;
114
115 pub type Get = extern "C" fn(sv: *mut SV, mg: *mut MAGIC) -> c_int;
116 pub type Set = extern "C" fn(sv: *mut SV, mg: *mut MAGIC) -> c_int;
117 pub type Len = extern "C" fn(sv: *mut SV, mg: *mut MAGIC) -> u32;
118 pub type Clear = extern "C" fn(sv: *mut SV, mg: *mut MAGIC) -> c_int;
119 pub type Free = extern "C" fn(sv: *mut SV, mg: *mut MAGIC) -> c_int;
120 pub type Copy = extern "C" fn(
121 sv: *mut SV,
122 mg: *mut MAGIC,
123 nsv: *mut SV,
124 name: *const libc::c_char,
125 namelen: i32,
126 ) -> c_int;
127 pub type Dup =
128 extern "C" fn(sv: *mut SV, mg: *mut MAGIC, clone_parms: *mut super::Unsupported) -> c_int;
129 pub type Local = extern "C" fn(sv: *mut SV, mg: *mut MAGIC) -> c_int;
130
131 #[macro_export]
132 macro_rules! perl_fn {
133 ($(
134 $(#[$attr:meta])*
135 extern "C" fn $name:ident ($($args:tt)*) $(-> $re:ty)? {
136 $($code:tt)*
137 }
138 )*) => {$(
139 $(#[$attr])*
140 extern "C" fn $name ($($args)*) $(-> $re)? {
141 $($code)*
142 }
143 )*};
144 }
145}
146
147/// The types in this module depend on the configuration of your perl installation.
148///
149/// If the perl interpreter has been compiled with `USEMULTIPLICITY`, these methods have an
150/// additional parameter.
151pub mod vtbl_types {
152 pub use super::vtbl_types_impl::*;
153}
154
155#[derive(Clone, Copy)]
6f26c2da
WB
156#[repr(C)]
157pub struct MGVTBL {
1e46bfbe
WB
158 pub get: Option<vtbl_types::Get>,
159 pub set: Option<vtbl_types::Set>,
160 pub len: Option<vtbl_types::Len>,
161 pub clear: Option<vtbl_types::Clear>,
162 pub free: Option<vtbl_types::Free>,
163 pub copy: Option<vtbl_types::Copy>,
164 pub dup: Option<vtbl_types::Dup>,
165 pub local: Option<vtbl_types::Local>,
6f26c2da
WB
166}
167
168impl MGVTBL {
1e46bfbe
WB
169 /// Let's not expose this directly, we need there to be distinct instances of these, so they
170 /// should be created via `MGVTBL::zero()`.
171 const EMPTY: Self = Self {
172 get: None,
173 set: None,
174 len: None,
175 clear: None,
176 free: None,
177 copy: None,
178 dup: None,
179 local: None,
180 };
181
6f26c2da
WB
182 /// Create a new all-zeroes vtbl as perl docs suggest this is the safest way to
183 /// make sure what a `PERL_MAGIC_ext` magic actually means, as the ptr value
184 /// may be arbitrary.
185 ///
186 /// # Safety
187 ///
188 /// This must not be deallocated as long as it is attached to a perl value, so best use this as
189 /// `const` variables, rather than dynamically allocating it.
190 pub const fn zero() -> Self {
e5a46a38 191 Self::EMPTY
6f26c2da
WB
192 }
193}
194
f7cc8c37
WB
195// in our glue:
196#[link(name = "glue", kind = "static")]
197extern "C" {
198 pub fn RSPL_StackMark_count(this: usize) -> usize;
199
200 pub fn RSPL_stack_get(offset: usize) -> *mut SV;
201
202 pub fn RSPL_croak_sv(sv: *mut SV) -> !;
83f19b95
WB
203
204 pub fn RSPL_newXS_flags(
205 name: *const i8,
206 subaddr: *const i8,
207 filename: *const i8,
208 proto: *const i8,
209 flags: u32,
210 );
211
f7cc8c37
WB
212 pub fn RSPL_SvNV(sv: *mut SV) -> f64;
213 pub fn RSPL_SvIV(sv: *mut SV) -> isize;
214 pub fn RSPL_SvPVutf8(sv: *mut SV, len: *mut libc::size_t) -> *const libc::c_char;
215 pub fn RSPL_SvPV(sv: *mut SV, len: *mut libc::size_t) -> *const libc::c_char;
83147b11 216 /// This calls `sv_utf8_downgrade` first to avoid croaking, instead returns `NULL` on error.
f7cc8c37
WB
217 pub fn RSPL_SvPVbyte(sv: *mut SV, len: *mut libc::size_t) -> *const libc::c_char;
218 pub fn RSPL_sv_2mortal(sv: *mut SV) -> *mut SV;
219 pub fn RSPL_get_undef() -> *mut SV;
220 pub fn RSPL_get_yes() -> *mut SV;
221 pub fn RSPL_get_no() -> *mut SV;
222 pub fn RSPL_pop_markstack_ptr() -> usize;
223 pub fn RSPL_stack_resize_by(count: isize);
224 pub fn RSPL_stack_shrink_to(count: usize);
225 pub fn RSPL_stack_sp() -> *mut *mut SV;
226 pub fn RSPL_newRV_inc(sv: *mut SV) -> *mut SV;
227 pub fn RSPL_newSViv(v: isize) -> *mut SV;
228 pub fn RSPL_newSVuv(v: usize) -> *mut SV;
229 pub fn RSPL_newSVnv(v: f64) -> *mut SV;
230 pub fn RSPL_newSVpvn(v: *const libc::c_char, len: libc::size_t) -> *mut SV;
3f791730 231 pub fn RSPL_newSVpvn_utf8(v: *const libc::c_char, len: libc::size_t) -> *mut SV;
f7cc8c37
WB
232 pub fn RSPL_SvREFCNT_inc(sv: *mut SV) -> *mut SV;
233 pub fn RSPL_SvREFCNT_dec(sv: *mut SV);
234 pub fn RSPL_is_reference(sv: *mut SV) -> bool;
235 pub fn RSPL_dereference(sv: *mut SV) -> *mut SV;
236 pub fn RSPL_is_array(sv: *mut SV) -> bool;
237 pub fn RSPL_is_hash(sv: *mut SV) -> bool;
238 pub fn RSPL_type_flags(sv: *mut SV) -> u32;
239 pub fn RSPL_svtype(sv: *mut SV) -> u32;
b5c53f3d 240 pub fn RSPL_SvOK(sv: *mut SV) -> bool;
9acdb782 241 pub fn RSPL_SvANY(sv: *mut SV) -> bool;
f7cc8c37
WB
242 pub fn RSPL_SvTRUE(sv: *mut SV) -> bool;
243
9acdb782
WB
244 pub fn RSPL_is_defined(sv: *mut SV) -> bool;
245
f7cc8c37
WB
246 pub fn RSPL_newAV() -> *mut AV;
247 pub fn RSPL_av_extend(av: *mut AV, len: libc::ssize_t);
248 pub fn RSPL_av_push(av: *mut AV, sv: *mut SV);
249 pub fn RSPL_av_pop(av: *mut AV) -> *mut SV;
250 pub fn RSPL_av_len(av: *mut AV) -> usize;
251 pub fn RSPL_av_fetch(av: *mut AV, index: libc::ssize_t, lval: i32) -> *mut *mut SV;
252
253 pub fn RSPL_newHV() -> *mut HV;
254 pub fn RSPL_HvTOTALKEYS(hv: *mut HV) -> usize;
255 pub fn RSPL_hv_fetch(
256 hv: *mut HV,
257 key: *const libc::c_char,
258 klen: i32,
259 lval: i32,
260 ) -> *mut *mut SV;
261 /// Always consumes ownership of `value`.
262 pub fn RSPL_hv_store(hv: *mut HV, key: *const libc::c_char, klen: i32, value: *mut SV) -> bool;
263 pub fn RSPL_hv_store_ent(hv: *mut HV, key: *mut SV, value: *mut SV) -> bool;
264 pub fn RSPL_hv_iterinit(hv: *mut HV);
265 pub fn RSPL_hv_iternextsv(
266 hv: *mut HV,
267 key: *mut *mut libc::c_char,
268 retlen: *mut i32,
269 ) -> *mut SV;
270 pub fn RSPL_hv_iternext(hv: *mut HV) -> *mut HE;
271 pub fn RSPL_hv_iterkeysv(he: *mut HE) -> *mut SV;
272 pub fn RSPL_hv_iterval(hv: *mut HV, he: *mut HE) -> *mut SV;
87c10237
WB
273
274 pub fn RSPL_gv_stashsv(name: *const SV, flags: i32) -> *mut HV;
275 pub fn RSPL_sv_bless(sv: *mut SV, stash: *mut HV) -> *mut SV;
ccde914a
WB
276
277 pub fn RSPL_ENTER();
278 pub fn RSPL_SAVETMPS();
279 pub fn RSPL_FREETMPS();
280 pub fn RSPL_LEAVE();
89989b0f
WB
281
282 pub fn RSPL_sv_reftype(sv: *const SV, ob: libc::c_int) -> *const libc::c_char;
61143f5d
WB
283
284 pub fn RSPL_PVLV() -> u32;
285 pub fn RSPL_LvTARG(sv: *mut SV) -> *mut SV;
b5c53f3d 286 //pub fn RSPL_LvTYPE(sv: *mut SV) -> u8;
61143f5d 287 pub fn RSPL_vivify_defelem(sv: *mut SV);
b5c53f3d 288
9acdb782 289 //pub fn RSPL_SvFLAGS(sv: *mut SV) -> u32;
b5c53f3d 290 pub fn RSPL_SvGETMAGIC(sv: *mut SV) -> bool;
6f26c2da
WB
291
292 pub fn RSPL_sv_magicext(
293 sv: *mut SV,
294 obj: *mut SV,
295 how: libc::c_int,
296 vtbl: Option<&MGVTBL>,
297 name: *const libc::c_char,
298 namelen: i32,
299 ) -> *mut MAGIC;
300 pub fn RSPL_sv_unmagicext(sv: *mut SV, ty: libc::c_int, vtbl: Option<&MGVTBL>);
301 pub fn RSPL_mg_findext(sv: *const SV, ty: libc::c_int, vtbl: Option<&MGVTBL>) -> *const MAGIC;
302 pub fn RSPL_MAGIC_virtual(mg: *const MAGIC) -> *const MGVTBL;
303 pub fn RSPL_MAGIC_ptr(mg: *const MAGIC) -> *const libc::c_char;
304 pub fn RSPL_MAGIC_len(mg: *const MAGIC) -> isize;
305 pub fn RSPL_PERL_MAGIC_ext() -> libc::c_int;
f7cc8c37
WB
306}
307
308/// Argument marker for the stack.
309pub struct StackMark(usize);
310
311impl StackMark {
312 pub fn count(&self) -> usize {
313 unsafe { RSPL_StackMark_count(self.0) }
314 }
315
316 pub fn iter(&self) -> StackIter {
317 StackIter {
318 at: self.0 + 1,
319 end: self.0 + 1 + self.count(),
320 }
321 }
322
f0475cd5
WB
323 /// Shrink the perl stack to this mark.
324 ///
325 /// # Safety
326 ///
327 /// This is only valid if the mark is still valid (smaller than `PL_stack_sp`) and all values
328 /// still remaining on the stack are mortal (which should normally be the case anyway).
f7cc8c37
WB
329 pub unsafe fn set_stack(self) {
330 RSPL_stack_shrink_to(self.0);
331 }
332}
333
8a062e94 334/// Iterator over the stack up to the [`StackMark`].
f7cc8c37
WB
335pub struct StackIter {
336 at: usize,
337 end: usize,
338}
339
340impl Iterator for StackIter {
341 type Item = crate::Scalar;
342
343 fn next(&mut self) -> Option<Self::Item> {
344 let at = self.at;
345 if at == self.end {
346 return None;
347 }
348 unsafe {
349 let ptr = RSPL_stack_get(self.at);
350 self.at += 1;
351 if ptr.is_null() {
352 None
353 } else {
354 Some(crate::Scalar::from_raw_ref(ptr))
355 }
356 }
357 }
358}
359
f0475cd5
WB
360/// Pop the current argument marker off of the argument marker stack.
361///
362/// # Safety
363///
364/// Read up on `PL_markstack_ptr` in perlguts. This is equivalent to `*PL_markstack_ptr--` in C.
f7cc8c37
WB
365pub unsafe fn pop_arg_mark() -> StackMark {
366 StackMark(RSPL_pop_markstack_ptr())
367}
368
f0475cd5
WB
369/// Push a value to the stack.
370///
371/// # Safety
372///
373/// Read up on mortals and the stack and when it is legal to put a value onto it. Typically a
374/// mortal value with no more references to it to avoid leaking if they aren't used later on.
f7cc8c37
WB
375pub unsafe fn stack_push_raw(value: *mut SV) {
376 RSPL_stack_resize_by(1);
377 *RSPL_stack_sp() = value;
378}
379
380pub fn stack_push(value: crate::Mortal) {
381 unsafe {
382 stack_push_raw(value.into_raw());
383 }
384}
385
f0475cd5
WB
386/// This calls perl's `croak_sv`.
387///
388/// # Safety
389///
390/// This seems to perform a `longjmp` and is thus never truly safe in rust code. You really want to
391/// limit this to the top entry point of your rust call stack in a separate `extern "C" fn` where
392/// no rust values with `Drop` handlers or anything similar are active.
393///
394/// The `perlmod_macro`'s `export` attribute typically creates 2 wrapper functions of the form:
395///
396/// ```no_run
397/// # use serde::Serialize;
398///
f0475cd5 399/// # struct Output;
d2534723
WB
400/// # impl Serialize for Output {
401/// # fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
402/// # serializer.serialize_unit()
403/// # }
404/// # }
f0475cd5
WB
405///
406/// # fn code_to_extract_parameters() {}
893f7299 407/// # fn actual_rust_function(_arg: ()) -> Result<Output, String> { Ok(Output) }
f0475cd5 408/// #[no_mangle]
4a0e18d9 409/// pub extern "C" fn exported_name(/* pTHX parameter, */ cv: &::perlmod::ffi::CV) {
f0475cd5
WB
410/// unsafe {
411/// match private_implementation_name(cv) {
412/// Ok(sv) => ::perlmod::ffi::stack_push_raw(sv),
413/// Err(sv) => ::perlmod::ffi::croak(sv),
414/// }
415/// }
416/// }
417///
418/// #[inline(never)]
419/// fn private_implementation_name(
420/// _cv: &::perlmod::ffi::CV,
421/// ) -> Result<*mut ::perlmod::ffi::SV, *mut ::perlmod::ffi::SV> {
422/// let args = code_to_extract_parameters();
423/// // ...
424/// let result = match actual_rust_function(args) {
425/// Ok(output) => output,
426/// Err(err) => {
427/// return Err(::perlmod::Value::new_string(&err.to_string())
428/// .into_mortal()
429/// .into_raw());
430/// }
431/// };
432///
433/// match ::perlmod::to_value(&result) {
434/// Ok(value) => Ok(value.into_mortal().into_raw()),
435/// Err(err) => Err(::perlmod::Value::new_string(&err.to_string())
436/// .into_mortal()
437/// .into_raw()),
438/// }
439/// }
440/// ```
441pub unsafe fn croak(sv: *mut SV) -> ! {
f7cc8c37
WB
442 RSPL_croak_sv(sv);
443}
ccde914a
WB
444
445/// Create a pseudo-block for mortals & temps to be freed after it.
446/// This calls `ENTER; SAVETMPS;` before and `FREETMPS; LEAVE;` after the provided closure.
447pub fn pseudo_block<F, R>(func: F) -> R
448where
449 F: FnOnce() -> R,
450{
451 unsafe {
452 RSPL_ENTER();
453 RSPL_SAVETMPS();
454 }
455
456 let res = func();
457
458 unsafe {
459 RSPL_FREETMPS();
460 RSPL_LEAVE();
461 }
462
463 res
464}