1 //! The [`Value`] type is a generic perl value reference distinguishing between its types
6 use serde
::{Deserialize, Serialize}
;
8 use crate::ffi
::{self, SV}
;
9 use crate::scalar
::ScalarRef
;
11 use crate::{perl_fn, raw_value}
;
12 use crate::{Array, Hash, Scalar}
;
14 /// A higher level value. This is basically an [`SV`] already cast to [`AV`](crate::ffi::AV) or
15 /// [`HV`](crate::ffi::HV) for arrays and hashes.
25 /// Create a new undef value:
26 pub fn new_undef() -> Self {
27 Value
::Scalar(Scalar
::new_undef())
30 /// Create a new integer value:
31 pub fn new_int(v
: isize) -> Self {
32 Value
::Scalar(Scalar
::new_int(v
))
35 /// Create a new unsigned integer value:
36 pub fn new_uint(v
: usize) -> Self {
37 Value
::Scalar(Scalar
::new_uint(v
))
40 /// Create a new floating point value.
41 pub fn new_float(v
: f64) -> Self {
42 Value
::Scalar(Scalar
::new_float(v
))
45 /// Create a new string value.
46 pub fn new_string(s
: &str) -> Self {
47 Value
::Scalar(Scalar
::new_string(s
))
50 /// Create a new byte string.
51 pub fn new_bytes(s
: &[u8]) -> Self {
52 Value
::Scalar(Scalar
::new_bytes(s
))
55 /// Create a new reference code reference.
59 /// It is up to the user to ensure that only a valid perl XSUB is used. You should know what
60 /// you're doing, as perl code WILL execute the function and expect it to behave in a
62 pub unsafe fn new_xsub(xsub
: perl_fn
!(extern "C" fn(*mut crate::ffi
::CV
))) -> Self {
64 Self::from_raw_move(crate::ffi
::RSPL_newXS_flags(
74 /// If the value is an array, returns the associated [`Array`].
75 pub fn as_array(&self) -> Option
<&Array
> {
77 Value
::Array(v
) => Some(v
),
82 /// If the value is an array, returns the associated mutable [`Array`].
83 pub fn as_array_mut(&mut self) -> Option
<&mut Array
> {
85 Value
::Array(v
) => Some(v
),
90 /// If the value is a hash, returns the associated [`struct@Hash`].
91 pub fn as_hash(&self) -> Option
<&Hash
> {
93 Value
::Hash(v
) => Some(v
),
98 /// If the value is a hash, returns the associated mutable [`struct@Hash`].
99 pub fn as_hash_mut(&mut self) -> Option
<&mut Hash
> {
101 Value
::Hash(v
) => Some(v
),
106 /// Convenience method to create a new raw pointer value. Note that pointers are stored as
107 /// arbitrary "byte strings" and any such byte string value can be interpreted as a raw pointer.
108 pub fn new_pointer
<T
>(s
: *mut T
) -> Self {
109 Self::new_bytes(&(s
as usize).to_ne_bytes())
112 /// Create an actual perl reference to the value. (The equivalent of perl's backslash
114 pub fn new_ref
<T
>(value
: &T
) -> Self
116 T
: std
::ops
::Deref
<Target
= ScalarRef
>,
118 Value
::Reference(unsafe { Scalar::from_raw_move(ffi::RSPL_newRV_inc(value.sv())) }
)
121 /// Create a new empty hash.
122 pub fn new_hash() -> Self {
123 Value
::Hash(Hash
::new())
126 /// Bless a reference into a package. The `Value` must be a reference.
128 /// Note that a blessed value in perl can have a destructor (a `DESTROY` sub), and keeps track
129 /// of references, so one can implement a class package like this:
132 /// // 'lib' and 'file' are optional. We use 'file' here to prevent doc tests from writing out
134 /// #[perlmod::package(name = "RSPM::MyThing", lib = "bless_doctest", file="/dev/null")]
136 /// # use perlmod::{Error, Value};
142 /// #[export(raw_return)]
143 /// fn new(#[raw] class: Value, content: String) -> Result<Value, Error> {
144 /// let mut ptr = Box::new(MyThing { content });
145 /// // Short version:
146 /// // return Value::bless_box(class, ptr);
150 /// // create a pointer value
151 /// let value = Value::new_pointer::<MyThing>(&mut *ptr);
153 /// // create a reference to it:
154 /// let value = Value::new_ref(&value);
156 /// // use the the provided class name as perl passes it along when using
157 /// // `RSPM::MyThing->new()`. Alternatively this could be hardcoded and
158 /// // `RSPM::MyThing::new()` (without an arrow) would be used instead.
159 /// let this = value.bless_sv(&class)?;
161 /// // From here on out perl will call our destructor defined below, so
162 /// // it's time to drop our reference to it!
163 /// let _perl = Box::leak(ptr);
169 /// fn something(#[raw] this: Value) {
170 /// let _ = this; // see the `DESTROY` sub below for how to access this.
171 /// println!("Example method callable via $foo->something()!");
174 /// #[export(name = "DESTROY")]
175 /// fn destroy(#[raw] this: Value) {
178 /// .ok_or_else(|| Error::new("not a reference"))
179 /// .and_then(|this| Ok(this.pv_raw()?))
182 /// let value = unsafe { Box::<MyThing>::from_raw(ptr) };
183 /// println!("Dropping value {:?}", value.content);
186 /// println!("DESTROY called with invalid pointer: {}", err);
192 pub fn bless(&self, package
: &str) -> Result
<Value
, Error
> {
193 let pkgsv
= Scalar
::new_string(package
);
194 self.bless_sv(&pkgsv
)
197 /// Same as [`bless`](Self::bless()) but the package string is already a perl [`ScalarRef`].
198 pub fn bless_sv(&self, pkgsv
: &ScalarRef
) -> Result
<Value
, Error
> {
199 let stash
= unsafe { ffi::RSPL_gv_stashsv(pkgsv.sv(), 0) }
;
201 return Err(Error(format
!(
202 "failed to find package {:?}",
203 pkgsv
.pv_string_utf8()
207 let value
= unsafe { ffi::RSPL_sv_bless(self.sv(), stash) }
;
209 return Err(Error(format
!(
210 "failed to bless value into package {:?}",
211 pkgsv
.pv_string_utf8()
215 Ok(Value
::Reference(unsafe { Scalar::from_raw_ref(value) }
))
218 /// Take over a raw `SV` value, assuming that we then own a reference to it.
222 /// This does not change the value's reference count, it is assumed that we're taking ownership
223 /// of one reference.
225 /// The caller must ensure that it is safe to decrease the reference count later on, or use
226 /// `into_raw()` instead of letting the `Value` get dropped.
227 pub unsafe fn from_raw_move(ptr
: *mut SV
) -> Self {
228 Self::from_scalar(unsafe { Scalar::from_raw_move(ptr as *mut SV) }
)
231 /// Create a new reference to an existing `SV` value. This will increase the value's reference
236 /// The caller may still need to decrease the reference count for the `ptr` source value.
237 pub unsafe fn from_raw_ref(ptr
: *mut SV
) -> Self {
238 Self::from_scalar(unsafe { Scalar::from_raw_ref(ptr as *mut SV) }
)
241 /// Convert a [`Scalar`] to a [`Value`].
242 pub fn from_scalar(scalar
: Scalar
) -> Self {
246 /// Create a new reference to this value.
247 pub fn clone_ref(&self) -> Self {
249 Value
::Scalar(v
) => Value
::Scalar(v
.clone_ref()),
250 Value
::Reference(v
) => Value
::Reference(v
.clone_ref()),
251 Value
::Array(v
) => Value
::Array(v
.clone_ref()),
252 Value
::Hash(v
) => Value
::Hash(v
.clone_ref()),
256 /// Dereference this reference value.
257 pub fn dereference(&self) -> Option
<Value
> {
259 Value
::Reference(v
) => v
.dereference().map(Value
::from_scalar
),
264 /// Turn this into a raw `SV` transferring control of one reference count.
265 pub fn into_raw(self) -> *mut SV
{
267 Value
::Scalar(v
) => v
.into_raw(),
268 Value
::Reference(v
) => v
.into_raw(),
269 Value
::Array(v
) => v
.into_scalar().into_raw(),
270 Value
::Hash(v
) => v
.into_scalar().into_raw(),
274 /// Turn this into a "mortal" value in perl.
275 pub fn into_mortal(self) -> crate::scalar
::Mortal
{
277 Value
::Scalar(v
) => v
.into_mortal(),
278 Value
::Reference(v
) => v
.into_mortal(),
279 Value
::Array(v
) => v
.into_scalar().into_mortal(),
280 Value
::Hash(v
) => v
.into_scalar().into_mortal(),
284 /// If this is value is an array, get the value at the specified index.
285 pub fn get(&self, index
: usize) -> Option
<Value
> {
286 if let Value
::Array(a
) = self {
293 /// Check that the value is a reference and if so, assume it is a reference to a boxed rust
294 /// type and return a reference to it.
298 /// This is mainly a helper to be used for blessed values. This only checks that the value
299 /// itself is any kind of reference, then assumes it contains something resembling a pointer
300 /// (see [`ScalarRef::pv_raw`](ScalarRef::pv_raw())), and if so, simply casts it to `T`.
301 pub unsafe fn from_ref_box
<T
>(&self) -> Result
<&T
, Error
> {
304 .ok_or_else(|| Error
::new("not a reference"))?
306 Ok(unsafe { &*(ptr as *const T) }
)
309 /// Check that the value is a reference and blessed into a particular package name. If so,
310 /// assume it is a referenced to a boxed rust type and return a reference to it.
314 /// See [`Value::from_ref_box`]. This additionally uses [`reftype`](ScalarRef::reftype) to
315 /// check that the passed value was indeed blessed into the provided `package` name. Other than
316 /// that, it cannot verify the the contained pointer is truly a `T`.
317 pub unsafe fn from_blessed_box
<'a
, T
>(&'a
self, package
: &'_
str) -> Result
<&'a T
, Error
> {
320 .ok_or_else(|| Error
::new("not a reference"))?
;
322 let reftype
= ptr
.reftype(true);
323 if reftype
!= package
{
324 return Err(Error
::new_owned(format
!(
325 "value not blessed into {:?} (`ref` returned {:?})",
330 Ok(unsafe { &*(ptr.pv_raw()? as *const T) }
)
333 /// Take ownership of a boxed value and create a perl value blessed into a package name.
335 /// Note that this leaks the box. To let perl properly drop the value, the class name (which
336 /// must be a valid perl class name), must include a `DESTROY` sub implementing a compatible
337 /// destructor. Like so:
340 /// #[perlmod::package(name = "My::Thing")]
342 /// use std::sync::Mutex;
344 /// use perlmod::{Error, Value};
346 /// const CLASSNAME: &str = "My::Thing";
349 /// pub struct Thing {
353 /// /// Constructor for a Thing.
354 /// /// Prior to perlmod 0.6, the `raw_return` and `#[raw]` attributes were necessary, now
355 /// /// they're optional but produce slightly less code.
356 /// #[export(raw_return)]
357 /// pub fn new(#[raw] class: Value, stuff: String) -> Result<Value, Error> {
358 /// Value::bless_box(class, Box::new(Thing { stuff }))
361 /// /// Destructor for a Thing.
362 /// #[export(name = "DESTROY")]
363 /// fn destroy(#[raw] this: Value) {
364 /// perlmod::destructor!(this, Thing: CLASSNAME);
367 /// /// Convenience helper for generating methods more quickly.
368 /// impl<'a> TryFrom<&'a Value> for &'a Thing {
369 /// type Error = Error;
371 /// fn try_from(value: &'a Value) -> Result<&'a Thing, Error> {
372 /// Ok(unsafe { value.from_blessed_box(CLASSNAME)? })
376 /// /// The `try_from_ref` attribute tells perlmod to use `TryFrom::try_from(&value)` to
377 /// /// pass to `say_hello`. The conversion will `die` in perl on failure.
379 /// pub fn say_hello(#[try_from_ref] this: &Thing) {
380 /// println!("Hello, {}", this.stuff);
384 pub fn bless_box
<T
>(class
: Value
, mut box_
: Box
<T
>) -> Result
<Value
, Error
> {
385 let value
= Value
::new_pointer
::<T
>(&mut *box_
);
386 let value
= Value
::new_ref(&value
);
387 let this
= value
.bless_sv(&class
)?
;
388 let _perl
= Box
::leak(box_
);
392 /// Attempt to create a substring, provided the contained value is actually a string.
393 pub fn substr
<I
>(&self, index
: I
) -> Result
<Value
, Error
>
395 I
: std
::slice
::SliceIndex
<[u8], Output
= [u8]>,
398 Value
::Scalar(s
) => s
.substr(index
).map(Value
::Scalar
),
399 _
=> Err(Error
::new("substr called on non-scalar")),
404 impl From
<Scalar
> for Value
{
405 fn from(scalar
: Scalar
) -> Self {
407 if ffi
::RSPL_is_array(scalar
.sv()) {
408 Value
::Array(Array
::from_scalar(scalar
))
409 } else if ffi
::RSPL_is_hash(scalar
.sv()) {
410 Value
::Hash(Hash
::from_scalar(scalar
))
411 } else if ffi
::RSPL_is_reference(scalar
.sv()) {
412 Value
::Reference(scalar
)
414 Value
::Scalar(scalar
)
420 impl From
<Hash
> for Value
{
421 fn from(hash
: Hash
) -> Self {
426 impl From
<Array
> for Value
{
427 fn from(array
: Array
) -> Self {
432 impl From
<raw_value
::RawValue
> for Value
{
433 fn from(value
: raw_value
::RawValue
) -> Self {
438 impl fmt
::Debug
for Value
{
439 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
442 Value
::Scalar(v
) => Debug
::fmt(v
, f
),
443 Value
::Reference(v
) => Debug
::fmt(v
, f
),
444 Value
::Array(v
) => Debug
::fmt(v
, f
),
445 Value
::Hash(v
) => Debug
::fmt(v
, f
),
450 impl core
::ops
::Deref
for Value
{
451 type Target
= ScalarRef
;
453 fn deref(&self) -> &Self::Target
{
455 Value
::Scalar(v
) => &*v
,
456 Value
::Reference(v
) => &*v
,
457 Value
::Array(v
) => &*v
,
458 Value
::Hash(v
) => &*v
,
463 impl core
::ops
::DerefMut
for Value
{
464 fn deref_mut(&mut self) -> &mut Self::Target
{
466 Value
::Scalar(v
) => &mut *v
,
467 Value
::Reference(v
) => &mut *v
,
468 Value
::Array(v
) => &mut *v
,
469 Value
::Hash(v
) => &mut *v
,
474 impl AsRef
<ScalarRef
> for Value
{
476 fn as_ref(&self) -> &ScalarRef
{
481 impl AsMut
<ScalarRef
> for Value
{
483 fn as_mut(&mut self) -> &mut ScalarRef
{
488 impl Serialize
for Value
{
489 fn serialize
<S
>(&self, serializer
: S
) -> Result
<S
::Ok
, S
::Error
>
491 S
: serde
::Serializer
,
493 use serde
::ser
::Error
;
495 if raw_value
::is_enabled() {
496 raw_value
::serialize_raw(self, serializer
)
499 Value
::Scalar(this
) => this
.serialize(serializer
),
500 Value
::Reference(this
) => Value
::from(
502 .ok_or_else(|| S
::Error
::custom("failed to dereference perl value"))?
,
504 .serialize(serializer
),
505 Value
::Array(value
) => value
.serialize(serializer
),
506 Value
::Hash(value
) => value
.serialize(serializer
),
512 impl<'de
> Deserialize
<'de
> for Value
{
513 fn deserialize
<D
>(deserializer
: D
) -> Result
<Value
, D
::Error
>
515 D
: serde
::Deserializer
<'de
>,
517 use serde
::de
::Visitor
;
521 impl<'de
> Visitor
<'de
> for ValueVisitor
{
524 fn expecting(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
525 formatter
.write_str("any valid PERL value")
529 fn visit_bool
<E
>(self, value
: bool
) -> Result
<Value
, E
> {
530 Ok(Value
::new_int(if value { 1 }
else { 0 }
))
534 fn visit_i64
<E
>(self, value
: i64) -> Result
<Value
, E
> {
535 Ok(Value
::new_int(value
as isize))
539 fn visit_u64
<E
>(self, value
: u64) -> Result
<Value
, E
> {
540 Ok(Value
::new_uint(value
as usize))
544 fn visit_f64
<E
>(self, value
: f64) -> Result
<Value
, E
> {
545 Ok(Value
::new_float(value
))
549 fn visit_str
<E
>(self, value
: &str) -> Result
<Value
, E
>
553 Ok(Value
::new_string(value
))
557 fn visit_string
<E
>(self, value
: String
) -> Result
<Value
, E
>
561 self.visit_str(&value
)
565 fn visit_none
<E
>(self) -> Result
<Value
, E
>
569 Ok(Value
::new_undef())
573 fn visit_some
<D
>(self, deserializer
: D
) -> Result
<Value
, D
::Error
>
575 D
: serde
::Deserializer
<'de
>,
577 Deserialize
::deserialize(deserializer
)
581 fn visit_unit
<E
>(self) -> Result
<Value
, E
> {
582 Ok(Value
::new_undef())
586 fn visit_seq
<V
>(self, mut visitor
: V
) -> Result
<Value
, V
::Error
>
588 V
: serde
::de
::SeqAccess
<'de
>,
590 let array
= Array
::new();
592 while let Some(elem
) = visitor
.next_element()?
{
596 Ok(Value
::Array(array
))
599 fn visit_map
<V
>(self, mut visitor
: V
) -> Result
<Value
, V
::Error
>
601 V
: serde
::de
::MapAccess
<'de
>,
603 // We use this to hint the deserializer that we're expecting a string-ish value.
604 struct KeyClassifier
;
605 struct KeyClass(String
);
607 impl<'de
> serde
::de
::DeserializeSeed
<'de
> for KeyClassifier
{
608 type Value
= KeyClass
;
610 fn deserialize
<D
>(self, deserializer
: D
) -> Result
<Self::Value
, D
::Error
>
612 D
: serde
::Deserializer
<'de
>,
614 deserializer
.deserialize_str(self)
618 impl<'de
> Visitor
<'de
> for KeyClassifier
{
619 type Value
= KeyClass
;
621 fn expecting(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
622 formatter
.write_str("a string key")
625 fn visit_str
<E
>(self, s
: &str) -> Result
<Self::Value
, E
>
629 Ok(KeyClass(s
.to_owned()))
632 fn visit_string
<E
>(self, s
: String
) -> Result
<Self::Value
, E
>
640 let hash
= Hash
::new();
641 while let Some(key
) = visitor
.next_key_seed(KeyClassifier
)?
{
642 let value
: Value
= visitor
.next_value()?
;
643 hash
.insert(&key
.0, value
);
645 Ok(Value
::from(hash
))
649 if raw_value
::is_enabled() {
650 raw_value
::RawValue
::deserialize(deserializer
).map(Value
::from
)
652 deserializer
.deserialize_any(ValueVisitor
)