1use crate::{
2 internal::{self, Internal},
3 std::sync::Arc,
4 ValueBag,
5};
6
7#[derive(Clone)]
16pub struct OwnedValueBag {
17 inner: internal::owned::OwnedInternal,
18}
19
20impl<'v> ValueBag<'v> {
21 pub fn to_owned(&self) -> OwnedValueBag {
23 OwnedValueBag {
24 inner: self.inner.to_owned(),
25 }
26 }
27
28 pub fn to_shared(&self) -> OwnedValueBag {
31 self.to_owned().into_shared()
32 }
33}
34
35impl ValueBag<'static> {
36 pub fn capture_shared_debug<T>(value: T) -> Self
43 where
44 T: internal::fmt::Debug + Send + Sync + 'static,
45 {
46 Self::try_capture_owned(&value).unwrap_or_else(|| ValueBag {
47 inner: Internal::SharedDebug(Arc::new(value)),
48 })
49 }
50
51 pub fn capture_shared_display<T>(value: T) -> Self
58 where
59 T: internal::fmt::Display + Send + Sync + 'static,
60 {
61 Self::try_capture_owned(&value).unwrap_or_else(|| ValueBag {
62 inner: Internal::SharedDisplay(Arc::new(value)),
63 })
64 }
65
66 #[cfg(feature = "error")]
70 pub fn capture_shared_error<T>(value: T) -> Self
71 where
72 T: internal::error::Error + Send + Sync + 'static,
73 {
74 ValueBag {
75 inner: Internal::SharedError(Arc::new(value)),
76 }
77 }
78
79 #[cfg(feature = "sval2")]
86 pub fn capture_shared_sval2<T>(value: T) -> Self
87 where
88 T: value_bag_sval2::lib::Value + Send + Sync + 'static,
89 {
90 Self::try_capture_owned(&value).unwrap_or(ValueBag {
91 inner: Internal::SharedSval2(Arc::new(value)),
92 })
93 }
94
95 #[cfg(feature = "serde1")]
102 pub fn capture_shared_serde1<T>(value: T) -> Self
103 where
104 T: value_bag_serde1::lib::Serialize + Send + Sync + 'static,
105 {
106 Self::try_capture_owned(&value).unwrap_or(ValueBag {
107 inner: Internal::SharedSerde1(Arc::new(value)),
108 })
109 }
110
111 #[cfg(feature = "seq")]
115 pub fn capture_shared_seq_slice<I, T>(value: I) -> Self
116 where
117 I: AsRef<[T]> + Send + Sync + 'static,
118 T: Send + Sync + 'static,
119 for<'v> &'v T: Into<ValueBag<'v>>,
120 {
121 use crate::{
122 internal::seq::Visitor,
123 std::{marker::PhantomData, ops::ControlFlow},
124 };
125
126 struct OwnedSeqSlice<I: ?Sized, T>(PhantomData<[T]>, I);
127
128 impl<I, T> internal::seq::Seq for OwnedSeqSlice<I, T>
129 where
130 I: AsRef<[T]> + ?Sized,
131 for<'v> &'v T: Into<ValueBag<'v>>,
132 {
133 fn visit(&self, visitor: &mut dyn Visitor<'_>) {
134 for v in self.1.as_ref().iter() {
135 if let ControlFlow::Break(()) = visitor.element(v.into()) {
136 return;
137 }
138 }
139 }
140 }
141
142 Self::try_capture_owned(&value).unwrap_or(ValueBag {
143 inner: Internal::SharedSeq(Arc::new(OwnedSeqSlice(PhantomData, value))),
144 })
145 }
146}
147
148impl OwnedValueBag {
149 pub const fn by_ref(&self) -> ValueBag<'_> {
158 ValueBag {
159 inner: self.inner.by_ref(),
160 }
161 }
162
163 pub fn into_shared(self) -> Self {
167 OwnedValueBag {
168 inner: self.inner.into_shared(),
169 }
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 #[cfg(target_arch = "wasm32")]
176 use wasm_bindgen_test::*;
177
178 use super::*;
179
180 use crate::{
181 fill,
182 std::{mem, string::ToString},
183 };
184
185 #[cfg(not(feature = "inline-str-l"))]
186 const SIZE_LIMIT_U64: usize = 4;
187 #[cfg(feature = "inline-str-l")]
188 const SIZE_LIMIT_U64: usize = 6;
189
190 #[test]
191 fn is_send_sync() {
192 fn assert<T: Send + Sync + 'static>() {}
193
194 assert::<OwnedValueBag>();
195 }
196
197 #[test]
198 fn owned_value_bag_size() {
199 let size = mem::size_of::<OwnedValueBag>();
200 let limit = mem::size_of::<u64>() * SIZE_LIMIT_U64;
201
202 if size > limit {
203 panic!(
204 "`OwnedValueBag` size ({} bytes) is too large (expected up to {} bytes)",
205 size, limit,
206 );
207 }
208 }
209
210 #[test]
211 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
212 fn fill_to_owned() {
213 let value = ValueBag::from_fill(&|slot: fill::Slot| slot.fill_any(42u64)).to_owned();
214
215 assert!(matches!(
216 value.inner,
217 internal::owned::OwnedInternal::BigUnsigned(42)
218 ));
219 }
220
221 #[test]
222 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
223 fn fill_to_shared() {
224 let value = ValueBag::from_fill(&|slot: fill::Slot| slot.fill_any(42u64)).to_shared();
225
226 assert!(matches!(
227 value.inner,
228 internal::owned::OwnedInternal::BigUnsigned(42)
229 ));
230 }
231
232 #[test]
233 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
234 fn fmt_to_owned() {
235 let debug = ValueBag::from_debug(&"a value").to_owned();
236 let display = ValueBag::from_display(&"a value").to_owned();
237
238 #[cfg(not(feature = "inline-str"))]
239 {
240 assert!(matches!(
241 debug.inner,
242 internal::owned::OwnedInternal::Debug(_)
243 ));
244 assert!(matches!(
245 display.inner,
246 internal::owned::OwnedInternal::Display(_)
247 ));
248 }
249 #[cfg(feature = "inline-str")]
250 {
251 assert!(matches!(
252 debug.inner,
253 internal::owned::OwnedInternal::SmallDebug(_)
254 ));
255 assert!(matches!(
256 display.inner,
257 internal::owned::OwnedInternal::SmallDisplay(_)
258 ));
259 }
260
261 assert_eq!("\"a value\"", debug.to_string());
262 assert_eq!("a value", display.to_string());
263
264 let debug = debug.by_ref();
265 let display = display.by_ref();
266
267 assert!(matches!(debug.inner, internal::Internal::AnonDebug(_)));
268 assert!(matches!(display.inner, internal::Internal::AnonDisplay(_)));
269 }
270
271 #[test]
272 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
273 fn fmt_to_owned_l() {
274 let debug =
275 ValueBag::from_debug(&"a value that occupies too much space to ever be stored inline")
276 .to_owned();
277 let display = ValueBag::from_display(
278 &"a value that occupies too much space to ever be stored inline",
279 )
280 .to_owned();
281
282 assert!(matches!(
283 debug.inner,
284 internal::owned::OwnedInternal::Debug(_)
285 ));
286 assert!(matches!(
287 display.inner,
288 internal::owned::OwnedInternal::Display(_)
289 ));
290
291 assert_eq!(
292 "\"a value that occupies too much space to ever be stored inline\"",
293 debug.to_string()
294 );
295 assert_eq!(
296 "a value that occupies too much space to ever be stored inline",
297 display.to_string()
298 );
299
300 let debug = debug.by_ref();
301 let display = display.by_ref();
302
303 assert!(matches!(debug.inner, internal::Internal::AnonDebug(_)));
304 assert!(matches!(display.inner, internal::Internal::AnonDisplay(_)));
305 }
306
307 #[test]
308 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
309 fn fmt_to_shared() {
310 let debug = ValueBag::from_debug(&"a value").to_shared();
311 let display = ValueBag::from_display(&"a value").to_shared();
312
313 #[cfg(not(feature = "inline-str"))]
314 {
315 assert!(matches!(
316 debug.inner,
317 internal::owned::OwnedInternal::SharedDebug(_)
318 ));
319 assert!(matches!(
320 display.inner,
321 internal::owned::OwnedInternal::SharedDisplay(_)
322 ));
323 }
324 #[cfg(feature = "inline-str")]
325 {
326 assert!(matches!(
327 debug.inner,
328 internal::owned::OwnedInternal::SmallDebug(_)
329 ));
330 assert!(matches!(
331 display.inner,
332 internal::owned::OwnedInternal::SmallDisplay(_)
333 ));
334 }
335 }
336
337 #[test]
338 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
339 fn owned_fmt_to_owned() {
340 let debug = ValueBag::capture_shared_debug("a value".to_string()).to_owned();
341 let display = ValueBag::capture_shared_display("a value".to_string()).to_owned();
342
343 assert!(matches!(
344 debug.inner,
345 internal::owned::OwnedInternal::SharedDebug(_)
346 ));
347 assert!(matches!(
348 display.inner,
349 internal::owned::OwnedInternal::SharedDisplay(_)
350 ));
351
352 assert_eq!("\"a value\"", debug.to_string());
353 assert_eq!("a value", display.to_string());
354
355 let debug = debug.by_ref();
356 let display = display.by_ref();
357
358 assert!(matches!(debug.inner, internal::Internal::SharedRefDebug(_)));
359 assert!(matches!(
360 display.inner,
361 internal::Internal::SharedRefDisplay(_)
362 ));
363 }
364
365 #[test]
366 #[cfg(feature = "error")]
367 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
368 fn error_to_owned() {
369 use crate::std::io;
370
371 let value =
372 ValueBag::from_dyn_error(&io::Error::new(io::ErrorKind::Other, "something failed!"))
373 .to_owned();
374
375 assert!(matches!(
376 value.inner,
377 internal::owned::OwnedInternal::Error(_)
378 ));
379
380 let value = value.by_ref();
381
382 assert!(matches!(value.inner, internal::Internal::AnonError(_)));
383
384 assert!(value.to_borrowed_error().is_some());
385 }
386
387 #[test]
388 #[cfg(feature = "error")]
389 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
390 fn error_to_shared() {
391 use crate::std::io;
392
393 let value =
394 ValueBag::from_dyn_error(&io::Error::new(io::ErrorKind::Other, "something failed!"))
395 .to_shared();
396
397 assert!(matches!(
398 value.inner,
399 internal::owned::OwnedInternal::SharedError(_)
400 ));
401 }
402
403 #[test]
404 #[cfg(feature = "error")]
405 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
406 fn owned_error_to_owned() {
407 use crate::std::io;
408
409 let value = ValueBag::capture_shared_error(io::Error::new(
410 io::ErrorKind::Other,
411 "something failed!",
412 ))
413 .to_owned();
414
415 assert!(matches!(
416 value.inner,
417 internal::owned::OwnedInternal::SharedError(_)
418 ));
419
420 let value = value.by_ref();
421
422 assert!(matches!(value.inner, internal::Internal::SharedRefError(_)));
423 }
424
425 #[test]
426 #[cfg(feature = "serde1")]
427 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
428 fn serde1_to_owned() {
429 let value = ValueBag::from_serde1(&42u64).to_owned();
430
431 assert!(matches!(
432 value.inner,
433 internal::owned::OwnedInternal::Serde1(_)
434 ));
435
436 let value = value.by_ref();
437
438 assert!(matches!(value.inner, internal::Internal::AnonSerde1(_)));
439 }
440
441 #[test]
442 #[cfg(feature = "serde1")]
443 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
444 fn serde1_to_shared() {
445 let value = ValueBag::from_serde1(&42u64).to_shared();
446
447 assert!(matches!(
448 value.inner,
449 internal::owned::OwnedInternal::SharedSerde1(_)
450 ));
451 }
452
453 #[test]
454 #[cfg(feature = "serde1")]
455 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
456 fn owned_serde1_to_owned() {
457 let value = ValueBag::capture_shared_serde1("a value".to_string()).to_owned();
458
459 assert!(matches!(
460 value.inner,
461 internal::owned::OwnedInternal::SharedSerde1(_)
462 ));
463
464 let value = value.by_ref();
465
466 assert!(matches!(
467 value.inner,
468 internal::Internal::SharedRefSerde1(_)
469 ));
470 }
471
472 #[test]
473 #[cfg(feature = "sval2")]
474 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
475 fn sval2_to_owned() {
476 let value = ValueBag::from_sval2(&42u64).to_owned();
477
478 assert!(matches!(
479 value.inner,
480 internal::owned::OwnedInternal::Sval2(_)
481 ));
482
483 let value = value.by_ref();
484
485 assert!(matches!(value.inner, internal::Internal::AnonSval2(_)));
486 }
487
488 #[test]
489 #[cfg(feature = "sval2")]
490 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
491 fn sval2_to_shared() {
492 let value = ValueBag::from_sval2(&42u64).to_shared();
493
494 assert!(matches!(
495 value.inner,
496 internal::owned::OwnedInternal::SharedSval2(_)
497 ));
498 }
499
500 #[test]
501 #[cfg(feature = "sval2")]
502 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
503 fn owned_sval2_to_owned() {
504 let value = ValueBag::capture_shared_sval2("a value".to_string()).to_owned();
505
506 assert!(matches!(
507 value.inner,
508 internal::owned::OwnedInternal::SharedSval2(_)
509 ));
510
511 let value = value.by_ref();
512
513 assert!(matches!(value.inner, internal::Internal::SharedRefSval2(_)));
514 }
515
516 #[test]
517 #[cfg(feature = "seq")]
518 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
519 fn seq_to_owned() {
520 let value = ValueBag::from_seq_slice(&[1, 2, 3]).to_owned();
521
522 assert!(matches!(
523 value.inner,
524 internal::owned::OwnedInternal::Seq(_)
525 ));
526
527 let value = value.by_ref();
528
529 assert!(matches!(value.inner, internal::Internal::AnonSeq(_)));
530 }
531
532 #[test]
533 #[cfg(feature = "seq")]
534 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
535 fn seq_to_shared() {
536 let value = ValueBag::from_seq_slice(&[1, 2, 3]).to_shared();
537
538 assert!(matches!(
539 value.inner,
540 internal::owned::OwnedInternal::SharedSeq(_)
541 ));
542 }
543
544 #[test]
545 #[cfg(feature = "seq")]
546 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
547 fn owned_seq_to_owned() {
548 let value = ValueBag::capture_shared_seq_slice(vec![1, 2, 3]).to_owned();
549
550 assert!(matches!(
551 value.inner,
552 internal::owned::OwnedInternal::SharedSeq(_)
553 ));
554
555 let value = value.by_ref();
556
557 assert!(matches!(value.inner, internal::Internal::SharedRefSeq(_)));
558 }
559}