]> git.proxmox.com Git - perlmod.git/blame - perlmod/src/scalar.rs
experimental direct substr support
[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};
d17087df 10use crate::magic::{Leakable, MagicSpec, MagicValue};
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 {
c0afdc3a 58 unsafe { Self::from_raw_move(ffi::RSPL_SvREFCNT_inc(ptr)) }
f7cc8c37
WB
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> {
c0afdc3a 335 self.pv_raw().map(|p| unsafe { &*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> {
c0afdc3a 345 self.pv_raw().map(|p| unsafe { &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 381
a43bf932
WB
382 /// Check whether this value is a substring.
383 pub fn is_substr(&self) -> bool {
384 unsafe {
385 self.find_raw_magic(
386 Some(ffi::RSPL_PERL_MAGIC_substr()),
387 Some(&*ffi::RSPL_vtbl_substr()),
388 )
389 .is_some()
390 }
391 }
392
393 /// Create a substring from a string.
394 pub fn substr<I>(&self, index: I) -> Result<Scalar, Error>
395 where
396 I: std::slice::SliceIndex<[u8], Output = [u8]>,
397 {
398 let bytes = self.pv_bytes();
399 let slice: &[u8] = bytes
400 .get(index)
401 .ok_or_else(|| Error::new("substr with out of bounds range"))?;
402 let start = unsafe { slice.as_ptr().offset_from(bytes.as_ptr()) };
403 let start = usize::try_from(start).map_err(|_| Error::new("bad substr index"))?;
404
405 Ok(unsafe {
406 Scalar::from_raw_move(ffi::RSPL_substr(
407 ffi::RSPL_SvREFCNT_inc(self.sv()),
408 start,
409 slice.len(),
410 ))
411 })
412 }
413
414 /// Try to produce a substring from an existing "base" value and a `&str`.
415 ///
416 /// Returns `None` if `substr` is not part of `value`.
417 pub fn substr_from_str_slice(value: &ScalarRef, substr: &str) -> Result<Option<Scalar>, Error> {
418 let value_bytes = value.pv_bytes();
419 let value_beg = value_bytes.as_ptr() as usize;
420 let value_end = value_beg + value_bytes.len();
421 let value_range = value_beg..value_end;
422
423 let str_bytes = substr.as_bytes();
424 let str_beg = str_bytes.as_ptr() as usize;
425 let str_end = str_beg + str_bytes.len();
426 if !value_range.contains(&str_beg) || !value_range.contains(&str_end) {
427 return Ok(None);
428 }
429
430 // we just checked the ranges:
431 let start = unsafe { str_bytes.as_ptr().offset_from(value_bytes.as_ptr()) as usize };
432 Ok(Some(unsafe {
433 Scalar::from_raw_move(ffi::RSPL_substr(
434 ffi::RSPL_SvREFCNT_inc(value.sv()),
435 start,
436 substr.len(),
437 ))
438 }))
439 }
440
083e8236
WB
441 /// Attach magic to this value.
442 ///
443 /// # Safety
444 ///
445 /// The passed `vtbl` must stay valid for as long as the perl value exists.
446 /// It is up to the user to make sure `how` has a valid value. Passing `None` will create a
447 /// magic value of type `PERL_MAGIC_ext` for convenience (recommended).
448 pub unsafe fn add_raw_magic(
449 &self,
450 obj: Option<&ScalarRef>,
451 how: Option<libc::c_int>,
452 vtbl: Option<&ffi::MGVTBL>,
453 name: *const libc::c_char,
454 namelen: i32,
455 ) {
c0afdc3a
WB
456 let _magic_ptr = unsafe {
457 ffi::RSPL_sv_magicext(
458 self.sv(),
459 obj.map(Self::sv).unwrap_or(std::ptr::null_mut()),
460 how.unwrap_or_else(|| ffi::RSPL_PERL_MAGIC_ext()),
461 vtbl,
462 name,
463 namelen,
464 )
465 };
083e8236
WB
466 }
467
468 /// Remove attached magic.
469 ///
470 /// If `ty` is `None`, a `PERL_MAGIC_ext` magic will be removed.
471 ///
472 /// # Safety
473 ///
474 /// It is up to the user that doing this will not crash the perl interpreter.
475 pub unsafe fn remove_raw_magic(&self, ty: Option<libc::c_int>, vtbl: Option<&ffi::MGVTBL>) {
c0afdc3a
WB
476 unsafe {
477 ffi::RSPL_sv_unmagicext(
478 self.sv(),
479 ty.unwrap_or_else(|| ffi::RSPL_PERL_MAGIC_ext()),
480 vtbl,
481 )
482 }
083e8236
WB
483 }
484
485 /// Find a magic value, if present.
486 ///
8c587b3b 487 /// If `ty` is `None`, a `PERL_MAGIC_ext` magic will be searched for.
083e8236
WB
488 pub fn find_raw_magic(
489 &self,
490 ty: Option<libc::c_int>,
491 vtbl: Option<&ffi::MGVTBL>,
492 ) -> Option<&ffi::MAGIC> {
493 unsafe {
494 ffi::RSPL_mg_findext(
495 self.sv(),
496 ty.unwrap_or_else(|| ffi::RSPL_PERL_MAGIC_ext()),
497 vtbl,
498 )
499 .as_ref()
500 }
501 }
502
503 /// Attach a magic tag to this value. This is a more convenient alternative to using
504 /// [`add_raw_magic`](ScalarRef::add_raw_magic()) manually.
e5a46a38 505 pub fn add_magic<T: Leakable>(&self, spec: MagicValue<'_, '_, 'static, T>) {
083e8236
WB
506 unsafe {
507 self.add_raw_magic(
d17087df
WB
508 spec.spec.obj,
509 spec.spec.how,
510 Some(spec.spec.vtbl),
083e8236
WB
511 spec.ptr.map(Leakable::leak).unwrap_or(std::ptr::null()),
512 0,
513 )
514 }
515 }
516
517 /// Find a magic value attached to this perl value.
518 ///
519 /// # Safety
520 ///
521 /// It is up to the user to ensure the correct types are used in the provided `MagicSpec`.
522 pub fn find_magic<'a, 's, 'm, T: Leakable>(
523 &'s self,
524 spec: &'m MagicSpec<'static, 'static, T>,
525 ) -> Option<&'a T::Pointee> {
526 match self.find_raw_magic(spec.how, Some(spec.vtbl)) {
527 None => None,
528 Some(mg) => {
529 assert_eq!(
530 mg.vtbl().map(|v| v as *const _),
531 Some(spec.vtbl as *const _),
532 "Perl_mg_findext misbehaved horribly",
533 );
534
535 T::get_ref(mg.ptr())
536 }
537 }
538 }
539
540 /// Remove a magic tag from this value previously added via
1e46bfbe
WB
541 /// [`add_magic`](ScalarRef::add_magic()) and potentially reclaim the contained value of type
542 /// `T`.
083e8236 543 ///
1e46bfbe
WB
544 /// When using a "default" magic tag via [`MagicTag::DEFAULT`](crate::magic::MagicTag::DEFAULT)
545 /// such as when using the [`declare_magic!`](crate::declare_magic!) macro, removing the magic
546 /// implicitly causes perl call the `free` method, therefore in this case this method returns
547 /// `None`.
548 ///
549 /// In case the magic was not found, [`MagicError::NotFound("")`] is returned.
083e8236 550 ///
1e46bfbe
WB
551 /// This does not need to include the object and type information.
552 pub fn remove_magic<T: Leakable>(
553 &self,
554 spec: &MagicSpec<'static, 'static, T>,
555 ) -> Result<Option<T>, MagicError> {
556 let this = match self.find_raw_magic(spec.how, Some(spec.vtbl)) {
557 None => Err(MagicError::NotFound("")),
558 Some(mg) => {
559 assert_eq!(
560 mg.vtbl().map(|v| v as *const _),
561 Some(spec.vtbl as *const _),
562 "Perl_mg_findext misbehaved horribly",
563 );
564
565 Ok(match mg.vtbl() {
566 // We assume that a 'free' callback takes care of reclaiming the value!
567 Some(v) if v.free.is_some() => None,
568 _ => T::get_ref(mg.ptr()).map(|m| unsafe { T::reclaim(m) }),
569 })
570 }
571 };
572
083e8236
WB
573 unsafe {
574 self.remove_raw_magic(spec.how, Some(spec.vtbl));
575 }
576 this
577 }
f7cc8c37
WB
578}
579
580impl std::fmt::Debug for Scalar {
581 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
3d5b075b 582 let this: &ScalarRef = self;
f7cc8c37
WB
583 std::fmt::Debug::fmt(this, f)
584 }
585}
586
587impl std::fmt::Debug for ScalarRef {
588 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
589 use std::fmt::Debug;
590 match self.ty() {
591 Type::Scalar(flags) => {
592 if flags.intersects(Flags::STRING) {
83147b11 593 Debug::fmt(self.pv_string_utf8(), f)
f7cc8c37
WB
594 } else if flags.intersects(Flags::INTEGER) {
595 write!(f, "{}", self.iv())
596 } else if flags.intersects(Flags::DOUBLE) {
597 write!(f, "{}", self.nv())
598 } else {
599 write!(f, "<unhandled scalar>")
600 }
601 }
602 Type::Reference => write!(f, "<*REFERENCE>"),
603 Type::Array => write!(f, "<*ARRAY>"),
604 Type::Hash => write!(f, "<*HASH>"),
605 Type::Other(_) => write!(f, "<*PERLTYPE>"),
606 }
607 }
608}
609
610impl serde::Serialize for Scalar {
611 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
612 where
613 S: serde::Serializer,
614 {
615 use serde::ser::Error;
616
245de6dd 617 if raw_value::is_enabled() {
e5a46a38 618 return raw_value::serialize_raw(self, serializer);
245de6dd
WB
619 }
620
f7cc8c37
WB
621 match self.ty() {
622 Type::Scalar(flags) => {
623 if flags.contains(Flags::STRING) {
83147b11 624 serializer.serialize_str(self.pv_string_utf8())
f7cc8c37
WB
625 } else if flags.contains(Flags::DOUBLE) {
626 serializer.serialize_f64(self.nv())
627 } else if flags.contains(Flags::INTEGER) {
628 serializer.serialize_i64(self.iv() as i64)
e077d87d
WB
629 } else if flags.is_empty() {
630 serializer.serialize_none()
f7cc8c37
WB
631 } else {
632 serializer.serialize_unit()
633 }
634 }
e077d87d
WB
635 Type::Other(other) => Err(S::Error::custom(format!(
636 "cannot serialize weird magic perl values ({})",
b5c53f3d 637 other,
e077d87d 638 ))),
f7cc8c37
WB
639
640 // These are impossible as they are all handled by different Value enum types:
641 Type::Reference => Value::from(
642 self.dereference()
643 .ok_or_else(|| S::Error::custom("failed to dereference perl value"))?,
644 )
645 .serialize(serializer),
646 Type::Array => {
647 let this = unsafe { crate::Array::from_raw_ref(self.sv() as *mut ffi::AV) };
648 this.serialize(serializer)
649 }
650 Type::Hash => {
651 let this = unsafe { crate::Hash::from_raw_ref(self.sv() as *mut ffi::HV) };
652 this.serialize(serializer)
653 }
654 }
655 }
656}