]> git.proxmox.com Git - perlmod.git/blob - perlmod/src/ffi.rs
add is_defined helper glue
[perlmod.git] / perlmod / src / ffi.rs
1 //! Unsafe ffi code.
2 //!
3 //! You should not use this code directly. This is used by the binding generator to implement xsubs
4 //! for exported functions.
5
6 /// Raw perl subroutine pointer value. This should not be used directly.
7 #[repr(C)]
8 pub struct CV {
9 _ffi: usize,
10 }
11
12 /// Raw scalar-ish perl value. This should not be used directly.
13 #[repr(C)]
14 pub struct SV {
15 _ffi: usize,
16 }
17
18 /// Raw perl array value. This should not be used directly.
19 #[repr(C)]
20 pub struct AV {
21 _ffi: usize,
22 }
23
24 /// Raw perl hash value. This should not be used directly.
25 #[repr(C)]
26 pub struct HV {
27 _ffi: usize,
28 }
29
30 /// Raw perl hash entry iterator. This should not be used directly.
31 #[repr(C)]
32 pub struct HE {
33 _ffi: usize,
34 }
35
36 // in our glue:
37 #[link(name = "glue", kind = "static")]
38 extern "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;
48 /// This calls `sv_utf8_downgrade` first to avoid croaking, instead returns `NULL` on error.
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_newSVpvn_utf8(v: *const libc::c_char, len: libc::size_t) -> *mut SV;
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;
72 pub fn RSPL_SvOK(sv: *mut SV) -> bool;
73 pub fn RSPL_SvANY(sv: *mut SV) -> bool;
74 pub fn RSPL_SvTRUE(sv: *mut SV) -> bool;
75
76 pub fn RSPL_is_defined(sv: *mut SV) -> bool;
77
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;
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;
108
109 pub fn RSPL_ENTER();
110 pub fn RSPL_SAVETMPS();
111 pub fn RSPL_FREETMPS();
112 pub fn RSPL_LEAVE();
113
114 pub fn RSPL_sv_reftype(sv: *const SV, ob: libc::c_int) -> *const libc::c_char;
115
116 pub fn RSPL_PVLV() -> u32;
117 pub fn RSPL_LvTARG(sv: *mut SV) -> *mut SV;
118 //pub fn RSPL_LvTYPE(sv: *mut SV) -> u8;
119 pub fn RSPL_vivify_defelem(sv: *mut SV);
120
121 //pub fn RSPL_SvFLAGS(sv: *mut SV) -> u32;
122 pub fn RSPL_SvGETMAGIC(sv: *mut SV) -> bool;
123 }
124
125 /// Argument marker for the stack.
126 pub struct StackMark(usize);
127
128 impl 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
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).
146 pub unsafe fn set_stack(self) {
147 RSPL_stack_shrink_to(self.0);
148 }
149 }
150
151 /// Iterator over the stack up to the [`StackMark`].
152 pub struct StackIter {
153 at: usize,
154 end: usize,
155 }
156
157 impl 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
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.
182 pub unsafe fn pop_arg_mark() -> StackMark {
183 StackMark(RSPL_pop_markstack_ptr())
184 }
185
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.
192 pub unsafe fn stack_push_raw(value: *mut SV) {
193 RSPL_stack_resize_by(1);
194 *RSPL_stack_sp() = value;
195 }
196
197 pub fn stack_push(value: crate::Mortal) {
198 unsafe {
199 stack_push_raw(value.into_raw());
200 }
201 }
202
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() {}
220 /// # fn actual_rust_function(_arg: ()) -> Result<Output, String> { Ok(Output) }
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 /// ```
254 pub unsafe fn croak(sv: *mut SV) -> ! {
255 RSPL_croak_sv(sv);
256 }
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.
260 pub fn pseudo_block<F, R>(func: F) -> R
261 where
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 }