]>
Commit | Line | Data |
---|---|---|
1 | //! The [`Value`] type is a generic perl value reference distinguishing between its types | |
2 | //! automatically. | |
3 | ||
4 | use std::fmt; | |
5 | ||
6 | use serde::{Deserialize, Serialize}; | |
7 | ||
8 | use crate::ffi::{self, SV}; | |
9 | use crate::scalar::ScalarRef; | |
10 | use crate::Error; | |
11 | use crate::{perl_fn, raw_value}; | |
12 | use crate::{Array, Hash, Scalar}; | |
13 | ||
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. | |
16 | #[derive(Clone)] | |
17 | pub enum Value { | |
18 | Scalar(Scalar), | |
19 | Reference(Scalar), | |
20 | Array(Array), | |
21 | Hash(Hash), | |
22 | } | |
23 | ||
24 | impl Value { | |
25 | /// Create a new undef value: | |
26 | pub fn new_undef() -> Self { | |
27 | Value::Scalar(Scalar::new_undef()) | |
28 | } | |
29 | ||
30 | /// Create a new integer value: | |
31 | pub fn new_int(v: isize) -> Self { | |
32 | Value::Scalar(Scalar::new_int(v)) | |
33 | } | |
34 | ||
35 | /// Create a new unsigned integer value: | |
36 | pub fn new_uint(v: usize) -> Self { | |
37 | Value::Scalar(Scalar::new_uint(v)) | |
38 | } | |
39 | ||
40 | /// Create a new floating point value. | |
41 | pub fn new_float(v: f64) -> Self { | |
42 | Value::Scalar(Scalar::new_float(v)) | |
43 | } | |
44 | ||
45 | /// Create a new string value. | |
46 | pub fn new_string(s: &str) -> Self { | |
47 | Value::Scalar(Scalar::new_string(s)) | |
48 | } | |
49 | ||
50 | /// Create a new byte string. | |
51 | pub fn new_bytes(s: &[u8]) -> Self { | |
52 | Value::Scalar(Scalar::new_bytes(s)) | |
53 | } | |
54 | ||
55 | /// Create a new reference code reference. | |
56 | /// | |
57 | /// # Safety | |
58 | /// | |
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 | |
61 | /// particular way! | |
62 | pub unsafe fn new_xsub(xsub: perl_fn!(extern "C" fn(*mut crate::ffi::CV))) -> Self { | |
63 | unsafe { | |
64 | Self::from_raw_move(crate::ffi::RSPL_newXS_flags( | |
65 | std::ptr::null(), | |
66 | xsub as _, | |
67 | std::ptr::null(), | |
68 | std::ptr::null(), | |
69 | 0, | |
70 | ) as _) | |
71 | } | |
72 | } | |
73 | ||
74 | /// If the value is an array, returns the associated [`Array`]. | |
75 | pub fn as_array(&self) -> Option<&Array> { | |
76 | match self { | |
77 | Value::Array(v) => Some(v), | |
78 | _ => None, | |
79 | } | |
80 | } | |
81 | ||
82 | /// If the value is an array, returns the associated mutable [`Array`]. | |
83 | pub fn as_array_mut(&mut self) -> Option<&mut Array> { | |
84 | match self { | |
85 | Value::Array(v) => Some(v), | |
86 | _ => None, | |
87 | } | |
88 | } | |
89 | ||
90 | /// If the value is a hash, returns the associated [`struct@Hash`]. | |
91 | pub fn as_hash(&self) -> Option<&Hash> { | |
92 | match self { | |
93 | Value::Hash(v) => Some(v), | |
94 | _ => None, | |
95 | } | |
96 | } | |
97 | ||
98 | /// If the value is a hash, returns the associated mutable [`struct@Hash`]. | |
99 | pub fn as_hash_mut(&mut self) -> Option<&mut Hash> { | |
100 | match self { | |
101 | Value::Hash(v) => Some(v), | |
102 | _ => None, | |
103 | } | |
104 | } | |
105 | ||
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()) | |
110 | } | |
111 | ||
112 | /// Create an actual perl reference to the value. (The equivalent of perl's backslash | |
113 | /// operator). | |
114 | pub fn new_ref<T>(value: &T) -> Self | |
115 | where | |
116 | T: std::ops::Deref<Target = ScalarRef>, | |
117 | { | |
118 | Value::Reference(unsafe { Scalar::from_raw_move(ffi::RSPL_newRV_inc(value.sv())) }) | |
119 | } | |
120 | ||
121 | /// Create a new empty hash. | |
122 | pub fn new_hash() -> Self { | |
123 | Value::Hash(Hash::new()) | |
124 | } | |
125 | ||
126 | /// Bless a reference into a package. The `Value` must be a reference. | |
127 | /// | |
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: | |
130 | /// | |
131 | /// ``` | |
132 | /// // 'lib' and 'file' are optional. We use 'file' here to prevent doc tests from writing out | |
133 | /// // the file. | |
134 | /// #[perlmod::package(name = "RSPM::MyThing", lib = "bless_doctest", file="/dev/null")] | |
135 | /// mod export { | |
136 | /// # use perlmod::{Error, Value}; | |
137 | /// | |
138 | /// struct MyThing { | |
139 | /// content: String, | |
140 | /// } | |
141 | /// | |
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); | |
147 | /// | |
148 | /// // Raw code: | |
149 | /// | |
150 | /// // create a pointer value | |
151 | /// let value = Value::new_pointer::<MyThing>(&mut *ptr); | |
152 | /// | |
153 | /// // create a reference to it: | |
154 | /// let value = Value::new_ref(&value); | |
155 | /// | |
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)?; | |
160 | /// | |
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); | |
164 | /// | |
165 | /// Ok(this) | |
166 | /// } | |
167 | /// | |
168 | /// #[export] | |
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()!"); | |
172 | /// } | |
173 | /// | |
174 | /// #[export(name = "DESTROY")] | |
175 | /// fn destroy(#[raw] this: Value) { | |
176 | /// match this | |
177 | /// .dereference() | |
178 | /// .ok_or_else(|| Error::new("not a reference")) | |
179 | /// .and_then(|this| Ok(this.pv_raw()?)) | |
180 | /// { | |
181 | /// Ok(ptr) => { | |
182 | /// let value = unsafe { Box::<MyThing>::from_raw(ptr) }; | |
183 | /// println!("Dropping value {:?}", value.content); | |
184 | /// } | |
185 | /// Err(err) => { | |
186 | /// println!("DESTROY called with invalid pointer: {}", err); | |
187 | /// } | |
188 | /// } | |
189 | /// } | |
190 | /// } | |
191 | /// ``` | |
192 | pub fn bless(&self, package: &str) -> Result<Value, Error> { | |
193 | let pkgsv = Scalar::new_string(package); | |
194 | self.bless_sv(&pkgsv) | |
195 | } | |
196 | ||
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) }; | |
200 | if stash.is_null() { | |
201 | return Err(Error(format!( | |
202 | "failed to find package {:?}", | |
203 | pkgsv.pv_string_utf8() | |
204 | ))); | |
205 | } | |
206 | ||
207 | let value = unsafe { ffi::RSPL_sv_bless(self.sv(), stash) }; | |
208 | if value.is_null() { | |
209 | return Err(Error(format!( | |
210 | "failed to bless value into package {:?}", | |
211 | pkgsv.pv_string_utf8() | |
212 | ))); | |
213 | } | |
214 | ||
215 | Ok(Value::Reference(unsafe { Scalar::from_raw_ref(value) })) | |
216 | } | |
217 | ||
218 | /// Take over a raw `SV` value, assuming that we then own a reference to it. | |
219 | /// | |
220 | /// # Safety | |
221 | /// | |
222 | /// This does not change the value's reference count, it is assumed that we're taking ownership | |
223 | /// of one reference. | |
224 | /// | |
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) }) | |
229 | } | |
230 | ||
231 | /// Create a new reference to an existing `SV` value. This will increase the value's reference | |
232 | /// count. | |
233 | /// | |
234 | /// # Safety | |
235 | /// | |
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) }) | |
239 | } | |
240 | ||
241 | /// Convert a [`Scalar`] to a [`Value`]. | |
242 | pub fn from_scalar(scalar: Scalar) -> Self { | |
243 | Self::from(scalar) | |
244 | } | |
245 | ||
246 | /// Create a new reference to this value. | |
247 | pub fn clone_ref(&self) -> Self { | |
248 | match 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()), | |
253 | } | |
254 | } | |
255 | ||
256 | /// Dereference this reference value. | |
257 | pub fn dereference(&self) -> Option<Value> { | |
258 | match self { | |
259 | Value::Reference(v) => v.dereference().map(Value::from_scalar), | |
260 | _ => None, | |
261 | } | |
262 | } | |
263 | ||
264 | /// Turn this into a raw `SV` transferring control of one reference count. | |
265 | pub fn into_raw(self) -> *mut SV { | |
266 | match self { | |
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(), | |
271 | } | |
272 | } | |
273 | ||
274 | /// Turn this into a "mortal" value in perl. | |
275 | pub fn into_mortal(self) -> crate::scalar::Mortal { | |
276 | match self { | |
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(), | |
281 | } | |
282 | } | |
283 | ||
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 { | |
287 | a.get(index) | |
288 | } else { | |
289 | None | |
290 | } | |
291 | } | |
292 | ||
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. | |
295 | /// | |
296 | /// # Safety | |
297 | /// | |
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> { | |
302 | let ptr = self | |
303 | .dereference() | |
304 | .ok_or_else(|| Error::new("not a reference"))? | |
305 | .pv_raw()?; | |
306 | Ok(unsafe { &*(ptr as *const T) }) | |
307 | } | |
308 | ||
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. | |
311 | /// | |
312 | /// # Safety | |
313 | /// | |
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> { | |
318 | let ptr = self | |
319 | .dereference() | |
320 | .ok_or_else(|| Error::new("not a reference"))?; | |
321 | ||
322 | let reftype = ptr.reftype(true); | |
323 | if reftype != package { | |
324 | return Err(Error::new_owned(format!( | |
325 | "value not blessed into {:?} (`ref` returned {:?})", | |
326 | package, reftype, | |
327 | ))); | |
328 | } | |
329 | ||
330 | Ok(unsafe { &*(ptr.pv_raw()? as *const T) }) | |
331 | } | |
332 | ||
333 | /// Take ownership of a boxed value and create a perl value blessed into a package name. | |
334 | /// | |
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: | |
338 | /// | |
339 | /// ``` | |
340 | /// #[perlmod::package(name = "My::Thing")] | |
341 | /// mod export { | |
342 | /// use std::sync::Mutex; | |
343 | /// | |
344 | /// use perlmod::{Error, Value}; | |
345 | /// | |
346 | /// const CLASSNAME: &str = "My::Thing"; | |
347 | /// | |
348 | /// /// Some thing. | |
349 | /// pub struct Thing { | |
350 | /// stuff: String, | |
351 | /// } | |
352 | /// | |
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 })) | |
359 | /// } | |
360 | /// | |
361 | /// /// Destructor for a Thing. | |
362 | /// #[export(name = "DESTROY")] | |
363 | /// fn destroy(#[raw] this: Value) { | |
364 | /// perlmod::destructor!(this, Thing: CLASSNAME); | |
365 | /// } | |
366 | /// | |
367 | /// /// Convenience helper for generating methods more quickly. | |
368 | /// impl<'a> TryFrom<&'a Value> for &'a Thing { | |
369 | /// type Error = Error; | |
370 | /// | |
371 | /// fn try_from(value: &'a Value) -> Result<&'a Thing, Error> { | |
372 | /// Ok(unsafe { value.from_blessed_box(CLASSNAME)? }) | |
373 | /// } | |
374 | /// } | |
375 | /// | |
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. | |
378 | /// #[export] | |
379 | /// pub fn say_hello(#[try_from_ref] this: &Thing) { | |
380 | /// println!("Hello, {}", this.stuff); | |
381 | /// } | |
382 | /// } | |
383 | /// ``` | |
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_); | |
389 | Ok(this) | |
390 | } | |
391 | ||
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> | |
394 | where | |
395 | I: std::slice::SliceIndex<[u8], Output = [u8]>, | |
396 | { | |
397 | match self { | |
398 | Value::Scalar(s) => s.substr(index).map(Value::Scalar), | |
399 | _ => Err(Error::new("substr called on non-scalar")), | |
400 | } | |
401 | } | |
402 | } | |
403 | ||
404 | impl From<Scalar> for Value { | |
405 | fn from(scalar: Scalar) -> Self { | |
406 | unsafe { | |
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) | |
413 | } else { | |
414 | Value::Scalar(scalar) | |
415 | } | |
416 | } | |
417 | } | |
418 | } | |
419 | ||
420 | impl From<Hash> for Value { | |
421 | fn from(hash: Hash) -> Self { | |
422 | Value::Hash(hash) | |
423 | } | |
424 | } | |
425 | ||
426 | impl From<Array> for Value { | |
427 | fn from(array: Array) -> Self { | |
428 | Value::Array(array) | |
429 | } | |
430 | } | |
431 | ||
432 | impl From<raw_value::RawValue> for Value { | |
433 | fn from(value: raw_value::RawValue) -> Self { | |
434 | value.into_inner() | |
435 | } | |
436 | } | |
437 | ||
438 | impl fmt::Debug for Value { | |
439 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
440 | use fmt::Debug; | |
441 | match self { | |
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), | |
446 | } | |
447 | } | |
448 | } | |
449 | ||
450 | impl core::ops::Deref for Value { | |
451 | type Target = ScalarRef; | |
452 | ||
453 | fn deref(&self) -> &Self::Target { | |
454 | match self { | |
455 | Value::Scalar(v) => &*v, | |
456 | Value::Reference(v) => &*v, | |
457 | Value::Array(v) => &*v, | |
458 | Value::Hash(v) => &*v, | |
459 | } | |
460 | } | |
461 | } | |
462 | ||
463 | impl core::ops::DerefMut for Value { | |
464 | fn deref_mut(&mut self) -> &mut Self::Target { | |
465 | match self { | |
466 | Value::Scalar(v) => &mut *v, | |
467 | Value::Reference(v) => &mut *v, | |
468 | Value::Array(v) => &mut *v, | |
469 | Value::Hash(v) => &mut *v, | |
470 | } | |
471 | } | |
472 | } | |
473 | ||
474 | impl AsRef<ScalarRef> for Value { | |
475 | #[inline] | |
476 | fn as_ref(&self) -> &ScalarRef { | |
477 | &*self | |
478 | } | |
479 | } | |
480 | ||
481 | impl AsMut<ScalarRef> for Value { | |
482 | #[inline] | |
483 | fn as_mut(&mut self) -> &mut ScalarRef { | |
484 | &mut *self | |
485 | } | |
486 | } | |
487 | ||
488 | impl Serialize for Value { | |
489 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | |
490 | where | |
491 | S: serde::Serializer, | |
492 | { | |
493 | use serde::ser::Error; | |
494 | ||
495 | if raw_value::is_enabled() { | |
496 | raw_value::serialize_raw(self, serializer) | |
497 | } else { | |
498 | match self { | |
499 | Value::Scalar(this) => this.serialize(serializer), | |
500 | Value::Reference(this) => Value::from( | |
501 | this.dereference() | |
502 | .ok_or_else(|| S::Error::custom("failed to dereference perl value"))?, | |
503 | ) | |
504 | .serialize(serializer), | |
505 | Value::Array(value) => value.serialize(serializer), | |
506 | Value::Hash(value) => value.serialize(serializer), | |
507 | } | |
508 | } | |
509 | } | |
510 | } | |
511 | ||
512 | impl<'de> Deserialize<'de> for Value { | |
513 | fn deserialize<D>(deserializer: D) -> Result<Value, D::Error> | |
514 | where | |
515 | D: serde::Deserializer<'de>, | |
516 | { | |
517 | use serde::de::Visitor; | |
518 | ||
519 | struct ValueVisitor; | |
520 | ||
521 | impl<'de> Visitor<'de> for ValueVisitor { | |
522 | type Value = Value; | |
523 | ||
524 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { | |
525 | formatter.write_str("any valid PERL value") | |
526 | } | |
527 | ||
528 | #[inline] | |
529 | fn visit_bool<E>(self, value: bool) -> Result<Value, E> { | |
530 | Ok(Value::new_int(if value { 1 } else { 0 })) | |
531 | } | |
532 | ||
533 | #[inline] | |
534 | fn visit_i64<E>(self, value: i64) -> Result<Value, E> { | |
535 | Ok(Value::new_int(value as isize)) | |
536 | } | |
537 | ||
538 | #[inline] | |
539 | fn visit_u64<E>(self, value: u64) -> Result<Value, E> { | |
540 | Ok(Value::new_uint(value as usize)) | |
541 | } | |
542 | ||
543 | #[inline] | |
544 | fn visit_f64<E>(self, value: f64) -> Result<Value, E> { | |
545 | Ok(Value::new_float(value)) | |
546 | } | |
547 | ||
548 | #[inline] | |
549 | fn visit_str<E>(self, value: &str) -> Result<Value, E> | |
550 | where | |
551 | E: serde::de::Error, | |
552 | { | |
553 | Ok(Value::new_string(value)) | |
554 | } | |
555 | ||
556 | #[inline] | |
557 | fn visit_string<E>(self, value: String) -> Result<Value, E> | |
558 | where | |
559 | E: serde::de::Error, | |
560 | { | |
561 | self.visit_str(&value) | |
562 | } | |
563 | ||
564 | #[inline] | |
565 | fn visit_none<E>(self) -> Result<Value, E> | |
566 | where | |
567 | E: serde::de::Error, | |
568 | { | |
569 | Ok(Value::new_undef()) | |
570 | } | |
571 | ||
572 | #[inline] | |
573 | fn visit_some<D>(self, deserializer: D) -> Result<Value, D::Error> | |
574 | where | |
575 | D: serde::Deserializer<'de>, | |
576 | { | |
577 | Deserialize::deserialize(deserializer) | |
578 | } | |
579 | ||
580 | #[inline] | |
581 | fn visit_unit<E>(self) -> Result<Value, E> { | |
582 | Ok(Value::new_undef()) | |
583 | } | |
584 | ||
585 | #[inline] | |
586 | fn visit_seq<V>(self, mut visitor: V) -> Result<Value, V::Error> | |
587 | where | |
588 | V: serde::de::SeqAccess<'de>, | |
589 | { | |
590 | let array = Array::new(); | |
591 | ||
592 | while let Some(elem) = visitor.next_element()? { | |
593 | array.push(elem); | |
594 | } | |
595 | ||
596 | Ok(Value::Array(array)) | |
597 | } | |
598 | ||
599 | fn visit_map<V>(self, mut visitor: V) -> Result<Value, V::Error> | |
600 | where | |
601 | V: serde::de::MapAccess<'de>, | |
602 | { | |
603 | // We use this to hint the deserializer that we're expecting a string-ish value. | |
604 | struct KeyClassifier; | |
605 | struct KeyClass(String); | |
606 | ||
607 | impl<'de> serde::de::DeserializeSeed<'de> for KeyClassifier { | |
608 | type Value = KeyClass; | |
609 | ||
610 | fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> | |
611 | where | |
612 | D: serde::Deserializer<'de>, | |
613 | { | |
614 | deserializer.deserialize_str(self) | |
615 | } | |
616 | } | |
617 | ||
618 | impl<'de> Visitor<'de> for KeyClassifier { | |
619 | type Value = KeyClass; | |
620 | ||
621 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { | |
622 | formatter.write_str("a string key") | |
623 | } | |
624 | ||
625 | fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> | |
626 | where | |
627 | E: serde::de::Error, | |
628 | { | |
629 | Ok(KeyClass(s.to_owned())) | |
630 | } | |
631 | ||
632 | fn visit_string<E>(self, s: String) -> Result<Self::Value, E> | |
633 | where | |
634 | E: serde::de::Error, | |
635 | { | |
636 | Ok(KeyClass(s)) | |
637 | } | |
638 | } | |
639 | ||
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); | |
644 | } | |
645 | Ok(Value::from(hash)) | |
646 | } | |
647 | } | |
648 | ||
649 | if raw_value::is_enabled() { | |
650 | raw_value::RawValue::deserialize(deserializer).map(Value::from) | |
651 | } else { | |
652 | deserializer.deserialize_any(ValueVisitor) | |
653 | } | |
654 | } | |
655 | } |