]> git.proxmox.com Git - perlmod.git/blame - perlmod/src/scalar.rs
document errno and serializ_error in the #[export] doc
[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 }
24ca4777
WB
120
121 /// Try to produce a substring from an existing "base" value and a `&str`.
122 ///
ff419b19 123 /// Returns `None` if `substr` is not part of `value` or if `substr` is the empty string.
c9ec592f 124 pub fn substr_from_str_slice(value: &ScalarRef, substr: &str) -> Option<Scalar> {
ff419b19 125 if substr.is_empty() {
c9ec592f 126 return None;
ff419b19
WB
127 }
128
24ca4777
WB
129 let value_bytes = value.pv_bytes();
130 let value_beg = value_bytes.as_ptr() as usize;
131 let value_end = value_beg + value_bytes.len();
132 let value_range = value_beg..value_end;
133
134 let str_bytes = substr.as_bytes();
135 let str_beg = str_bytes.as_ptr() as usize;
ff419b19 136 let str_end = str_beg + str_bytes.len() - 1;
24ca4777 137 if !value_range.contains(&str_beg) || !value_range.contains(&str_end) {
c9ec592f 138 return None;
24ca4777
WB
139 }
140
141 // we just checked the ranges:
cd69debd
WB
142 let mut start = unsafe { str_bytes.as_ptr().offset_from(value_bytes.as_ptr()) as usize };
143 let mut len = substr.len();
144
145 if unsafe { ffi::RSPL_SvUTF8(value.sv()) } {
146 // go from byte offset to code point offset
147 len = str_bytes
148 .iter()
149 .copied()
150 .filter(|&b| (b as i8) >= -0x40)
151 .count();
152 start = value_bytes[..start]
153 .iter()
154 .copied()
155 .filter(|&b| (b as i8) >= -0x40)
156 .count();
157 }
158
c9ec592f 159 Some(unsafe {
24ca4777
WB
160 Scalar::from_raw_move(ffi::RSPL_substr(
161 ffi::RSPL_SvREFCNT_inc(value.sv()),
162 start,
cd69debd 163 len,
24ca4777 164 ))
c9ec592f 165 })
24ca4777 166 }
f7cc8c37
WB
167}
168
4fe09940
WB
169impl Clone for Scalar {
170 #[inline]
171 fn clone(&self) -> Self {
172 unsafe { Self::from_raw_ref(self.sv()) }
173 }
174}
175
f7cc8c37
WB
176impl Drop for Scalar {
177 fn drop(&mut self) {
178 unsafe {
179 ffi::RSPL_SvREFCNT_dec(self.sv());
180 }
181 }
182}
183
184impl core::ops::Deref for Scalar {
185 type Target = ScalarRef;
186
187 fn deref(&self) -> &Self::Target {
188 unsafe { &*(self.0 as *mut ScalarRef) }
189 }
190}
191
192impl core::ops::DerefMut for Scalar {
193 fn deref_mut(&mut self) -> &mut Self::Target {
194 unsafe { &mut *(self.0 as *mut ScalarRef) }
195 }
196}
197
7a433bb6 198/// A value which has been pushed to perl's "mortal stack".
f7cc8c37
WB
199#[repr(transparent)]
200pub struct Mortal(*mut SV);
201
202impl Mortal {
203 /// Get the inner value.
204 pub fn into_raw(self) -> *mut SV {
205 self.0
206 }
207}
208
209impl core::ops::Deref for Mortal {
210 type Target = ScalarRef;
211
212 fn deref(&self) -> &Self::Target {
213 unsafe { &*(self.0 as *mut ScalarRef) }
214 }
215}
216
217impl core::ops::DerefMut for Mortal {
218 fn deref_mut(&mut self) -> &mut Self::Target {
219 unsafe { &mut *(self.0 as *mut ScalarRef) }
220 }
221}
222
f3f92edc
WB
223/// A reference to a perl value. This is a pre reference type and cannot be constructed manually.
224/// It is meant to provide methods common to `Value`, `Scalar`, `Array`, `Hash`, as these are all
225/// scalar values under the hood.
226pub struct ScalarRef(PhantomData<()>);
f7cc8c37
WB
227
228bitflags! {
229 /// Represents the types a `Value` can contain. Values can usually contain multiple scalar types
230 /// at once and it is unclear which is the "true" type, so we can only check whether a value
231 /// contains something, not what it is originally meant to be!
232 ///
233 /// NOTE: The values must be the same as in our c glue code!
234 pub struct Flags: u8 {
235 const INTEGER = 1;
236 const DOUBLE = 2;
237 const STRING = 4;
238 }
239}
240
241/// While scalar types aren't clearly different from another, complex types are, so we do
242/// distinguish between these:
243#[derive(Clone, Copy, Debug, Eq, PartialEq)]
244pub enum Type {
245 Scalar(Flags),
246 Reference,
247 Array,
248 Hash,
249 Other(u8),
250}
251
252impl ScalarRef {
253 pub(crate) fn sv(&self) -> *mut SV {
254 self as *const ScalarRef as *const SV as *mut SV
255 }
256
245de6dd
WB
257 /// Get the raw `*mut SV` value for this.
258 ///
259 /// This does not affect the reference count of this value. This is up to the user.
260 pub fn as_raw(&self) -> *mut SV {
261 self.sv()
262 }
263
b5c53f3d 264 fn get_type(sv: *mut SV) -> Type {
f7cc8c37 265 unsafe {
9acdb782
WB
266 if !ffi::RSPL_is_defined(sv) {
267 return Type::Scalar(Flags::empty());
268 }
269
b5c53f3d
WB
270 // These are simple:
271 if ffi::RSPL_is_reference(sv) {
272 return Type::Reference;
273 } else if ffi::RSPL_is_array(sv) {
274 return Type::Array;
275 } else if ffi::RSPL_is_hash(sv) {
276 return Type::Hash;
277 }
278
279 // Scalars have flags:
280 let flags = ffi::RSPL_type_flags(sv);
281 if flags != 0 {
282 return Type::Scalar(Flags::from_bits_truncate(flags as u8));
283 }
284
b5c53f3d
WB
285 let ty = ffi::RSPL_svtype(sv);
286 if ty == 0 {
287 // Looks like undef
3d5b075b 288 Type::Scalar(Flags::empty())
b5c53f3d
WB
289 } else if ty == ffi::RSPL_PVLV() {
290 // We don't support all kinds of magic, but some lvalues are simple:
291 // Try to GET the value and then check for definedness.
292 ffi::RSPL_SvGETMAGIC(sv);
293 if !ffi::RSPL_SvOK(sv) {
294 // This happens when the value points to a non-existing hash element we could
295 // auto-vivify, but we won't:
296 return Type::Scalar(Flags::empty());
f7cc8c37 297 }
b5c53f3d
WB
298
299 // Otherwise we just try to "recurse", which will work for substrings.
3d5b075b 300 Self::get_type(ffi::RSPL_LvTARG(sv))
b5c53f3d 301 } else {
3d5b075b 302 Type::Other(ty as u8)
f7cc8c37 303 }
3d5b075b 304 }
f7cc8c37
WB
305 }
306
b5c53f3d
WB
307 /// Get some information about the value's type.
308 pub fn ty(&self) -> Type {
309 Self::get_type(self.sv())
61143f5d
WB
310 }
311
f7cc8c37
WB
312 /// Dereference this reference.
313 pub fn dereference(&self) -> Option<Scalar> {
314 let ptr = unsafe { ffi::RSPL_dereference(self.sv()) };
315 if ptr.is_null() {
316 None
317 } else {
318 Some(unsafe { Scalar::from_raw_ref(ptr) })
319 }
320 }
321
1182e7f5 322 /// Coerce to a double value. (perlxs `SvNV`).
f7cc8c37
WB
323 pub fn nv(&self) -> f64 {
324 unsafe { ffi::RSPL_SvNV(self.sv()) }
325 }
326
1182e7f5 327 /// Coerce to an integer value. (perlxs `SvIV`).
f7cc8c37
WB
328 pub fn iv(&self) -> isize {
329 unsafe { ffi::RSPL_SvIV(self.sv()) }
330 }
331
1182e7f5 332 /// Coerce to an utf8 string value. (perlxs `SvPVutf8`)
83147b11 333 pub fn pv_string_utf8(&self) -> &str {
f7cc8c37
WB
334 unsafe {
335 let mut len: libc::size_t = 0;
336 let ptr = ffi::RSPL_SvPVutf8(self.sv(), &mut len) as *const u8;
337 std::str::from_utf8_unchecked(std::slice::from_raw_parts(ptr, len))
338 }
339 }
340
1182e7f5 341 /// Coerce to a string without utf8 encoding. (perlxs `SvPV`)
83147b11 342 pub fn pv_bytes(&self) -> &[u8] {
f7cc8c37
WB
343 unsafe {
344 let mut len: libc::size_t = 0;
345 let ptr = ffi::RSPL_SvPV(self.sv(), &mut len) as *const u8;
346 std::slice::from_raw_parts(ptr, len)
347 }
348 }
349
83147b11
WB
350 /// Coerce to a byte-string, downgrading from utf-8. (perlxs `SvPVbyte`)
351 ///
352 /// May fail if there are values which don't fit into bytes in the contained utf-8 string, in
353 /// which case `None` is returned.
354 pub fn pv_utf8_to_bytes(&self) -> Option<&[u8]> {
f7cc8c37
WB
355 unsafe {
356 let mut len: libc::size_t = 0;
357 let ptr = ffi::RSPL_SvPVbyte(self.sv(), &mut len) as *const u8;
83147b11
WB
358 if ptr.is_null() {
359 return None;
360 }
361 Some(std::slice::from_raw_parts(ptr, len))
f7cc8c37
WB
362 }
363 }
364
e62be4a7 365 /// Interpret the byte string as a raw pointer.
c837c7cc 366 pub fn pv_raw<T>(&self) -> Result<*mut T, Error> {
e62be4a7
WB
367 let bytes = self.pv_bytes();
368
369 let bytes: [u8; mem::size_of::<usize>()] = bytes
370 .try_into()
76f6a079 371 .map_err(|err| Error(format!("invalid value for pointer: {err}")))?;
e62be4a7
WB
372
373 Ok(usize::from_ne_bytes(bytes) as *mut T)
374 }
375
c837c7cc
WB
376 /// Interpret the byte string as a pointer and return it as a reference for convenience.
377 ///
378 /// # Safety
379 ///
380 /// The user is responsible for making sure the underlying pointer is correct.
381 pub unsafe fn pv_ref<T>(&self) -> Result<&T, Error> {
c0afdc3a 382 self.pv_raw().map(|p| unsafe { &*p })
c837c7cc
WB
383 }
384
385 /// Interpret the byte string as a pointer and return it as a mutable reference for
386 /// convenience.
387 ///
388 /// # Safety
389 ///
390 /// The user is responsible for making sure the underlying pointer is correct.
391 pub unsafe fn pv_mut_ref<T>(&self) -> Result<&mut T, Error> {
c0afdc3a 392 self.pv_raw().map(|p| unsafe { &mut *p })
c837c7cc
WB
393 }
394
f7cc8c37
WB
395 /// Create another owned reference to this value.
396 pub fn clone_ref(&self) -> Scalar {
397 unsafe { Scalar::from_raw_ref(self.sv()) }
398 }
399
1182e7f5 400 /// Convenience check for `SVt_NULL`
f7cc8c37
WB
401 pub fn is_undef(&self) -> bool {
402 0 == unsafe { ffi::RSPL_type_flags(self.sv()) }
403 }
404
62f3c1eb 405 // FIXME: self consuming on a phantom type... this can probably not be useful
1182e7f5 406 /// Turn this into a [`Value`].
f7cc8c37
WB
407 pub fn into_value(self) -> Value {
408 Value::from_scalar(self.clone_ref())
409 }
89989b0f
WB
410
411 /// Get the reference type for this value. (Similar to `ref` in perl).
412 ///
413 /// If `blessed` is true and the value is a blessed reference, the package name will be
414 /// returned, otherwise the scalar type (`"SCALAR"`, `"ARRAY"`, ...) will be returned.
415 pub fn reftype(&self, blessed: bool) -> &'static str {
f8b49fc1 416 let ptr = unsafe { ffi::RSPL_sv_reftype(self.sv(), i32::from(blessed)) };
89989b0f
WB
417
418 if ptr.is_null() {
419 "<UNKNOWN>"
420 } else {
421 unsafe {
422 std::ffi::CStr::from_ptr(ptr)
423 .to_str()
424 .unwrap_or("<NON-UTF8-CLASSNAME>")
425 }
426 }
427 }
083e8236 428
a43bf932
WB
429 /// Check whether this value is a substring.
430 pub fn is_substr(&self) -> bool {
431 unsafe {
432 self.find_raw_magic(
433 Some(ffi::RSPL_PERL_MAGIC_substr()),
434 Some(&*ffi::RSPL_vtbl_substr()),
435 )
436 .is_some()
437 }
438 }
439
440 /// Create a substring from a string.
441 pub fn substr<I>(&self, index: I) -> Result<Scalar, Error>
442 where
443 I: std::slice::SliceIndex<[u8], Output = [u8]>,
444 {
445 let bytes = self.pv_bytes();
446 let slice: &[u8] = bytes
447 .get(index)
448 .ok_or_else(|| Error::new("substr with out of bounds range"))?;
449 let start = unsafe { slice.as_ptr().offset_from(bytes.as_ptr()) };
450 let start = usize::try_from(start).map_err(|_| Error::new("bad substr index"))?;
451
452 Ok(unsafe {
453 Scalar::from_raw_move(ffi::RSPL_substr(
454 ffi::RSPL_SvREFCNT_inc(self.sv()),
455 start,
456 slice.len(),
457 ))
458 })
459 }
460
083e8236
WB
461 /// Attach magic to this value.
462 ///
463 /// # Safety
464 ///
465 /// The passed `vtbl` must stay valid for as long as the perl value exists.
466 /// It is up to the user to make sure `how` has a valid value. Passing `None` will create a
467 /// magic value of type `PERL_MAGIC_ext` for convenience (recommended).
468 pub unsafe fn add_raw_magic(
469 &self,
470 obj: Option<&ScalarRef>,
471 how: Option<libc::c_int>,
472 vtbl: Option<&ffi::MGVTBL>,
473 name: *const libc::c_char,
474 namelen: i32,
475 ) {
c0afdc3a
WB
476 let _magic_ptr = unsafe {
477 ffi::RSPL_sv_magicext(
478 self.sv(),
479 obj.map(Self::sv).unwrap_or(std::ptr::null_mut()),
480 how.unwrap_or_else(|| ffi::RSPL_PERL_MAGIC_ext()),
481 vtbl,
482 name,
483 namelen,
484 )
485 };
083e8236
WB
486 }
487
488 /// Remove attached magic.
489 ///
490 /// If `ty` is `None`, a `PERL_MAGIC_ext` magic will be removed.
491 ///
492 /// # Safety
493 ///
494 /// It is up to the user that doing this will not crash the perl interpreter.
495 pub unsafe fn remove_raw_magic(&self, ty: Option<libc::c_int>, vtbl: Option<&ffi::MGVTBL>) {
c0afdc3a
WB
496 unsafe {
497 ffi::RSPL_sv_unmagicext(
498 self.sv(),
499 ty.unwrap_or_else(|| ffi::RSPL_PERL_MAGIC_ext()),
500 vtbl,
501 )
502 }
083e8236
WB
503 }
504
505 /// Find a magic value, if present.
506 ///
8c587b3b 507 /// If `ty` is `None`, a `PERL_MAGIC_ext` magic will be searched for.
083e8236
WB
508 pub fn find_raw_magic(
509 &self,
510 ty: Option<libc::c_int>,
511 vtbl: Option<&ffi::MGVTBL>,
512 ) -> Option<&ffi::MAGIC> {
513 unsafe {
514 ffi::RSPL_mg_findext(
515 self.sv(),
516 ty.unwrap_or_else(|| ffi::RSPL_PERL_MAGIC_ext()),
517 vtbl,
518 )
519 .as_ref()
520 }
521 }
522
523 /// Attach a magic tag to this value. This is a more convenient alternative to using
524 /// [`add_raw_magic`](ScalarRef::add_raw_magic()) manually.
e5a46a38 525 pub fn add_magic<T: Leakable>(&self, spec: MagicValue<'_, '_, 'static, T>) {
083e8236
WB
526 unsafe {
527 self.add_raw_magic(
d17087df
WB
528 spec.spec.obj,
529 spec.spec.how,
530 Some(spec.spec.vtbl),
083e8236
WB
531 spec.ptr.map(Leakable::leak).unwrap_or(std::ptr::null()),
532 0,
533 )
534 }
535 }
536
537 /// Find a magic value attached to this perl value.
538 ///
539 /// # Safety
540 ///
541 /// It is up to the user to ensure the correct types are used in the provided `MagicSpec`.
76f6a079
WB
542 pub fn find_magic<'a, T: Leakable>(
543 &'_ self,
544 spec: &'_ MagicSpec<'static, 'static, T>,
083e8236
WB
545 ) -> Option<&'a T::Pointee> {
546 match self.find_raw_magic(spec.how, Some(spec.vtbl)) {
547 None => None,
548 Some(mg) => {
549 assert_eq!(
550 mg.vtbl().map(|v| v as *const _),
551 Some(spec.vtbl as *const _),
552 "Perl_mg_findext misbehaved horribly",
553 );
554
555 T::get_ref(mg.ptr())
556 }
557 }
558 }
559
560 /// Remove a magic tag from this value previously added via
1e46bfbe
WB
561 /// [`add_magic`](ScalarRef::add_magic()) and potentially reclaim the contained value of type
562 /// `T`.
083e8236 563 ///
1e46bfbe
WB
564 /// When using a "default" magic tag via [`MagicTag::DEFAULT`](crate::magic::MagicTag::DEFAULT)
565 /// such as when using the [`declare_magic!`](crate::declare_magic!) macro, removing the magic
566 /// implicitly causes perl call the `free` method, therefore in this case this method returns
567 /// `None`.
568 ///
569 /// In case the magic was not found, [`MagicError::NotFound("")`] is returned.
083e8236 570 ///
1e46bfbe
WB
571 /// This does not need to include the object and type information.
572 pub fn remove_magic<T: Leakable>(
573 &self,
574 spec: &MagicSpec<'static, 'static, T>,
575 ) -> Result<Option<T>, MagicError> {
576 let this = match self.find_raw_magic(spec.how, Some(spec.vtbl)) {
577 None => Err(MagicError::NotFound("")),
578 Some(mg) => {
579 assert_eq!(
580 mg.vtbl().map(|v| v as *const _),
581 Some(spec.vtbl as *const _),
582 "Perl_mg_findext misbehaved horribly",
583 );
584
585 Ok(match mg.vtbl() {
586 // We assume that a 'free' callback takes care of reclaiming the value!
587 Some(v) if v.free.is_some() => None,
588 _ => T::get_ref(mg.ptr()).map(|m| unsafe { T::reclaim(m) }),
589 })
590 }
591 };
592
083e8236
WB
593 unsafe {
594 self.remove_raw_magic(spec.how, Some(spec.vtbl));
595 }
596 this
597 }
c9ec592f
WB
598
599 /// Merges a `Cow<str>` with this value.
600 ///
601 /// Note that the `Cow` part is not required here.
602 ///
603 /// If `self` is a UTF-8 scalar and its memory representation covers the borrowed substring,
604 /// this is equivalent to calling [`Scalar::substr`] with the `index` matching the string.
605 ///
606 /// Otherwise (if the provided string is unrelated to `self`), this is also equivalent to
607 /// calling `[Scalar::new_string]`.
608 pub fn merge_str_slice(&self, text: &str) -> Scalar {
cd69debd 609 Scalar::substr_from_str_slice(self, text).unwrap_or_else(|| Scalar::new_string(text))
c9ec592f 610 }
f7cc8c37
WB
611}
612
613impl std::fmt::Debug for Scalar {
614 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
3d5b075b 615 let this: &ScalarRef = self;
f7cc8c37
WB
616 std::fmt::Debug::fmt(this, f)
617 }
618}
619
620impl std::fmt::Debug for ScalarRef {
621 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
622 use std::fmt::Debug;
623 match self.ty() {
624 Type::Scalar(flags) => {
625 if flags.intersects(Flags::STRING) {
83147b11 626 Debug::fmt(self.pv_string_utf8(), f)
f7cc8c37
WB
627 } else if flags.intersects(Flags::INTEGER) {
628 write!(f, "{}", self.iv())
629 } else if flags.intersects(Flags::DOUBLE) {
630 write!(f, "{}", self.nv())
631 } else {
632 write!(f, "<unhandled scalar>")
633 }
634 }
635 Type::Reference => write!(f, "<*REFERENCE>"),
636 Type::Array => write!(f, "<*ARRAY>"),
637 Type::Hash => write!(f, "<*HASH>"),
638 Type::Other(_) => write!(f, "<*PERLTYPE>"),
639 }
640 }
641}
642
643impl serde::Serialize for Scalar {
644 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
645 where
646 S: serde::Serializer,
647 {
648 use serde::ser::Error;
649
245de6dd 650 if raw_value::is_enabled() {
e5a46a38 651 return raw_value::serialize_raw(self, serializer);
245de6dd
WB
652 }
653
f7cc8c37
WB
654 match self.ty() {
655 Type::Scalar(flags) => {
656 if flags.contains(Flags::STRING) {
83147b11 657 serializer.serialize_str(self.pv_string_utf8())
f7cc8c37
WB
658 } else if flags.contains(Flags::DOUBLE) {
659 serializer.serialize_f64(self.nv())
660 } else if flags.contains(Flags::INTEGER) {
661 serializer.serialize_i64(self.iv() as i64)
e077d87d
WB
662 } else if flags.is_empty() {
663 serializer.serialize_none()
f7cc8c37
WB
664 } else {
665 serializer.serialize_unit()
666 }
667 }
e077d87d 668 Type::Other(other) => Err(S::Error::custom(format!(
76f6a079 669 "cannot serialize weird magic perl values ({other})",
e077d87d 670 ))),
f7cc8c37
WB
671
672 // These are impossible as they are all handled by different Value enum types:
673 Type::Reference => Value::from(
674 self.dereference()
675 .ok_or_else(|| S::Error::custom("failed to dereference perl value"))?,
676 )
677 .serialize(serializer),
678 Type::Array => {
679 let this = unsafe { crate::Array::from_raw_ref(self.sv() as *mut ffi::AV) };
680 this.serialize(serializer)
681 }
682 Type::Hash => {
683 let this = unsafe { crate::Hash::from_raw_ref(self.sv() as *mut ffi::HV) };
684 this.serialize(serializer)
685 }
686 }
687 }
688}