]> git.proxmox.com Git - perlmod.git/blame - perlmod/src/scalar.rs
Value: add bless_sv method for convenience
[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.
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
29 /// Turn this into a raw `SV` transferring control of one reference count.
30 pub fn into_raw(self) -> *mut SV {
31 let ptr = self.0;
32 core::mem::forget(self);
33 ptr
34 }
35
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.
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
45 /// `into_raw()` instead of letting the `Scalar` get dropped.
46 pub unsafe fn from_raw_move(ptr: *mut SV) -> Self {
47 Self(ptr)
48 }
49
50 /// Increase the reference count on an `SV` pointer.
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 {
91 Self::new_bytes(s.as_bytes())
92 }
93
94 /// Create a new byte string.
95 pub fn new_bytes(s: &[u8]) -> Self {
96 unsafe {
97 Self::from_raw_move(ffi::RSPL_newSVpvn(
98 s.as_ptr() as *const libc::c_char,
99 s.len() as libc::size_t,
100 ))
101 }
102 }
e62be4a7
WB
103
104 /// Convenience method to create a new raw pointer value. Note that pointers are stored as
105 /// arbitrary "byte strings" and any such byte string value can be interpreted as a raw pointer.
106 pub fn new_pointer<T>(s: *mut T) -> Self {
107 Self::new_bytes(&(s as usize).to_ne_bytes())
108 }
f7cc8c37
WB
109}
110
111impl Drop for Scalar {
112 fn drop(&mut self) {
113 unsafe {
114 ffi::RSPL_SvREFCNT_dec(self.sv());
115 }
116 }
117}
118
119impl core::ops::Deref for Scalar {
120 type Target = ScalarRef;
121
122 fn deref(&self) -> &Self::Target {
123 unsafe { &*(self.0 as *mut ScalarRef) }
124 }
125}
126
127impl core::ops::DerefMut for Scalar {
128 fn deref_mut(&mut self) -> &mut Self::Target {
129 unsafe { &mut *(self.0 as *mut ScalarRef) }
130 }
131}
132
7a433bb6 133/// A value which has been pushed to perl's "mortal stack".
f7cc8c37
WB
134#[repr(transparent)]
135pub struct Mortal(*mut SV);
136
137impl Mortal {
138 /// Get the inner value.
139 pub fn into_raw(self) -> *mut SV {
140 self.0
141 }
142}
143
144impl core::ops::Deref for Mortal {
145 type Target = ScalarRef;
146
147 fn deref(&self) -> &Self::Target {
148 unsafe { &*(self.0 as *mut ScalarRef) }
149 }
150}
151
152impl core::ops::DerefMut for Mortal {
153 fn deref_mut(&mut self) -> &mut Self::Target {
154 unsafe { &mut *(self.0 as *mut ScalarRef) }
155 }
156}
157
158pub struct ScalarRef;
159
160bitflags! {
161 /// Represents the types a `Value` can contain. Values can usually contain multiple scalar types
162 /// at once and it is unclear which is the "true" type, so we can only check whether a value
163 /// contains something, not what it is originally meant to be!
164 ///
165 /// NOTE: The values must be the same as in our c glue code!
166 pub struct Flags: u8 {
167 const INTEGER = 1;
168 const DOUBLE = 2;
169 const STRING = 4;
170 }
171}
172
173/// While scalar types aren't clearly different from another, complex types are, so we do
174/// distinguish between these:
175#[derive(Clone, Copy, Debug, Eq, PartialEq)]
176pub enum Type {
177 Scalar(Flags),
178 Reference,
179 Array,
180 Hash,
181 Other(u8),
182}
183
184impl ScalarRef {
185 pub(crate) fn sv(&self) -> *mut SV {
186 self as *const ScalarRef as *const SV as *mut SV
187 }
188
189 /// Get some information about the value's type.
190 pub fn ty(&self) -> Type {
191 unsafe {
192 if ffi::RSPL_is_reference(self.sv()) {
193 Type::Reference
194 } else {
195 let flags = ffi::RSPL_type_flags(self.sv());
196 if flags > 0xff {
197 panic!("bad C type returned");
198 } else if flags != 0 {
199 Type::Scalar(Flags::from_bits(flags as u8).unwrap())
200 } else if ffi::RSPL_is_array(self.sv()) {
201 Type::Array
202 } else if ffi::RSPL_is_hash(self.sv()) {
203 Type::Hash
204 } else {
205 Type::Other(ffi::RSPL_svtype(self.sv()) as u8)
206 }
207 }
208 }
209 }
210
211 /// Dereference this reference.
212 pub fn dereference(&self) -> Option<Scalar> {
213 let ptr = unsafe { ffi::RSPL_dereference(self.sv()) };
214 if ptr.is_null() {
215 None
216 } else {
217 Some(unsafe { Scalar::from_raw_ref(ptr) })
218 }
219 }
220
221 /// Coerce to a double value. (perlxs SvNV).
222 pub fn nv(&self) -> f64 {
223 unsafe { ffi::RSPL_SvNV(self.sv()) }
224 }
225
226 /// Coerce to an integer value. (perlxs SvIV).
227 pub fn iv(&self) -> isize {
228 unsafe { ffi::RSPL_SvIV(self.sv()) }
229 }
230
231 /// Coerce to an utf8 string value. (perlxs SvPVutf8)
232 pub fn pv_utf8(&self) -> &str {
233 unsafe {
234 let mut len: libc::size_t = 0;
235 let ptr = ffi::RSPL_SvPVutf8(self.sv(), &mut len) as *const u8;
236 std::str::from_utf8_unchecked(std::slice::from_raw_parts(ptr, len))
237 }
238 }
239
240 /// Coerce to a string without utf8 encoding. (perlxs SvPV)
241 pub fn pv_string_bytes(&self) -> &[u8] {
242 unsafe {
243 let mut len: libc::size_t = 0;
244 let ptr = ffi::RSPL_SvPV(self.sv(), &mut len) as *const u8;
245 std::slice::from_raw_parts(ptr, len)
246 }
247 }
248
249 /// Coerce to a byte-string. (perlxs SvPVbyte)
250 pub fn pv_bytes(&self) -> &[u8] {
251 unsafe {
252 let mut len: libc::size_t = 0;
253 let ptr = ffi::RSPL_SvPVbyte(self.sv(), &mut len) as *const u8;
254 std::slice::from_raw_parts(ptr, len)
255 }
256 }
257
e62be4a7
WB
258 /// Interpret the byte string as a raw pointer.
259 ///
260 /// # Safety
261 ///
262 /// The user is responsible for making sure the underlying pointer is correct.
263 pub unsafe fn pv_raw<T>(&self) -> Result<*mut T, Error> {
264 let bytes = self.pv_bytes();
265
266 let bytes: [u8; mem::size_of::<usize>()] = bytes
267 .try_into()
268 .map_err(|err| Error(format!("invalid value for pointer: {}", err)))?;
269
270 Ok(usize::from_ne_bytes(bytes) as *mut T)
271 }
272
f7cc8c37
WB
273 /// Create another owned reference to this value.
274 pub fn clone_ref(&self) -> Scalar {
275 unsafe { Scalar::from_raw_ref(self.sv()) }
276 }
277
278 /// Convenience check for SVt_NULL
279 pub fn is_undef(&self) -> bool {
280 0 == unsafe { ffi::RSPL_type_flags(self.sv()) }
281 }
282
283 /// Turn this into a `Value`.
284 pub fn into_value(self) -> Value {
285 Value::from_scalar(self.clone_ref())
286 }
287}
288
289impl std::fmt::Debug for Scalar {
290 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
291 let this: &ScalarRef = &self;
292 std::fmt::Debug::fmt(this, f)
293 }
294}
295
296impl std::fmt::Debug for ScalarRef {
297 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
298 use std::fmt::Debug;
299 match self.ty() {
300 Type::Scalar(flags) => {
301 if flags.intersects(Flags::STRING) {
302 Debug::fmt(self.pv_utf8(), f)
303 } else if flags.intersects(Flags::INTEGER) {
304 write!(f, "{}", self.iv())
305 } else if flags.intersects(Flags::DOUBLE) {
306 write!(f, "{}", self.nv())
307 } else {
308 write!(f, "<unhandled scalar>")
309 }
310 }
311 Type::Reference => write!(f, "<*REFERENCE>"),
312 Type::Array => write!(f, "<*ARRAY>"),
313 Type::Hash => write!(f, "<*HASH>"),
314 Type::Other(_) => write!(f, "<*PERLTYPE>"),
315 }
316 }
317}
318
319impl serde::Serialize for Scalar {
320 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
321 where
322 S: serde::Serializer,
323 {
324 use serde::ser::Error;
325
326 match self.ty() {
327 Type::Scalar(flags) => {
328 if flags.contains(Flags::STRING) {
329 serializer.serialize_str(self.pv_utf8())
330 } else if flags.contains(Flags::DOUBLE) {
331 serializer.serialize_f64(self.nv())
332 } else if flags.contains(Flags::INTEGER) {
333 serializer.serialize_i64(self.iv() as i64)
334 } else {
335 serializer.serialize_unit()
336 }
337 }
338 Type::Other(_) => Err(S::Error::custom(
339 "cannot deserialize weird magic perl values",
340 )),
341
342 // These are impossible as they are all handled by different Value enum types:
343 Type::Reference => Value::from(
344 self.dereference()
345 .ok_or_else(|| S::Error::custom("failed to dereference perl value"))?,
346 )
347 .serialize(serializer),
348 Type::Array => {
349 let this = unsafe { crate::Array::from_raw_ref(self.sv() as *mut ffi::AV) };
350 this.serialize(serializer)
351 }
352 Type::Hash => {
353 let this = unsafe { crate::Hash::from_raw_ref(self.sv() as *mut ffi::HV) };
354 this.serialize(serializer)
355 }
356 }
357 }
358}