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