1use crate::std::fmt;
8
9#[cfg(feature = "alloc")]
10use crate::std::{borrow::ToOwned, string::String};
11
12use super::{Internal, InternalVisitor};
13use crate::{Error, ValueBag};
14
15mod primitive;
16
17impl ValueBag<'static> {
18 #[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
32impl<'v> ValueBag<'v> {
33 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 pub fn to_u64(&self) -> Option<u64> {
50 self.inner.cast().into_u64()
51 }
52
53 pub fn to_i64(&self) -> Option<i64> {
58 self.inner.cast().into_i64()
59 }
60
61 pub fn to_u128(&self) -> Option<u128> {
66 self.inner.cast().into_u128()
67 }
68
69 pub fn to_i128(&self) -> Option<i128> {
74 self.inner.cast().into_i128()
75 }
76
77 pub fn to_f64(&self) -> Option<f64> {
87 self.inner.cast().into_f64()
88 }
89
90 pub fn as_f64(&self) -> f64 {
100 self.inner.cast().as_f64()
101 }
102
103 pub fn to_bool(&self) -> Option<bool> {
108 self.inner.cast().into_bool()
109 }
110
111 pub fn to_char(&self) -> Option<char> {
116 self.inner.cast().into_char()
117 }
118
119 pub fn to_borrowed_str(&self) -> Option<&'v str> {
124 self.inner.cast().into_borrowed_str()
125 }
126
127 pub fn is_empty(&self) -> bool {
129 matches!(self.inner, Internal::None)
130 }
131
132 pub fn is<T: 'static>(&self) -> bool {
134 self.downcast_ref::<T>().is_some()
135 }
136
137 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
180impl<'v> Internal<'v> {
181 #[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 let mut cast = CastVisitor(Cast::None);
335 let _ = other.internal_visit(&mut cast);
336 cast.0
337 }
338 }
339 }
340}
341
342pub(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
356impl<'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")]
462mod alloc_support {
463 use super::*;
464
465 use crate::std::borrow::Cow;
466
467 impl<'v> ValueBag<'v> {
468 #[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)]
531mod 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}