]> git.proxmox.com Git - perlmod.git/blame - perlmod/src/scalar.rs
drop imports already in 2021 prelude
[perlmod.git] / perlmod / src / scalar.rs
CommitLineData
7a433bb6
WB
1//! Module containing the [`Scalar`] and [`Mortal`] types.
2
f3f92edc 3use std::marker::PhantomData;
e62be4a7
WB
4use std::mem;
5
f7cc8c37
WB
6use bitflags::bitflags;
7
1e46bfbe 8use crate::error::MagicError;
f7cc8c37 9use crate::ffi::{self, SV};
083e8236 10use crate::magic::{Leakable, MagicSpec};
245de6dd
WB
11use crate::raw_value;
12use crate::{Error, Value};
f7cc8c37
WB
13
14/// An owned reference to a perl value.
15///
16/// This keeps a reference to a value which lives in the perl interpreter.
1182e7f5
WB
17/// This derefs to a [`ScalarRef`] which implements most of the basic functionality common to all
18/// [`SV`] related types.
f7cc8c37
WB
19#[repr(transparent)]
20pub struct Scalar(*mut SV);
21
f7cc8c37
WB
22impl Scalar {
23 /// Turn this into a "mortal" value. This will move this value's owned reference onto the
24 /// mortal stack to be cleaned up after the next perl statement if no more references exist.
25 ///
26 /// (To be garbage collected after this perl-statement.)
27 pub fn into_mortal(self) -> Mortal {
28 Mortal(unsafe { ffi::RSPL_sv_2mortal(self.into_raw()) })
29 }
30
1182e7f5 31 /// Turn this into a raw [`SV`] transferring control of one reference count.
f7cc8c37
WB
32 pub fn into_raw(self) -> *mut SV {
33 let ptr = self.0;
34 core::mem::forget(self);
35 ptr
36 }
37
1182e7f5
WB
38 /// Create a wrapping [`Scalar`] from an [`SV`] pointer. The [`Scalar`] takes over the owned
39 /// reference from the passed [`SV`], which means it must not be a mortal reference.
f7cc8c37
WB
40 ///
41 /// # Safety
42 ///
43 /// This does not change the value's reference count, it is assumed that we're taking ownership
44 /// of one reference.
45 ///
46 /// The caller must ensure that it is safe to decrease the reference count later on, or use
1182e7f5 47 /// [`into_raw()`](Scalar::into_raw) instead of letting the [`Scalar`] get dropped.
f7cc8c37
WB
48 pub unsafe fn from_raw_move(ptr: *mut SV) -> Self {
49 Self(ptr)
50 }
51
1182e7f5 52 /// Increase the reference count on an [`SV`] pointer.
f7cc8c37
WB
53 ///
54 /// # Safety
55 ///
56 /// The caller may still need to decrease the reference count for the `ptr` source value.
57 pub unsafe fn from_raw_ref(ptr: *mut SV) -> Self {
58 Self::from_raw_move(ffi::RSPL_SvREFCNT_inc(ptr))
59 }
60
61 /// Create a reference to `PL_sv_undef`.
62 pub fn new_undef() -> Self {
63 unsafe { Self::from_raw_ref(ffi::RSPL_get_undef()) }
64 }
65
66 /// Create a reference to `PL_sv_yes`.
67 pub fn new_yes() -> Self {
68 unsafe { Self::from_raw_ref(ffi::RSPL_get_yes()) }
69 }
70
71 /// Create a reference to `PL_sv_no`.
72 pub fn new_no() -> Self {
73 unsafe { Self::from_raw_ref(ffi::RSPL_get_no()) }
74 }
75
76 /// Create a new integer value:
77 pub fn new_int(v: isize) -> Self {
78 unsafe { Self::from_raw_move(ffi::RSPL_newSViv(v)) }
79 }
80
81 /// Create a new unsigned integer value:
82 pub fn new_uint(v: usize) -> Self {
83 unsafe { Self::from_raw_move(ffi::RSPL_newSVuv(v)) }
84 }
85
86 /// Create a new floating point value.
87 pub fn new_float(v: f64) -> Self {
88 unsafe { Self::from_raw_move(ffi::RSPL_newSVnv(v)) }
89 }
90
91 /// Create a new string value.
92 pub fn new_string(s: &str) -> Self {
3f791730
WB
93 if s.as_bytes().iter().any(|&b| b >= 0x80) {
94 unsafe {
95 Self::from_raw_move(ffi::RSPL_newSVpvn_utf8(
96 s.as_bytes().as_ptr() as *const libc::c_char,
97 s.as_bytes().len() as libc::size_t,
98 ))
99 }
100 } else {
101 Self::new_bytes(s.as_bytes())
102 }
f7cc8c37
WB
103 }
104
105 /// Create a new byte string.
106 pub fn new_bytes(s: &[u8]) -> Self {
107 unsafe {
108 Self::from_raw_move(ffi::RSPL_newSVpvn(
109 s.as_ptr() as *const libc::c_char,
110 s.len() as libc::size_t,
111 ))
112 }
113 }
e62be4a7
WB
114
115 /// Convenience method to create a new raw pointer value. Note that pointers are stored as
116 /// arbitrary "byte strings" and any such byte string value can be interpreted as a raw pointer.
117 pub fn new_pointer<T>(s: *mut T) -> Self {
118 Self::new_bytes(&(s as usize).to_ne_bytes())
119 }
f7cc8c37
WB
120}
121
4fe09940
WB
122impl Clone for Scalar {
123 #[inline]
124 fn clone(&self) -> Self {
125 unsafe { Self::from_raw_ref(self.sv()) }
126 }
127}
128
f7cc8c37
WB
129impl Drop for Scalar {
130 fn drop(&mut self) {
131 unsafe {
132 ffi::RSPL_SvREFCNT_dec(self.sv());
133 }
134 }
135}
136
137impl core::ops::Deref for Scalar {
138 type Target = ScalarRef;
139
140 fn deref(&self) -> &Self::Target {
141 unsafe { &*(self.0 as *mut ScalarRef) }
142 }
143}
144
145impl core::ops::DerefMut for Scalar {
146 fn deref_mut(&mut self) -> &mut Self::Target {
147 unsafe { &mut *(self.0 as *mut ScalarRef) }
148 }
149}
150
7a433bb6 151/// A value which has been pushed to perl's "mortal stack".
f7cc8c37
WB
152#[repr(transparent)]
153pub struct Mortal(*mut SV);
154
155impl Mortal {
156 /// Get the inner value.
157 pub fn into_raw(self) -> *mut SV {
158 self.0
159 }
160}
161
162impl core::ops::Deref for Mortal {
163 type Target = ScalarRef;
164
165 fn deref(&self) -> &Self::Target {
166 unsafe { &*(self.0 as *mut ScalarRef) }
167 }
168}
169
170impl core::ops::DerefMut for Mortal {
171 fn deref_mut(&mut self) -> &mut Self::Target {
172 unsafe { &mut *(self.0 as *mut ScalarRef) }
173 }
174}
175
f3f92edc
WB
176/// A reference to a perl value. This is a pre reference type and cannot be constructed manually.
177/// It is meant to provide methods common to `Value`, `Scalar`, `Array`, `Hash`, as these are all
178/// scalar values under the hood.
179pub struct ScalarRef(PhantomData<()>);
f7cc8c37
WB
180
181bitflags! {
182 /// Represents the types a `Value` can contain. Values can usually contain multiple scalar types
183 /// at once and it is unclear which is the "true" type, so we can only check whether a value
184 /// contains something, not what it is originally meant to be!
185 ///
186 /// NOTE: The values must be the same as in our c glue code!
187 pub struct Flags: u8 {
188 const INTEGER = 1;
189 const DOUBLE = 2;
190 const STRING = 4;
191 }
192}
193
194/// While scalar types aren't clearly different from another, complex types are, so we do
195/// distinguish between these:
196#[derive(Clone, Copy, Debug, Eq, PartialEq)]
197pub enum Type {
198 Scalar(Flags),
199 Reference,
200 Array,
201 Hash,
202 Other(u8),
203}
204
205impl ScalarRef {
206 pub(crate) fn sv(&self) -> *mut SV {
207 self as *const ScalarRef as *const SV as *mut SV
208 }
209
245de6dd
WB
210 /// Get the raw `*mut SV` value for this.
211 ///
212 /// This does not affect the reference count of this value. This is up to the user.
213 pub fn as_raw(&self) -> *mut SV {
214 self.sv()
215 }
216
b5c53f3d 217 fn get_type(sv: *mut SV) -> Type {
f7cc8c37 218 unsafe {
9acdb782
WB
219 if !ffi::RSPL_is_defined(sv) {
220 return Type::Scalar(Flags::empty());
221 }
222
b5c53f3d
WB
223 // These are simple:
224 if ffi::RSPL_is_reference(sv) {
225 return Type::Reference;
226 } else if ffi::RSPL_is_array(sv) {
227 return Type::Array;
228 } else if ffi::RSPL_is_hash(sv) {
229 return Type::Hash;
230 }
231
232 // Scalars have flags:
233 let flags = ffi::RSPL_type_flags(sv);
234 if flags != 0 {
235 return Type::Scalar(Flags::from_bits_truncate(flags as u8));
236 }
237
b5c53f3d
WB
238 let ty = ffi::RSPL_svtype(sv);
239 if ty == 0 {
240 // Looks like undef
3d5b075b 241 Type::Scalar(Flags::empty())
b5c53f3d
WB
242 } else if ty == ffi::RSPL_PVLV() {
243 // We don't support all kinds of magic, but some lvalues are simple:
244 // Try to GET the value and then check for definedness.
245 ffi::RSPL_SvGETMAGIC(sv);
246 if !ffi::RSPL_SvOK(sv) {
247 // This happens when the value points to a non-existing hash element we could
248 // auto-vivify, but we won't:
249 return Type::Scalar(Flags::empty());
f7cc8c37 250 }
b5c53f3d
WB
251
252 // Otherwise we just try to "recurse", which will work for substrings.
3d5b075b 253 Self::get_type(ffi::RSPL_LvTARG(sv))
b5c53f3d 254 } else {
3d5b075b 255 Type::Other(ty as u8)
f7cc8c37 256 }
3d5b075b 257 }
f7cc8c37
WB
258 }
259
b5c53f3d
WB
260 /// Get some information about the value's type.
261 pub fn ty(&self) -> Type {
262 Self::get_type(self.sv())
61143f5d
WB
263 }
264
f7cc8c37
WB
265 /// Dereference this reference.
266 pub fn dereference(&self) -> Option<Scalar> {
267 let ptr = unsafe { ffi::RSPL_dereference(self.sv()) };
268 if ptr.is_null() {
269 None
270 } else {
271 Some(unsafe { Scalar::from_raw_ref(ptr) })
272 }
273 }
274
1182e7f5 275 /// Coerce to a double value. (perlxs `SvNV`).
f7cc8c37
WB
276 pub fn nv(&self) -> f64 {
277 unsafe { ffi::RSPL_SvNV(self.sv()) }
278 }
279
1182e7f5 280 /// Coerce to an integer value. (perlxs `SvIV`).
f7cc8c37
WB
281 pub fn iv(&self) -> isize {
282 unsafe { ffi::RSPL_SvIV(self.sv()) }
283 }
284
1182e7f5 285 /// Coerce to an utf8 string value. (perlxs `SvPVutf8`)
83147b11 286 pub fn pv_string_utf8(&self) -> &str {
f7cc8c37
WB
287 unsafe {
288 let mut len: libc::size_t = 0;
289 let ptr = ffi::RSPL_SvPVutf8(self.sv(), &mut len) as *const u8;
290 std::str::from_utf8_unchecked(std::slice::from_raw_parts(ptr, len))
291 }
292 }
293
1182e7f5 294 /// Coerce to a string without utf8 encoding. (perlxs `SvPV`)
83147b11 295 pub fn pv_bytes(&self) -> &[u8] {
f7cc8c37
WB
296 unsafe {
297 let mut len: libc::size_t = 0;
298 let ptr = ffi::RSPL_SvPV(self.sv(), &mut len) as *const u8;
299 std::slice::from_raw_parts(ptr, len)
300 }
301 }
302
83147b11
WB
303 /// Coerce to a byte-string, downgrading from utf-8. (perlxs `SvPVbyte`)
304 ///
305 /// May fail if there are values which don't fit into bytes in the contained utf-8 string, in
306 /// which case `None` is returned.
307 pub fn pv_utf8_to_bytes(&self) -> Option<&[u8]> {
f7cc8c37
WB
308 unsafe {
309 let mut len: libc::size_t = 0;
310 let ptr = ffi::RSPL_SvPVbyte(self.sv(), &mut len) as *const u8;
83147b11
WB
311 if ptr.is_null() {
312 return None;
313 }
314 Some(std::slice::from_raw_parts(ptr, len))
f7cc8c37
WB
315 }
316 }
317
e62be4a7 318 /// Interpret the byte string as a raw pointer.
c837c7cc 319 pub fn pv_raw<T>(&self) -> Result<*mut T, Error> {
e62be4a7
WB
320 let bytes = self.pv_bytes();
321
322 let bytes: [u8; mem::size_of::<usize>()] = bytes
323 .try_into()
324 .map_err(|err| Error(format!("invalid value for pointer: {}", err)))?;
325
326 Ok(usize::from_ne_bytes(bytes) as *mut T)
327 }
328
c837c7cc
WB
329 /// Interpret the byte string as a pointer and return it as a reference for convenience.
330 ///
331 /// # Safety
332 ///
333 /// The user is responsible for making sure the underlying pointer is correct.
334 pub unsafe fn pv_ref<T>(&self) -> Result<&T, Error> {
2991a46a 335 self.pv_raw().map(|p| &*p)
c837c7cc
WB
336 }
337
338 /// Interpret the byte string as a pointer and return it as a mutable reference for
339 /// convenience.
340 ///
341 /// # Safety
342 ///
343 /// The user is responsible for making sure the underlying pointer is correct.
344 pub unsafe fn pv_mut_ref<T>(&self) -> Result<&mut T, Error> {
2991a46a 345 self.pv_raw().map(|p| &mut *p)
c837c7cc
WB
346 }
347
f7cc8c37
WB
348 /// Create another owned reference to this value.
349 pub fn clone_ref(&self) -> Scalar {
350 unsafe { Scalar::from_raw_ref(self.sv()) }
351 }
352
1182e7f5 353 /// Convenience check for `SVt_NULL`
f7cc8c37
WB
354 pub fn is_undef(&self) -> bool {
355 0 == unsafe { ffi::RSPL_type_flags(self.sv()) }
356 }
357
62f3c1eb 358 // FIXME: self consuming on a phantom type... this can probably not be useful
1182e7f5 359 /// Turn this into a [`Value`].
f7cc8c37
WB
360 pub fn into_value(self) -> Value {
361 Value::from_scalar(self.clone_ref())
362 }
89989b0f
WB
363
364 /// Get the reference type for this value. (Similar to `ref` in perl).
365 ///
366 /// If `blessed` is true and the value is a blessed reference, the package name will be
367 /// returned, otherwise the scalar type (`"SCALAR"`, `"ARRAY"`, ...) will be returned.
368 pub fn reftype(&self, blessed: bool) -> &'static str {
369 let ptr = unsafe { ffi::RSPL_sv_reftype(self.sv(), if blessed { 1 } else { 0 }) };
370
371 if ptr.is_null() {
372 "<UNKNOWN>"
373 } else {
374 unsafe {
375 std::ffi::CStr::from_ptr(ptr)
376 .to_str()
377 .unwrap_or("<NON-UTF8-CLASSNAME>")
378 }
379 }
380 }
083e8236
WB
381
382 /// Attach magic to this value.
383 ///
384 /// # Safety
385 ///
386 /// The passed `vtbl` must stay valid for as long as the perl value exists.
387 /// It is up to the user to make sure `how` has a valid value. Passing `None` will create a
388 /// magic value of type `PERL_MAGIC_ext` for convenience (recommended).
389 pub unsafe fn add_raw_magic(
390 &self,
391 obj: Option<&ScalarRef>,
392 how: Option<libc::c_int>,
393 vtbl: Option<&ffi::MGVTBL>,
394 name: *const libc::c_char,
395 namelen: i32,
396 ) {
397 let _magic_ptr = ffi::RSPL_sv_magicext(
398 self.sv(),
399 obj.map(Self::sv).unwrap_or(std::ptr::null_mut()),
400 how.unwrap_or_else(|| ffi::RSPL_PERL_MAGIC_ext()),
401 vtbl,
402 name,
403 namelen,
404 );
405 }
406
407 /// Remove attached magic.
408 ///
409 /// If `ty` is `None`, a `PERL_MAGIC_ext` magic will be removed.
410 ///
411 /// # Safety
412 ///
413 /// It is up to the user that doing this will not crash the perl interpreter.
414 pub unsafe fn remove_raw_magic(&self, ty: Option<libc::c_int>, vtbl: Option<&ffi::MGVTBL>) {
415 ffi::RSPL_sv_unmagicext(
416 self.sv(),
417 ty.unwrap_or_else(|| ffi::RSPL_PERL_MAGIC_ext()),
418 vtbl,
419 )
420 }
421
422 /// Find a magic value, if present.
423 ///
424 /// If `ty` is `None`, a `PERL_MAGIC_ext` magic will be removed.
425 pub fn find_raw_magic(
426 &self,
427 ty: Option<libc::c_int>,
428 vtbl: Option<&ffi::MGVTBL>,
429 ) -> Option<&ffi::MAGIC> {
430 unsafe {
431 ffi::RSPL_mg_findext(
432 self.sv(),
433 ty.unwrap_or_else(|| ffi::RSPL_PERL_MAGIC_ext()),
434 vtbl,
435 )
436 .as_ref()
437 }
438 }
439
440 /// Attach a magic tag to this value. This is a more convenient alternative to using
441 /// [`add_raw_magic`](ScalarRef::add_raw_magic()) manually.
442 pub fn add_magic<'o, T: Leakable>(&self, spec: MagicSpec<'o, 'static, T>) {
443 unsafe {
444 self.add_raw_magic(
445 spec.obj,
446 spec.how,
447 Some(spec.vtbl),
448 spec.ptr.map(Leakable::leak).unwrap_or(std::ptr::null()),
449 0,
450 )
451 }
452 }
453
454 /// Find a magic value attached to this perl value.
455 ///
456 /// # Safety
457 ///
458 /// It is up to the user to ensure the correct types are used in the provided `MagicSpec`.
459 pub fn find_magic<'a, 's, 'm, T: Leakable>(
460 &'s self,
461 spec: &'m MagicSpec<'static, 'static, T>,
462 ) -> Option<&'a T::Pointee> {
463 match self.find_raw_magic(spec.how, Some(spec.vtbl)) {
464 None => None,
465 Some(mg) => {
466 assert_eq!(
467 mg.vtbl().map(|v| v as *const _),
468 Some(spec.vtbl as *const _),
469 "Perl_mg_findext misbehaved horribly",
470 );
471
472 T::get_ref(mg.ptr())
473 }
474 }
475 }
476
477 /// Remove a magic tag from this value previously added via
1e46bfbe
WB
478 /// [`add_magic`](ScalarRef::add_magic()) and potentially reclaim the contained value of type
479 /// `T`.
083e8236 480 ///
1e46bfbe
WB
481 /// When using a "default" magic tag via [`MagicTag::DEFAULT`](crate::magic::MagicTag::DEFAULT)
482 /// such as when using the [`declare_magic!`](crate::declare_magic!) macro, removing the magic
483 /// implicitly causes perl call the `free` method, therefore in this case this method returns
484 /// `None`.
485 ///
486 /// In case the magic was not found, [`MagicError::NotFound("")`] is returned.
083e8236 487 ///
1e46bfbe
WB
488 /// This does not need to include the object and type information.
489 pub fn remove_magic<T: Leakable>(
490 &self,
491 spec: &MagicSpec<'static, 'static, T>,
492 ) -> Result<Option<T>, MagicError> {
493 let this = match self.find_raw_magic(spec.how, Some(spec.vtbl)) {
494 None => Err(MagicError::NotFound("")),
495 Some(mg) => {
496 assert_eq!(
497 mg.vtbl().map(|v| v as *const _),
498 Some(spec.vtbl as *const _),
499 "Perl_mg_findext misbehaved horribly",
500 );
501
502 Ok(match mg.vtbl() {
503 // We assume that a 'free' callback takes care of reclaiming the value!
504 Some(v) if v.free.is_some() => None,
505 _ => T::get_ref(mg.ptr()).map(|m| unsafe { T::reclaim(m) }),
506 })
507 }
508 };
509
083e8236
WB
510 unsafe {
511 self.remove_raw_magic(spec.how, Some(spec.vtbl));
512 }
513 this
514 }
f7cc8c37
WB
515}
516
517impl std::fmt::Debug for Scalar {
518 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
3d5b075b 519 let this: &ScalarRef = self;
f7cc8c37
WB
520 std::fmt::Debug::fmt(this, f)
521 }
522}
523
524impl std::fmt::Debug for ScalarRef {
525 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
526 use std::fmt::Debug;
527 match self.ty() {
528 Type::Scalar(flags) => {
529 if flags.intersects(Flags::STRING) {
83147b11 530 Debug::fmt(self.pv_string_utf8(), f)
f7cc8c37
WB
531 } else if flags.intersects(Flags::INTEGER) {
532 write!(f, "{}", self.iv())
533 } else if flags.intersects(Flags::DOUBLE) {
534 write!(f, "{}", self.nv())
535 } else {
536 write!(f, "<unhandled scalar>")
537 }
538 }
539 Type::Reference => write!(f, "<*REFERENCE>"),
540 Type::Array => write!(f, "<*ARRAY>"),
541 Type::Hash => write!(f, "<*HASH>"),
542 Type::Other(_) => write!(f, "<*PERLTYPE>"),
543 }
544 }
545}
546
547impl serde::Serialize for Scalar {
548 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
549 where
550 S: serde::Serializer,
551 {
552 use serde::ser::Error;
553
245de6dd
WB
554 if raw_value::is_enabled() {
555 return raw_value::serialize_raw(&self, serializer);
556 }
557
f7cc8c37
WB
558 match self.ty() {
559 Type::Scalar(flags) => {
560 if flags.contains(Flags::STRING) {
83147b11 561 serializer.serialize_str(self.pv_string_utf8())
f7cc8c37
WB
562 } else if flags.contains(Flags::DOUBLE) {
563 serializer.serialize_f64(self.nv())
564 } else if flags.contains(Flags::INTEGER) {
565 serializer.serialize_i64(self.iv() as i64)
e077d87d
WB
566 } else if flags.is_empty() {
567 serializer.serialize_none()
f7cc8c37
WB
568 } else {
569 serializer.serialize_unit()
570 }
571 }
e077d87d
WB
572 Type::Other(other) => Err(S::Error::custom(format!(
573 "cannot serialize weird magic perl values ({})",
b5c53f3d 574 other,
e077d87d 575 ))),
f7cc8c37
WB
576
577 // These are impossible as they are all handled by different Value enum types:
578 Type::Reference => Value::from(
579 self.dereference()
580 .ok_or_else(|| S::Error::custom("failed to dereference perl value"))?,
581 )
582 .serialize(serializer),
583 Type::Array => {
584 let this = unsafe { crate::Array::from_raw_ref(self.sv() as *mut ffi::AV) };
585 this.serialize(serializer)
586 }
587 Type::Hash => {
588 let this = unsafe { crate::Hash::from_raw_ref(self.sv() as *mut ffi::HV) };
589 this.serialize(serializer)
590 }
591 }
592 }
593}