1 | //! Coerce a `Value` into some concrete types. |
2 | //! |
3 | //! These operations are cheap when the captured value is a simple primitive, |
4 | //! but may end up executing arbitrary caller code if the value is complex. |
5 | //! They will also attempt to downcast erased types into a primitive where possible. |
6 | |
7 | use crate::std::fmt; |
8 | |
9 | #[cfg (feature = "alloc" )] |
10 | use crate::std::{borrow::ToOwned, string::String}; |
11 | |
12 | use super::{Internal, InternalVisitor}; |
13 | use crate::{Error, ValueBag}; |
14 | |
15 | mod primitive; |
16 | |
17 | impl ValueBag<'static> { |
18 | /// Try capture an owned raw value. |
19 | /// |
20 | /// This method will return `Some` if the value is a simple primitive |
21 | /// that can be captured without losing its structure. In other cases |
22 | /// this method will return `None`. |
23 | #[cfg (feature = "owned" )] |
24 | pub fn try_capture_owned<T>(value: &'_ T) -> Option<Self> |
25 | where |
26 | T: ?Sized + 'static, |
27 | { |
28 | primitive::from_owned_any(value) |
29 | } |
30 | } |
31 | |
32 | impl<'v> ValueBag<'v> { |
33 | /// Try capture a raw value. |
34 | /// |
35 | /// This method will return `Some` if the value is a simple primitive |
36 | /// that can be captured without losing its structure. In other cases |
37 | /// this method will return `None`. |
38 | pub fn try_capture<T>(value: &'v T) -> Option<Self> |
39 | where |
40 | T: ?Sized + 'static, |
41 | { |
42 | primitive::from_any(value) |
43 | } |
44 | |
45 | /// Try get a `u64` from this value. |
46 | /// |
47 | /// This method is cheap for primitive types, but may call arbitrary |
48 | /// serialization implementations for complex ones. |
49 | pub fn to_u64(&self) -> Option<u64> { |
50 | self.inner.cast().into_u64() |
51 | } |
52 | |
53 | /// Try get a `i64` from this value. |
54 | /// |
55 | /// This method is cheap for primitive types, but may call arbitrary |
56 | /// serialization implementations for complex ones. |
57 | pub fn to_i64(&self) -> Option<i64> { |
58 | self.inner.cast().into_i64() |
59 | } |
60 | |
61 | /// Try get a `u128` from this value. |
62 | /// |
63 | /// This method is cheap for primitive types, but may call arbitrary |
64 | /// serialization implementations for complex ones. |
65 | pub fn to_u128(&self) -> Option<u128> { |
66 | self.inner.cast().into_u128() |
67 | } |
68 | |
69 | /// Try get a `i128` from this value. |
70 | /// |
71 | /// This method is cheap for primitive types, but may call arbitrary |
72 | /// serialization implementations for complex ones. |
73 | pub fn to_i128(&self) -> Option<i128> { |
74 | self.inner.cast().into_i128() |
75 | } |
76 | |
77 | /// Try get a `f64` from this value. |
78 | /// |
79 | /// This method is cheap for primitive types, but may call arbitrary |
80 | /// serialization implementations for complex ones. |
81 | /// |
82 | /// This method is based on standard `TryInto` conversions, and will |
83 | /// only return `Some` if there's a guaranteed lossless conversion between |
84 | /// the source and destination types. For a more lenient alternative, see |
85 | /// [`ValueBag::as_f64`]. |
86 | pub fn to_f64(&self) -> Option<f64> { |
87 | self.inner.cast().into_f64() |
88 | } |
89 | |
90 | /// Get a `f64` from this value. |
91 | /// |
92 | /// This method is cheap for primitive types, but may call arbitrary |
93 | /// serialization implementations for complex ones. |
94 | /// |
95 | /// This method is like [`ValueBag::to_f64`] except will always return |
96 | /// a `f64`, regardless of the actual type of underlying value. For |
97 | /// numeric types, it will use a regular `as` conversion, which may be lossy. |
98 | /// For non-numeric types it will return `NaN`. |
99 | pub fn as_f64(&self) -> f64 { |
100 | self.inner.cast().as_f64() |
101 | } |
102 | |
103 | /// Try get a `bool` from this value. |
104 | /// |
105 | /// This method is cheap for primitive types, but may call arbitrary |
106 | /// serialization implementations for complex ones. |
107 | pub fn to_bool(&self) -> Option<bool> { |
108 | self.inner.cast().into_bool() |
109 | } |
110 | |
111 | /// Try get a `char` from this value. |
112 | /// |
113 | /// This method is cheap for primitive types, but may call arbitrary |
114 | /// serialization implementations for complex ones. |
115 | pub fn to_char(&self) -> Option<char> { |
116 | self.inner.cast().into_char() |
117 | } |
118 | |
119 | /// Try get a `str` from this value. |
120 | /// |
121 | /// This method is cheap for primitive types. It won't allocate an owned |
122 | /// `String` if the value is a complex type. |
123 | pub fn to_borrowed_str(&self) -> Option<&'v str> { |
124 | self.inner.cast().into_borrowed_str() |
125 | } |
126 | |
127 | /// Check whether this value is empty. |
128 | pub fn is_empty(&self) -> bool { |
129 | matches!(self.inner, Internal::None) |
130 | } |
131 | |
132 | /// Check whether this value can be downcast to `T`. |
133 | pub fn is<T: 'static>(&self) -> bool { |
134 | self.downcast_ref::<T>().is_some() |
135 | } |
136 | |
137 | /// Try downcast this value to `T`. |
138 | pub fn downcast_ref<T: 'static>(&self) -> Option<&T> { |
139 | match self.inner { |
140 | Internal::Debug(value) => value.as_any().downcast_ref(), |
141 | Internal::Display(value) => value.as_any().downcast_ref(), |
142 | #[cfg (feature = "error" )] |
143 | Internal::Error(value) => value.as_any().downcast_ref(), |
144 | #[cfg (feature = "sval2" )] |
145 | Internal::Sval2(value) => value.as_any().downcast_ref(), |
146 | #[cfg (feature = "serde1" )] |
147 | Internal::Serde1(value) => value.as_any().downcast_ref(), |
148 | |
149 | #[cfg (feature = "owned" )] |
150 | Internal::SharedDebug(ref value) => value.as_any().downcast_ref(), |
151 | #[cfg (feature = "owned" )] |
152 | Internal::SharedDisplay(ref value) => value.as_any().downcast_ref(), |
153 | #[cfg (all(feature = "error" , feature = "owned" ))] |
154 | Internal::SharedError(ref value) => value.as_any().downcast_ref(), |
155 | #[cfg (all(feature = "serde1" , feature = "owned" ))] |
156 | Internal::SharedSerde1(ref value) => value.as_any().downcast_ref(), |
157 | #[cfg (all(feature = "sval2" , feature = "owned" ))] |
158 | Internal::SharedSval2(ref value) => value.as_any().downcast_ref(), |
159 | #[cfg (all(feature = "seq" , feature = "owned" ))] |
160 | Internal::SharedSeq(ref value) => value.as_any().downcast_ref(), |
161 | |
162 | #[cfg (feature = "owned" )] |
163 | Internal::SharedRefDebug(value) => value.as_any().downcast_ref(), |
164 | #[cfg (feature = "owned" )] |
165 | Internal::SharedRefDisplay(value) => value.as_any().downcast_ref(), |
166 | #[cfg (all(feature = "error" , feature = "owned" ))] |
167 | Internal::SharedRefError(value) => value.as_any().downcast_ref(), |
168 | #[cfg (all(feature = "serde1" , feature = "owned" ))] |
169 | Internal::SharedRefSerde1(value) => value.as_any().downcast_ref(), |
170 | #[cfg (all(feature = "sval2" , feature = "owned" ))] |
171 | Internal::SharedRefSval2(value) => value.as_any().downcast_ref(), |
172 | #[cfg (all(feature = "seq" , feature = "owned" ))] |
173 | Internal::SharedRefSeq(value) => value.as_any().downcast_ref(), |
174 | |
175 | _ => None, |
176 | } |
177 | } |
178 | } |
179 | |
180 | impl<'v> Internal<'v> { |
181 | /// Cast the inner value to another type. |
182 | #[inline ] |
183 | fn cast(&self) -> Cast<'v> { |
184 | struct CastVisitor<'v>(Cast<'v>); |
185 | |
186 | impl<'v> InternalVisitor<'v> for CastVisitor<'v> { |
187 | #[inline ] |
188 | fn fill(&mut self, v: &dyn crate::fill::Fill) -> Result<(), Error> { |
189 | v.fill(crate::fill::Slot::new(self)) |
190 | } |
191 | |
192 | #[inline ] |
193 | fn debug(&mut self, _: &dyn fmt::Debug) -> Result<(), Error> { |
194 | Ok(()) |
195 | } |
196 | |
197 | #[inline ] |
198 | fn display(&mut self, _: &dyn fmt::Display) -> Result<(), Error> { |
199 | Ok(()) |
200 | } |
201 | |
202 | #[inline ] |
203 | fn u64(&mut self, v: u64) -> Result<(), Error> { |
204 | self.0 = Cast::Unsigned(v); |
205 | Ok(()) |
206 | } |
207 | |
208 | #[inline ] |
209 | fn i64(&mut self, v: i64) -> Result<(), Error> { |
210 | self.0 = Cast::Signed(v); |
211 | Ok(()) |
212 | } |
213 | |
214 | #[inline ] |
215 | fn u128(&mut self, v: &u128) -> Result<(), Error> { |
216 | self.0 = Cast::BigUnsigned(*v); |
217 | Ok(()) |
218 | } |
219 | |
220 | #[inline ] |
221 | fn i128(&mut self, v: &i128) -> Result<(), Error> { |
222 | self.0 = Cast::BigSigned(*v); |
223 | Ok(()) |
224 | } |
225 | |
226 | #[inline ] |
227 | fn f64(&mut self, v: f64) -> Result<(), Error> { |
228 | self.0 = Cast::Float(v); |
229 | Ok(()) |
230 | } |
231 | |
232 | #[inline ] |
233 | fn bool(&mut self, v: bool) -> Result<(), Error> { |
234 | self.0 = Cast::Bool(v); |
235 | Ok(()) |
236 | } |
237 | |
238 | #[inline ] |
239 | fn char(&mut self, v: char) -> Result<(), Error> { |
240 | self.0 = Cast::Char(v); |
241 | Ok(()) |
242 | } |
243 | |
244 | #[cfg (feature = "alloc" )] |
245 | #[inline ] |
246 | fn str(&mut self, s: &str) -> Result<(), Error> { |
247 | self.0 = Cast::String(s.to_owned()); |
248 | Ok(()) |
249 | } |
250 | |
251 | #[cfg (not(feature = "alloc" ))] |
252 | #[inline ] |
253 | fn str(&mut self, _: &str) -> Result<(), Error> { |
254 | Ok(()) |
255 | } |
256 | |
257 | #[inline ] |
258 | fn borrowed_str(&mut self, v: &'v str) -> Result<(), Error> { |
259 | self.0 = Cast::Str(v); |
260 | Ok(()) |
261 | } |
262 | |
263 | #[inline ] |
264 | fn none(&mut self) -> Result<(), Error> { |
265 | self.0 = Cast::None; |
266 | Ok(()) |
267 | } |
268 | |
269 | #[cfg (feature = "error" )] |
270 | #[inline ] |
271 | fn error(&mut self, _: &dyn super::error::Error) -> Result<(), Error> { |
272 | Ok(()) |
273 | } |
274 | |
275 | #[cfg (feature = "sval2" )] |
276 | #[inline ] |
277 | fn sval2(&mut self, v: &dyn super::sval::v2::Value) -> Result<(), Error> { |
278 | if super::sval::v2::internal_visit(v, self) { |
279 | Ok(()) |
280 | } else { |
281 | Err(Error::msg("invalid cast" )) |
282 | } |
283 | } |
284 | |
285 | #[cfg (feature = "sval2" )] |
286 | fn borrowed_sval2(&mut self, v: &'v dyn super::sval::v2::Value) -> Result<(), Error> { |
287 | if super::sval::v2::borrowed_internal_visit(v, self) { |
288 | Ok(()) |
289 | } else { |
290 | Err(Error::msg("invalid cast" )) |
291 | } |
292 | } |
293 | |
294 | #[cfg (feature = "serde1" )] |
295 | #[inline ] |
296 | fn serde1(&mut self, v: &dyn super::serde::v1::Serialize) -> Result<(), Error> { |
297 | if super::serde::v1::internal_visit(v, self) { |
298 | Ok(()) |
299 | } else { |
300 | Err(Error::msg("invalid cast" )) |
301 | } |
302 | } |
303 | |
304 | #[cfg (feature = "seq" )] |
305 | fn seq(&mut self, _: &dyn super::seq::Seq) -> Result<(), Error> { |
306 | self.0 = Cast::None; |
307 | Ok(()) |
308 | } |
309 | |
310 | fn poisoned(&mut self, _: &'static str) -> Result<(), Error> { |
311 | self.0 = Cast::None; |
312 | Ok(()) |
313 | } |
314 | } |
315 | |
316 | match &self { |
317 | Internal::Signed(value) => Cast::Signed(*value), |
318 | Internal::Unsigned(value) => Cast::Unsigned(*value), |
319 | #[cfg (feature = "inline-i128" )] |
320 | Internal::BigSigned(value) => Cast::BigSigned(*value), |
321 | #[cfg (not(feature = "inline-i128" ))] |
322 | Internal::BigSigned(value) => Cast::BigSigned(**value), |
323 | #[cfg (feature = "inline-i128" )] |
324 | Internal::BigUnsigned(value) => Cast::BigUnsigned(*value), |
325 | #[cfg (not(feature = "inline-i128" ))] |
326 | Internal::BigUnsigned(value) => Cast::BigUnsigned(**value), |
327 | Internal::Float(value) => Cast::Float(*value), |
328 | Internal::Bool(value) => Cast::Bool(*value), |
329 | Internal::Char(value) => Cast::Char(*value), |
330 | Internal::Str(value) => Cast::Str(value), |
331 | Internal::None => Cast::None, |
332 | other => { |
333 | // If the erased value isn't a primitive then we visit it |
334 | let mut cast = CastVisitor(Cast::None); |
335 | let _ = other.internal_visit(&mut cast); |
336 | cast.0 |
337 | } |
338 | } |
339 | } |
340 | } |
341 | |
342 | pub(in crate::internal) enum Cast<'v> { |
343 | Signed(i64), |
344 | Unsigned(u64), |
345 | BigSigned(i128), |
346 | BigUnsigned(u128), |
347 | Float(f64), |
348 | Bool(bool), |
349 | Char(char), |
350 | Str(&'v str), |
351 | None, |
352 | #[cfg (feature = "alloc" )] |
353 | String(String), |
354 | } |
355 | |
356 | impl<'v> Cast<'v> { |
357 | #[inline ] |
358 | fn into_borrowed_str(self) -> Option<&'v str> { |
359 | if let Cast::Str(value) = self { |
360 | Some(value) |
361 | } else { |
362 | None |
363 | } |
364 | } |
365 | |
366 | #[inline ] |
367 | fn into_u64(self) -> Option<u64> { |
368 | match self { |
369 | Cast::Unsigned(value) => Some(value), |
370 | Cast::BigUnsigned(value) => value.try_into().ok(), |
371 | Cast::Signed(value) => value.try_into().ok(), |
372 | Cast::BigSigned(value) => value.try_into().ok(), |
373 | _ => None, |
374 | } |
375 | } |
376 | |
377 | #[inline ] |
378 | fn into_i64(self) -> Option<i64> { |
379 | match self { |
380 | Cast::Signed(value) => Some(value), |
381 | Cast::BigSigned(value) => value.try_into().ok(), |
382 | Cast::Unsigned(value) => value.try_into().ok(), |
383 | Cast::BigUnsigned(value) => value.try_into().ok(), |
384 | _ => None, |
385 | } |
386 | } |
387 | |
388 | #[inline ] |
389 | fn into_u128(self) -> Option<u128> { |
390 | match self { |
391 | Cast::BigUnsigned(value) => Some(value), |
392 | Cast::Unsigned(value) => Some(value.into()), |
393 | Cast::Signed(value) => value.try_into().ok(), |
394 | Cast::BigSigned(value) => value.try_into().ok(), |
395 | _ => None, |
396 | } |
397 | } |
398 | |
399 | #[inline ] |
400 | fn into_i128(self) -> Option<i128> { |
401 | match self { |
402 | Cast::BigSigned(value) => Some(value), |
403 | Cast::Signed(value) => Some(value.into()), |
404 | Cast::Unsigned(value) => value.try_into().ok(), |
405 | Cast::BigUnsigned(value) => value.try_into().ok(), |
406 | _ => None, |
407 | } |
408 | } |
409 | |
410 | #[inline ] |
411 | fn into_f64(self) -> Option<f64> { |
412 | match self { |
413 | Cast::Float(value) => Some(value), |
414 | Cast::Unsigned(value) => u32::try_from(value) |
415 | .ok() |
416 | .and_then(|value| value.try_into().ok()), |
417 | Cast::Signed(value) => i32::try_from(value) |
418 | .ok() |
419 | .and_then(|value| value.try_into().ok()), |
420 | Cast::BigUnsigned(value) => u32::try_from(value) |
421 | .ok() |
422 | .and_then(|value| value.try_into().ok()), |
423 | Cast::BigSigned(value) => i32::try_from(value) |
424 | .ok() |
425 | .and_then(|value| value.try_into().ok()), |
426 | _ => None, |
427 | } |
428 | } |
429 | |
430 | #[inline ] |
431 | fn as_f64(self) -> f64 { |
432 | match self { |
433 | Cast::Float(value) => value, |
434 | Cast::Unsigned(value) => value as f64, |
435 | Cast::Signed(value) => value as f64, |
436 | Cast::BigUnsigned(value) => value as f64, |
437 | Cast::BigSigned(value) => value as f64, |
438 | _ => f64::NAN, |
439 | } |
440 | } |
441 | |
442 | #[inline ] |
443 | fn into_char(self) -> Option<char> { |
444 | if let Cast::Char(value) = self { |
445 | Some(value) |
446 | } else { |
447 | None |
448 | } |
449 | } |
450 | |
451 | #[inline ] |
452 | fn into_bool(self) -> Option<bool> { |
453 | if let Cast::Bool(value) = self { |
454 | Some(value) |
455 | } else { |
456 | None |
457 | } |
458 | } |
459 | } |
460 | |
461 | #[cfg (feature = "alloc" )] |
462 | mod alloc_support { |
463 | use super::*; |
464 | |
465 | use crate::std::borrow::Cow; |
466 | |
467 | impl<'v> ValueBag<'v> { |
468 | /// Try get a `str` from this value. |
469 | /// |
470 | /// This method is cheap for primitive types, but may call arbitrary |
471 | /// serialization implementations for complex ones. If the serialization |
472 | /// implementation produces a short lived string it will be allocated. |
473 | #[inline ] |
474 | pub fn to_str(&self) -> Option<Cow<'v, str>> { |
475 | self.inner.cast().into_str() |
476 | } |
477 | } |
478 | |
479 | impl<'v> Cast<'v> { |
480 | #[inline ] |
481 | pub(in crate::internal) fn into_str(self) -> Option<Cow<'v, str>> { |
482 | match self { |
483 | Cast::Str(value) => Some(value.into()), |
484 | Cast::String(value) => Some(value.into()), |
485 | _ => None, |
486 | } |
487 | } |
488 | } |
489 | |
490 | #[cfg (test)] |
491 | mod tests { |
492 | #[cfg (target_arch = "wasm32" )] |
493 | use wasm_bindgen_test::*; |
494 | |
495 | use crate::{std::borrow::ToOwned, test::IntoValueBag, ValueBag}; |
496 | |
497 | #[test ] |
498 | #[cfg_attr (target_arch = "wasm32" , wasm_bindgen_test)] |
499 | fn primitive_cast() { |
500 | let short_lived = "a string" .to_owned(); |
501 | assert_eq!( |
502 | "a string" , |
503 | (&*short_lived) |
504 | .into_value_bag() |
505 | .to_borrowed_str() |
506 | .expect("invalid value" ) |
507 | ); |
508 | assert_eq!( |
509 | "a string" , |
510 | &*"a string" .into_value_bag().to_str().expect("invalid value" ) |
511 | ); |
512 | assert_eq!( |
513 | "a string" , |
514 | (&*short_lived) |
515 | .into_value_bag() |
516 | .to_borrowed_str() |
517 | .expect("invalid value" ) |
518 | ); |
519 | assert_eq!( |
520 | "a string" , |
521 | ValueBag::try_capture(&short_lived) |
522 | .expect("invalid value" ) |
523 | .to_borrowed_str() |
524 | .expect("invalid value" ) |
525 | ); |
526 | } |
527 | } |
528 | } |
529 | |
530 | #[cfg (test)] |
531 | mod tests { |
532 | #[cfg (target_arch = "wasm32" )] |
533 | use wasm_bindgen_test::*; |
534 | |
535 | use super::*; |
536 | |
537 | use crate::test::IntoValueBag; |
538 | |
539 | #[test ] |
540 | #[cfg_attr (target_arch = "wasm32" , wasm_bindgen_test)] |
541 | fn is_empty() { |
542 | assert!(ValueBag::from(None::<i32>).is_empty(),); |
543 | |
544 | assert!(ValueBag::try_capture(&None::<i32>).unwrap().is_empty(),); |
545 | } |
546 | |
547 | #[test ] |
548 | #[cfg_attr (target_arch = "wasm32" , wasm_bindgen_test)] |
549 | fn primitive_capture_str() { |
550 | let s: &str = "short lived" ; |
551 | assert_eq!( |
552 | "short lived" , |
553 | ValueBag::try_capture(s) |
554 | .unwrap() |
555 | .to_borrowed_str() |
556 | .expect("invalid value" ) |
557 | ); |
558 | } |
559 | |
560 | #[test ] |
561 | #[cfg_attr (target_arch = "wasm32" , wasm_bindgen_test)] |
562 | fn primitive_cast() { |
563 | assert_eq!( |
564 | "a string" , |
565 | "a string" |
566 | .into_value_bag() |
567 | .by_ref() |
568 | .to_borrowed_str() |
569 | .expect("invalid value" ) |
570 | ); |
571 | |
572 | assert_eq!( |
573 | 1u64, |
574 | 1u8.into_value_bag() |
575 | .by_ref() |
576 | .to_u64() |
577 | .expect("invalid value" ) |
578 | ); |
579 | assert_eq!( |
580 | 1u64, |
581 | 1u16.into_value_bag() |
582 | .by_ref() |
583 | .to_u64() |
584 | .expect("invalid value" ) |
585 | ); |
586 | assert_eq!( |
587 | 1u64, |
588 | 1u32.into_value_bag() |
589 | .by_ref() |
590 | .to_u64() |
591 | .expect("invalid value" ) |
592 | ); |
593 | assert_eq!( |
594 | 1u64, |
595 | 1u64.into_value_bag() |
596 | .by_ref() |
597 | .to_u64() |
598 | .expect("invalid value" ) |
599 | ); |
600 | assert_eq!( |
601 | 1u64, |
602 | 1usize |
603 | .into_value_bag() |
604 | .by_ref() |
605 | .to_u64() |
606 | .expect("invalid value" ) |
607 | ); |
608 | assert_eq!( |
609 | 1u128, |
610 | 1u128 |
611 | .into_value_bag() |
612 | .by_ref() |
613 | .to_u128() |
614 | .expect("invalid value" ) |
615 | ); |
616 | |
617 | assert_eq!( |
618 | -1i64, |
619 | -(1i8 |
620 | .into_value_bag() |
621 | .by_ref() |
622 | .to_i64() |
623 | .expect("invalid value" )) |
624 | ); |
625 | assert_eq!( |
626 | -1i64, |
627 | -(1i8 |
628 | .into_value_bag() |
629 | .by_ref() |
630 | .to_i64() |
631 | .expect("invalid value" )) |
632 | ); |
633 | assert_eq!( |
634 | -1i64, |
635 | -(1i8 |
636 | .into_value_bag() |
637 | .by_ref() |
638 | .to_i64() |
639 | .expect("invalid value" )) |
640 | ); |
641 | assert_eq!( |
642 | -1i64, |
643 | -(1i64 |
644 | .into_value_bag() |
645 | .by_ref() |
646 | .to_i64() |
647 | .expect("invalid value" )) |
648 | ); |
649 | assert_eq!( |
650 | -1i64, |
651 | -(1isize |
652 | .into_value_bag() |
653 | .by_ref() |
654 | .to_i64() |
655 | .expect("invalid value" )) |
656 | ); |
657 | assert_eq!( |
658 | -1i128, |
659 | -(1i128 |
660 | .into_value_bag() |
661 | .by_ref() |
662 | .to_i128() |
663 | .expect("invalid value" )) |
664 | ); |
665 | |
666 | assert!(1f64.into_value_bag().by_ref().to_f64().is_some()); |
667 | assert!(1u64.into_value_bag().by_ref().to_f64().is_some()); |
668 | assert!((-1i64).into_value_bag().by_ref().to_f64().is_some()); |
669 | assert!(1u128.into_value_bag().by_ref().to_f64().is_some()); |
670 | assert!((-1i128).into_value_bag().by_ref().to_f64().is_some()); |
671 | |
672 | assert!(u64::MAX.into_value_bag().by_ref().to_u128().is_some()); |
673 | assert!(i64::MIN.into_value_bag().by_ref().to_i128().is_some()); |
674 | assert!(i64::MAX.into_value_bag().by_ref().to_u64().is_some()); |
675 | |
676 | assert!((-1i64).into_value_bag().by_ref().to_u64().is_none()); |
677 | assert!(u64::MAX.into_value_bag().by_ref().to_i64().is_none()); |
678 | assert!(u64::MAX.into_value_bag().by_ref().to_f64().is_none()); |
679 | |
680 | assert!(i128::MAX.into_value_bag().by_ref().to_i64().is_none()); |
681 | assert!(u128::MAX.into_value_bag().by_ref().to_u64().is_none()); |
682 | |
683 | assert!(1f64.into_value_bag().by_ref().to_u64().is_none()); |
684 | |
685 | assert_eq!( |
686 | 'a' , |
687 | 'a' .into_value_bag() |
688 | .by_ref() |
689 | .to_char() |
690 | .expect("invalid value" ) |
691 | ); |
692 | assert!(true |
693 | .into_value_bag() |
694 | .by_ref() |
695 | .to_bool() |
696 | .expect("invalid value" )); |
697 | } |
698 | |
699 | #[test ] |
700 | fn as_cast() { |
701 | assert_eq!(1.0, 1f64.into_value_bag().as_f64()); |
702 | assert_eq!(1.0, 1u64.into_value_bag().as_f64()); |
703 | assert_eq!(-1.0, -(1i64.into_value_bag().as_f64())); |
704 | assert!(true.into_value_bag().as_f64().is_nan()); |
705 | } |
706 | } |
707 | |