]> git.proxmox.com Git - perlmod.git/blame - perlmod/src/scalar.rs
macro: support env vars in package attributes
[perlmod.git] / perlmod / src / scalar.rs
CommitLineData
7a433bb6
WB
1//! Module containing the [`Scalar`] and [`Mortal`] types.
2
e62be4a7
WB
3use std::convert::TryInto;
4use std::mem;
5
f7cc8c37
WB
6use bitflags::bitflags;
7
8use crate::ffi::{self, SV};
e62be4a7 9use crate::Error;
f7cc8c37
WB
10use crate::Value;
11
12/// An owned reference to a perl value.
13///
14/// This keeps a reference to a value which lives in the perl interpreter.
1182e7f5
WB
15/// This derefs to a [`ScalarRef`] which implements most of the basic functionality common to all
16/// [`SV`] related types.
f7cc8c37
WB
17#[repr(transparent)]
18pub struct Scalar(*mut SV);
19
f7cc8c37
WB
20impl Scalar {
21 /// Turn this into a "mortal" value. This will move this value's owned reference onto the
22 /// mortal stack to be cleaned up after the next perl statement if no more references exist.
23 ///
24 /// (To be garbage collected after this perl-statement.)
25 pub fn into_mortal(self) -> Mortal {
26 Mortal(unsafe { ffi::RSPL_sv_2mortal(self.into_raw()) })
27 }
28
1182e7f5 29 /// Turn this into a raw [`SV`] transferring control of one reference count.
f7cc8c37
WB
30 pub fn into_raw(self) -> *mut SV {
31 let ptr = self.0;
32 core::mem::forget(self);
33 ptr
34 }
35
1182e7f5
WB
36 /// Create a wrapping [`Scalar`] from an [`SV`] pointer. The [`Scalar`] takes over the owned
37 /// reference from the passed [`SV`], which means it must not be a mortal reference.
f7cc8c37
WB
38 ///
39 /// # Safety
40 ///
41 /// This does not change the value's reference count, it is assumed that we're taking ownership
42 /// of one reference.
43 ///
44 /// The caller must ensure that it is safe to decrease the reference count later on, or use
1182e7f5 45 /// [`into_raw()`](Scalar::into_raw) instead of letting the [`Scalar`] get dropped.
f7cc8c37
WB
46 pub unsafe fn from_raw_move(ptr: *mut SV) -> Self {
47 Self(ptr)
48 }
49
1182e7f5 50 /// Increase the reference count on an [`SV`] pointer.
f7cc8c37
WB
51 ///
52 /// # Safety
53 ///
54 /// The caller may still need to decrease the reference count for the `ptr` source value.
55 pub unsafe fn from_raw_ref(ptr: *mut SV) -> Self {
56 Self::from_raw_move(ffi::RSPL_SvREFCNT_inc(ptr))
57 }
58
59 /// Create a reference to `PL_sv_undef`.
60 pub fn new_undef() -> Self {
61 unsafe { Self::from_raw_ref(ffi::RSPL_get_undef()) }
62 }
63
64 /// Create a reference to `PL_sv_yes`.
65 pub fn new_yes() -> Self {
66 unsafe { Self::from_raw_ref(ffi::RSPL_get_yes()) }
67 }
68
69 /// Create a reference to `PL_sv_no`.
70 pub fn new_no() -> Self {
71 unsafe { Self::from_raw_ref(ffi::RSPL_get_no()) }
72 }
73
74 /// Create a new integer value:
75 pub fn new_int(v: isize) -> Self {
76 unsafe { Self::from_raw_move(ffi::RSPL_newSViv(v)) }
77 }
78
79 /// Create a new unsigned integer value:
80 pub fn new_uint(v: usize) -> Self {
81 unsafe { Self::from_raw_move(ffi::RSPL_newSVuv(v)) }
82 }
83
84 /// Create a new floating point value.
85 pub fn new_float(v: f64) -> Self {
86 unsafe { Self::from_raw_move(ffi::RSPL_newSVnv(v)) }
87 }
88
89 /// Create a new string value.
90 pub fn new_string(s: &str) -> Self {
3f791730
WB
91 if s.as_bytes().iter().any(|&b| b >= 0x80) {
92 unsafe {
93 Self::from_raw_move(ffi::RSPL_newSVpvn_utf8(
94 s.as_bytes().as_ptr() as *const libc::c_char,
95 s.as_bytes().len() as libc::size_t,
96 ))
97 }
98 } else {
99 Self::new_bytes(s.as_bytes())
100 }
f7cc8c37
WB
101 }
102
103 /// Create a new byte string.
104 pub fn new_bytes(s: &[u8]) -> Self {
105 unsafe {
106 Self::from_raw_move(ffi::RSPL_newSVpvn(
107 s.as_ptr() as *const libc::c_char,
108 s.len() as libc::size_t,
109 ))
110 }
111 }
e62be4a7
WB
112
113 /// Convenience method to create a new raw pointer value. Note that pointers are stored as
114 /// arbitrary "byte strings" and any such byte string value can be interpreted as a raw pointer.
115 pub fn new_pointer<T>(s: *mut T) -> Self {
116 Self::new_bytes(&(s as usize).to_ne_bytes())
117 }
f7cc8c37
WB
118}
119
120impl Drop for Scalar {
121 fn drop(&mut self) {
122 unsafe {
123 ffi::RSPL_SvREFCNT_dec(self.sv());
124 }
125 }
126}
127
128impl core::ops::Deref for Scalar {
129 type Target = ScalarRef;
130
131 fn deref(&self) -> &Self::Target {
132 unsafe { &*(self.0 as *mut ScalarRef) }
133 }
134}
135
136impl core::ops::DerefMut for Scalar {
137 fn deref_mut(&mut self) -> &mut Self::Target {
138 unsafe { &mut *(self.0 as *mut ScalarRef) }
139 }
140}
141
7a433bb6 142/// A value which has been pushed to perl's "mortal stack".
f7cc8c37
WB
143#[repr(transparent)]
144pub struct Mortal(*mut SV);
145
146impl Mortal {
147 /// Get the inner value.
148 pub fn into_raw(self) -> *mut SV {
149 self.0
150 }
151}
152
153impl core::ops::Deref for Mortal {
154 type Target = ScalarRef;
155
156 fn deref(&self) -> &Self::Target {
157 unsafe { &*(self.0 as *mut ScalarRef) }
158 }
159}
160
161impl core::ops::DerefMut for Mortal {
162 fn deref_mut(&mut self) -> &mut Self::Target {
163 unsafe { &mut *(self.0 as *mut ScalarRef) }
164 }
165}
166
167pub struct ScalarRef;
168
169bitflags! {
170 /// Represents the types a `Value` can contain. Values can usually contain multiple scalar types
171 /// at once and it is unclear which is the "true" type, so we can only check whether a value
172 /// contains something, not what it is originally meant to be!
173 ///
174 /// NOTE: The values must be the same as in our c glue code!
175 pub struct Flags: u8 {
176 const INTEGER = 1;
177 const DOUBLE = 2;
178 const STRING = 4;
179 }
180}
181
182/// While scalar types aren't clearly different from another, complex types are, so we do
183/// distinguish between these:
184#[derive(Clone, Copy, Debug, Eq, PartialEq)]
185pub enum Type {
186 Scalar(Flags),
187 Reference,
188 Array,
189 Hash,
190 Other(u8),
191}
192
193impl ScalarRef {
194 pub(crate) fn sv(&self) -> *mut SV {
195 self as *const ScalarRef as *const SV as *mut SV
196 }
197
b5c53f3d 198 fn get_type(sv: *mut SV) -> Type {
f7cc8c37 199 unsafe {
9acdb782
WB
200 if !ffi::RSPL_is_defined(sv) {
201 return Type::Scalar(Flags::empty());
202 }
203
b5c53f3d
WB
204 // These are simple:
205 if ffi::RSPL_is_reference(sv) {
206 return Type::Reference;
207 } else if ffi::RSPL_is_array(sv) {
208 return Type::Array;
209 } else if ffi::RSPL_is_hash(sv) {
210 return Type::Hash;
211 }
212
213 // Scalars have flags:
214 let flags = ffi::RSPL_type_flags(sv);
215 if flags != 0 {
216 return Type::Scalar(Flags::from_bits_truncate(flags as u8));
217 }
218
b5c53f3d
WB
219 let ty = ffi::RSPL_svtype(sv);
220 if ty == 0 {
221 // Looks like undef
3d5b075b 222 Type::Scalar(Flags::empty())
b5c53f3d
WB
223 } else if ty == ffi::RSPL_PVLV() {
224 // We don't support all kinds of magic, but some lvalues are simple:
225 // Try to GET the value and then check for definedness.
226 ffi::RSPL_SvGETMAGIC(sv);
227 if !ffi::RSPL_SvOK(sv) {
228 // This happens when the value points to a non-existing hash element we could
229 // auto-vivify, but we won't:
230 return Type::Scalar(Flags::empty());
f7cc8c37 231 }
b5c53f3d
WB
232
233 // Otherwise we just try to "recurse", which will work for substrings.
3d5b075b 234 Self::get_type(ffi::RSPL_LvTARG(sv))
b5c53f3d 235 } else {
3d5b075b 236 Type::Other(ty as u8)
f7cc8c37 237 }
3d5b075b 238 }
f7cc8c37
WB
239 }
240
b5c53f3d
WB
241 /// Get some information about the value's type.
242 pub fn ty(&self) -> Type {
243 Self::get_type(self.sv())
61143f5d
WB
244 }
245
f7cc8c37
WB
246 /// Dereference this reference.
247 pub fn dereference(&self) -> Option<Scalar> {
248 let ptr = unsafe { ffi::RSPL_dereference(self.sv()) };
249 if ptr.is_null() {
250 None
251 } else {
252 Some(unsafe { Scalar::from_raw_ref(ptr) })
253 }
254 }
255
1182e7f5 256 /// Coerce to a double value. (perlxs `SvNV`).
f7cc8c37
WB
257 pub fn nv(&self) -> f64 {
258 unsafe { ffi::RSPL_SvNV(self.sv()) }
259 }
260
1182e7f5 261 /// Coerce to an integer value. (perlxs `SvIV`).
f7cc8c37
WB
262 pub fn iv(&self) -> isize {
263 unsafe { ffi::RSPL_SvIV(self.sv()) }
264 }
265
1182e7f5 266 /// Coerce to an utf8 string value. (perlxs `SvPVutf8`)
83147b11 267 pub fn pv_string_utf8(&self) -> &str {
f7cc8c37
WB
268 unsafe {
269 let mut len: libc::size_t = 0;
270 let ptr = ffi::RSPL_SvPVutf8(self.sv(), &mut len) as *const u8;
271 std::str::from_utf8_unchecked(std::slice::from_raw_parts(ptr, len))
272 }
273 }
274
1182e7f5 275 /// Coerce to a string without utf8 encoding. (perlxs `SvPV`)
83147b11 276 pub fn pv_bytes(&self) -> &[u8] {
f7cc8c37
WB
277 unsafe {
278 let mut len: libc::size_t = 0;
279 let ptr = ffi::RSPL_SvPV(self.sv(), &mut len) as *const u8;
280 std::slice::from_raw_parts(ptr, len)
281 }
282 }
283
83147b11
WB
284 /// Coerce to a byte-string, downgrading from utf-8. (perlxs `SvPVbyte`)
285 ///
286 /// May fail if there are values which don't fit into bytes in the contained utf-8 string, in
287 /// which case `None` is returned.
288 pub fn pv_utf8_to_bytes(&self) -> Option<&[u8]> {
f7cc8c37
WB
289 unsafe {
290 let mut len: libc::size_t = 0;
291 let ptr = ffi::RSPL_SvPVbyte(self.sv(), &mut len) as *const u8;
83147b11
WB
292 if ptr.is_null() {
293 return None;
294 }
295 Some(std::slice::from_raw_parts(ptr, len))
f7cc8c37
WB
296 }
297 }
298
e62be4a7 299 /// Interpret the byte string as a raw pointer.
c837c7cc 300 pub fn pv_raw<T>(&self) -> Result<*mut T, Error> {
e62be4a7
WB
301 let bytes = self.pv_bytes();
302
303 let bytes: [u8; mem::size_of::<usize>()] = bytes
304 .try_into()
305 .map_err(|err| Error(format!("invalid value for pointer: {}", err)))?;
306
307 Ok(usize::from_ne_bytes(bytes) as *mut T)
308 }
309
c837c7cc
WB
310 /// Interpret the byte string as a pointer and return it as a reference for convenience.
311 ///
312 /// # Safety
313 ///
314 /// The user is responsible for making sure the underlying pointer is correct.
315 pub unsafe fn pv_ref<T>(&self) -> Result<&T, Error> {
2991a46a 316 self.pv_raw().map(|p| &*p)
c837c7cc
WB
317 }
318
319 /// Interpret the byte string as a pointer and return it as a mutable reference for
320 /// convenience.
321 ///
322 /// # Safety
323 ///
324 /// The user is responsible for making sure the underlying pointer is correct.
325 pub unsafe fn pv_mut_ref<T>(&self) -> Result<&mut T, Error> {
2991a46a 326 self.pv_raw().map(|p| &mut *p)
c837c7cc
WB
327 }
328
f7cc8c37
WB
329 /// Create another owned reference to this value.
330 pub fn clone_ref(&self) -> Scalar {
331 unsafe { Scalar::from_raw_ref(self.sv()) }
332 }
333
1182e7f5 334 /// Convenience check for `SVt_NULL`
f7cc8c37
WB
335 pub fn is_undef(&self) -> bool {
336 0 == unsafe { ffi::RSPL_type_flags(self.sv()) }
337 }
338
1182e7f5 339 /// Turn this into a [`Value`].
f7cc8c37
WB
340 pub fn into_value(self) -> Value {
341 Value::from_scalar(self.clone_ref())
342 }
89989b0f
WB
343
344 /// Get the reference type for this value. (Similar to `ref` in perl).
345 ///
346 /// If `blessed` is true and the value is a blessed reference, the package name will be
347 /// returned, otherwise the scalar type (`"SCALAR"`, `"ARRAY"`, ...) will be returned.
348 pub fn reftype(&self, blessed: bool) -> &'static str {
349 let ptr = unsafe { ffi::RSPL_sv_reftype(self.sv(), if blessed { 1 } else { 0 }) };
350
351 if ptr.is_null() {
352 "<UNKNOWN>"
353 } else {
354 unsafe {
355 std::ffi::CStr::from_ptr(ptr)
356 .to_str()
357 .unwrap_or("<NON-UTF8-CLASSNAME>")
358 }
359 }
360 }
f7cc8c37
WB
361}
362
363impl std::fmt::Debug for Scalar {
364 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
3d5b075b 365 let this: &ScalarRef = self;
f7cc8c37
WB
366 std::fmt::Debug::fmt(this, f)
367 }
368}
369
370impl std::fmt::Debug for ScalarRef {
371 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
372 use std::fmt::Debug;
373 match self.ty() {
374 Type::Scalar(flags) => {
375 if flags.intersects(Flags::STRING) {
83147b11 376 Debug::fmt(self.pv_string_utf8(), f)
f7cc8c37
WB
377 } else if flags.intersects(Flags::INTEGER) {
378 write!(f, "{}", self.iv())
379 } else if flags.intersects(Flags::DOUBLE) {
380 write!(f, "{}", self.nv())
381 } else {
382 write!(f, "<unhandled scalar>")
383 }
384 }
385 Type::Reference => write!(f, "<*REFERENCE>"),
386 Type::Array => write!(f, "<*ARRAY>"),
387 Type::Hash => write!(f, "<*HASH>"),
388 Type::Other(_) => write!(f, "<*PERLTYPE>"),
389 }
390 }
391}
392
393impl serde::Serialize for Scalar {
394 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
395 where
396 S: serde::Serializer,
397 {
398 use serde::ser::Error;
399
400 match self.ty() {
401 Type::Scalar(flags) => {
402 if flags.contains(Flags::STRING) {
83147b11 403 serializer.serialize_str(self.pv_string_utf8())
f7cc8c37
WB
404 } else if flags.contains(Flags::DOUBLE) {
405 serializer.serialize_f64(self.nv())
406 } else if flags.contains(Flags::INTEGER) {
407 serializer.serialize_i64(self.iv() as i64)
e077d87d
WB
408 } else if flags.is_empty() {
409 serializer.serialize_none()
f7cc8c37
WB
410 } else {
411 serializer.serialize_unit()
412 }
413 }
e077d87d
WB
414 Type::Other(other) => Err(S::Error::custom(format!(
415 "cannot serialize weird magic perl values ({})",
b5c53f3d 416 other,
e077d87d 417 ))),
f7cc8c37
WB
418
419 // These are impossible as they are all handled by different Value enum types:
420 Type::Reference => Value::from(
421 self.dereference()
422 .ok_or_else(|| S::Error::custom("failed to dereference perl value"))?,
423 )
424 .serialize(serializer),
425 Type::Array => {
426 let this = unsafe { crate::Array::from_raw_ref(self.sv() as *mut ffi::AV) };
427 this.serialize(serializer)
428 }
429 Type::Hash => {
430 let this = unsafe { crate::Hash::from_raw_ref(self.sv() as *mut ffi::HV) };
431 this.serialize(serializer)
432 }
433 }
434 }
435}