]>
Commit | Line | Data |
---|---|---|
7a433bb6 WB |
1 | //! Module containing the [`Scalar`] and [`Mortal`] types. |
2 | ||
f7cc8c37 WB |
3 | use bitflags::bitflags; |
4 | ||
5 | use crate::ffi::{self, SV}; | |
6 | use crate::Value; | |
7 | ||
8 | /// An owned reference to a perl value. | |
9 | /// | |
10 | /// This keeps a reference to a value which lives in the perl interpreter. | |
11 | /// This derefs to a `ScalarRef` which implements most of the basic functionality common to all | |
12 | /// `SV` related types. | |
f7cc8c37 WB |
13 | #[repr(transparent)] |
14 | pub struct Scalar(*mut SV); | |
15 | ||
f7cc8c37 WB |
16 | impl Scalar { |
17 | /// Turn this into a "mortal" value. This will move this value's owned reference onto the | |
18 | /// mortal stack to be cleaned up after the next perl statement if no more references exist. | |
19 | /// | |
20 | /// (To be garbage collected after this perl-statement.) | |
21 | pub fn into_mortal(self) -> Mortal { | |
22 | Mortal(unsafe { ffi::RSPL_sv_2mortal(self.into_raw()) }) | |
23 | } | |
24 | ||
25 | /// Turn this into a raw `SV` transferring control of one reference count. | |
26 | pub fn into_raw(self) -> *mut SV { | |
27 | let ptr = self.0; | |
28 | core::mem::forget(self); | |
29 | ptr | |
30 | } | |
31 | ||
32 | /// Create a wrapping `Scalar` from an `SV` pointer. The `Scalar` takes over the owned | |
33 | /// reference from the passed `SV`, which means it must not be a mortal reference. | |
34 | /// | |
35 | /// # Safety | |
36 | /// | |
37 | /// This does not change the value's reference count, it is assumed that we're taking ownership | |
38 | /// of one reference. | |
39 | /// | |
40 | /// The caller must ensure that it is safe to decrease the reference count later on, or use | |
41 | /// `into_raw()` instead of letting the `Scalar` get dropped. | |
42 | pub unsafe fn from_raw_move(ptr: *mut SV) -> Self { | |
43 | Self(ptr) | |
44 | } | |
45 | ||
46 | /// Increase the reference count on an `SV` pointer. | |
47 | /// | |
48 | /// # Safety | |
49 | /// | |
50 | /// The caller may still need to decrease the reference count for the `ptr` source value. | |
51 | pub unsafe fn from_raw_ref(ptr: *mut SV) -> Self { | |
52 | Self::from_raw_move(ffi::RSPL_SvREFCNT_inc(ptr)) | |
53 | } | |
54 | ||
55 | /// Create a reference to `PL_sv_undef`. | |
56 | pub fn new_undef() -> Self { | |
57 | unsafe { Self::from_raw_ref(ffi::RSPL_get_undef()) } | |
58 | } | |
59 | ||
60 | /// Create a reference to `PL_sv_yes`. | |
61 | pub fn new_yes() -> Self { | |
62 | unsafe { Self::from_raw_ref(ffi::RSPL_get_yes()) } | |
63 | } | |
64 | ||
65 | /// Create a reference to `PL_sv_no`. | |
66 | pub fn new_no() -> Self { | |
67 | unsafe { Self::from_raw_ref(ffi::RSPL_get_no()) } | |
68 | } | |
69 | ||
70 | /// Create a new integer value: | |
71 | pub fn new_int(v: isize) -> Self { | |
72 | unsafe { Self::from_raw_move(ffi::RSPL_newSViv(v)) } | |
73 | } | |
74 | ||
75 | /// Create a new unsigned integer value: | |
76 | pub fn new_uint(v: usize) -> Self { | |
77 | unsafe { Self::from_raw_move(ffi::RSPL_newSVuv(v)) } | |
78 | } | |
79 | ||
80 | /// Create a new floating point value. | |
81 | pub fn new_float(v: f64) -> Self { | |
82 | unsafe { Self::from_raw_move(ffi::RSPL_newSVnv(v)) } | |
83 | } | |
84 | ||
85 | /// Create a new string value. | |
86 | pub fn new_string(s: &str) -> Self { | |
87 | Self::new_bytes(s.as_bytes()) | |
88 | } | |
89 | ||
90 | /// Create a new byte string. | |
91 | pub fn new_bytes(s: &[u8]) -> Self { | |
92 | unsafe { | |
93 | Self::from_raw_move(ffi::RSPL_newSVpvn( | |
94 | s.as_ptr() as *const libc::c_char, | |
95 | s.len() as libc::size_t, | |
96 | )) | |
97 | } | |
98 | } | |
99 | } | |
100 | ||
101 | impl Drop for Scalar { | |
102 | fn drop(&mut self) { | |
103 | unsafe { | |
104 | ffi::RSPL_SvREFCNT_dec(self.sv()); | |
105 | } | |
106 | } | |
107 | } | |
108 | ||
109 | impl core::ops::Deref for Scalar { | |
110 | type Target = ScalarRef; | |
111 | ||
112 | fn deref(&self) -> &Self::Target { | |
113 | unsafe { &*(self.0 as *mut ScalarRef) } | |
114 | } | |
115 | } | |
116 | ||
117 | impl core::ops::DerefMut for Scalar { | |
118 | fn deref_mut(&mut self) -> &mut Self::Target { | |
119 | unsafe { &mut *(self.0 as *mut ScalarRef) } | |
120 | } | |
121 | } | |
122 | ||
7a433bb6 | 123 | /// A value which has been pushed to perl's "mortal stack". |
f7cc8c37 WB |
124 | #[repr(transparent)] |
125 | pub struct Mortal(*mut SV); | |
126 | ||
127 | impl Mortal { | |
128 | /// Get the inner value. | |
129 | pub fn into_raw(self) -> *mut SV { | |
130 | self.0 | |
131 | } | |
132 | } | |
133 | ||
134 | impl core::ops::Deref for Mortal { | |
135 | type Target = ScalarRef; | |
136 | ||
137 | fn deref(&self) -> &Self::Target { | |
138 | unsafe { &*(self.0 as *mut ScalarRef) } | |
139 | } | |
140 | } | |
141 | ||
142 | impl core::ops::DerefMut for Mortal { | |
143 | fn deref_mut(&mut self) -> &mut Self::Target { | |
144 | unsafe { &mut *(self.0 as *mut ScalarRef) } | |
145 | } | |
146 | } | |
147 | ||
148 | pub struct ScalarRef; | |
149 | ||
150 | bitflags! { | |
151 | /// Represents the types a `Value` can contain. Values can usually contain multiple scalar types | |
152 | /// at once and it is unclear which is the "true" type, so we can only check whether a value | |
153 | /// contains something, not what it is originally meant to be! | |
154 | /// | |
155 | /// NOTE: The values must be the same as in our c glue code! | |
156 | pub struct Flags: u8 { | |
157 | const INTEGER = 1; | |
158 | const DOUBLE = 2; | |
159 | const STRING = 4; | |
160 | } | |
161 | } | |
162 | ||
163 | /// While scalar types aren't clearly different from another, complex types are, so we do | |
164 | /// distinguish between these: | |
165 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] | |
166 | pub enum Type { | |
167 | Scalar(Flags), | |
168 | Reference, | |
169 | Array, | |
170 | Hash, | |
171 | Other(u8), | |
172 | } | |
173 | ||
174 | impl ScalarRef { | |
175 | pub(crate) fn sv(&self) -> *mut SV { | |
176 | self as *const ScalarRef as *const SV as *mut SV | |
177 | } | |
178 | ||
179 | /// Get some information about the value's type. | |
180 | pub fn ty(&self) -> Type { | |
181 | unsafe { | |
182 | if ffi::RSPL_is_reference(self.sv()) { | |
183 | Type::Reference | |
184 | } else { | |
185 | let flags = ffi::RSPL_type_flags(self.sv()); | |
186 | if flags > 0xff { | |
187 | panic!("bad C type returned"); | |
188 | } else if flags != 0 { | |
189 | Type::Scalar(Flags::from_bits(flags as u8).unwrap()) | |
190 | } else if ffi::RSPL_is_array(self.sv()) { | |
191 | Type::Array | |
192 | } else if ffi::RSPL_is_hash(self.sv()) { | |
193 | Type::Hash | |
194 | } else { | |
195 | Type::Other(ffi::RSPL_svtype(self.sv()) as u8) | |
196 | } | |
197 | } | |
198 | } | |
199 | } | |
200 | ||
201 | /// Dereference this reference. | |
202 | pub fn dereference(&self) -> Option<Scalar> { | |
203 | let ptr = unsafe { ffi::RSPL_dereference(self.sv()) }; | |
204 | if ptr.is_null() { | |
205 | None | |
206 | } else { | |
207 | Some(unsafe { Scalar::from_raw_ref(ptr) }) | |
208 | } | |
209 | } | |
210 | ||
211 | /// Coerce to a double value. (perlxs SvNV). | |
212 | pub fn nv(&self) -> f64 { | |
213 | unsafe { ffi::RSPL_SvNV(self.sv()) } | |
214 | } | |
215 | ||
216 | /// Coerce to an integer value. (perlxs SvIV). | |
217 | pub fn iv(&self) -> isize { | |
218 | unsafe { ffi::RSPL_SvIV(self.sv()) } | |
219 | } | |
220 | ||
221 | /// Coerce to an utf8 string value. (perlxs SvPVutf8) | |
222 | pub fn pv_utf8(&self) -> &str { | |
223 | unsafe { | |
224 | let mut len: libc::size_t = 0; | |
225 | let ptr = ffi::RSPL_SvPVutf8(self.sv(), &mut len) as *const u8; | |
226 | std::str::from_utf8_unchecked(std::slice::from_raw_parts(ptr, len)) | |
227 | } | |
228 | } | |
229 | ||
230 | /// Coerce to a string without utf8 encoding. (perlxs SvPV) | |
231 | pub fn pv_string_bytes(&self) -> &[u8] { | |
232 | unsafe { | |
233 | let mut len: libc::size_t = 0; | |
234 | let ptr = ffi::RSPL_SvPV(self.sv(), &mut len) as *const u8; | |
235 | std::slice::from_raw_parts(ptr, len) | |
236 | } | |
237 | } | |
238 | ||
239 | /// Coerce to a byte-string. (perlxs SvPVbyte) | |
240 | pub fn pv_bytes(&self) -> &[u8] { | |
241 | unsafe { | |
242 | let mut len: libc::size_t = 0; | |
243 | let ptr = ffi::RSPL_SvPVbyte(self.sv(), &mut len) as *const u8; | |
244 | std::slice::from_raw_parts(ptr, len) | |
245 | } | |
246 | } | |
247 | ||
248 | /// Create another owned reference to this value. | |
249 | pub fn clone_ref(&self) -> Scalar { | |
250 | unsafe { Scalar::from_raw_ref(self.sv()) } | |
251 | } | |
252 | ||
253 | /// Convenience check for SVt_NULL | |
254 | pub fn is_undef(&self) -> bool { | |
255 | 0 == unsafe { ffi::RSPL_type_flags(self.sv()) } | |
256 | } | |
257 | ||
258 | /// Turn this into a `Value`. | |
259 | pub fn into_value(self) -> Value { | |
260 | Value::from_scalar(self.clone_ref()) | |
261 | } | |
262 | } | |
263 | ||
264 | impl std::fmt::Debug for Scalar { | |
265 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | |
266 | let this: &ScalarRef = &self; | |
267 | std::fmt::Debug::fmt(this, f) | |
268 | } | |
269 | } | |
270 | ||
271 | impl std::fmt::Debug for ScalarRef { | |
272 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | |
273 | use std::fmt::Debug; | |
274 | match self.ty() { | |
275 | Type::Scalar(flags) => { | |
276 | if flags.intersects(Flags::STRING) { | |
277 | Debug::fmt(self.pv_utf8(), f) | |
278 | } else if flags.intersects(Flags::INTEGER) { | |
279 | write!(f, "{}", self.iv()) | |
280 | } else if flags.intersects(Flags::DOUBLE) { | |
281 | write!(f, "{}", self.nv()) | |
282 | } else { | |
283 | write!(f, "<unhandled scalar>") | |
284 | } | |
285 | } | |
286 | Type::Reference => write!(f, "<*REFERENCE>"), | |
287 | Type::Array => write!(f, "<*ARRAY>"), | |
288 | Type::Hash => write!(f, "<*HASH>"), | |
289 | Type::Other(_) => write!(f, "<*PERLTYPE>"), | |
290 | } | |
291 | } | |
292 | } | |
293 | ||
294 | impl serde::Serialize for Scalar { | |
295 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | |
296 | where | |
297 | S: serde::Serializer, | |
298 | { | |
299 | use serde::ser::Error; | |
300 | ||
301 | match self.ty() { | |
302 | Type::Scalar(flags) => { | |
303 | if flags.contains(Flags::STRING) { | |
304 | serializer.serialize_str(self.pv_utf8()) | |
305 | } else if flags.contains(Flags::DOUBLE) { | |
306 | serializer.serialize_f64(self.nv()) | |
307 | } else if flags.contains(Flags::INTEGER) { | |
308 | serializer.serialize_i64(self.iv() as i64) | |
309 | } else { | |
310 | serializer.serialize_unit() | |
311 | } | |
312 | } | |
313 | Type::Other(_) => Err(S::Error::custom( | |
314 | "cannot deserialize weird magic perl values", | |
315 | )), | |
316 | ||
317 | // These are impossible as they are all handled by different Value enum types: | |
318 | Type::Reference => Value::from( | |
319 | self.dereference() | |
320 | .ok_or_else(|| S::Error::custom("failed to dereference perl value"))?, | |
321 | ) | |
322 | .serialize(serializer), | |
323 | Type::Array => { | |
324 | let this = unsafe { crate::Array::from_raw_ref(self.sv() as *mut ffi::AV) }; | |
325 | this.serialize(serializer) | |
326 | } | |
327 | Type::Hash => { | |
328 | let this = unsafe { crate::Hash::from_raw_ref(self.sv() as *mut ffi::HV) }; | |
329 | this.serialize(serializer) | |
330 | } | |
331 | } | |
332 | } | |
333 | } |