1use core::{borrow::Borrow, fmt, ops::ControlFlow};
14
15use crate::{
16 and::And,
17 empty::Empty,
18 str::{Str, ToStr},
19 value::{FromValue, ToValue, Value},
20};
21
22pub trait Props {
36 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
44 &'kv self,
45 for_each: F,
46 ) -> ControlFlow<()>;
47
48 fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
58 let key = key.to_str();
59 let mut value = None;
60
61 let _ = self.for_each(|k, v| {
62 if k == key {
63 value = Some(v);
64
65 ControlFlow::Break(())
66 } else {
67 ControlFlow::Continue(())
68 }
69 });
70
71 value
72 }
73
74 fn pull<'kv, V: FromValue<'kv>, K: ToStr>(&'kv self, key: K) -> Option<V> {
82 self.get(key).and_then(|v| v.cast())
83 }
84
85 fn and_props<U: Props>(self, other: U) -> And<Self, U>
89 where
90 Self: Sized,
91 {
92 And::new(self, other)
93 }
94
95 fn collect<'kv, C: FromProps<'kv>>(&'kv self) -> C {
101 C::from_props(self)
102 }
103
104 fn as_map(&self) -> &AsMap<Self>
108 where
109 Self: Sized,
110 {
111 AsMap::new(self)
112 }
113
114 #[cfg(feature = "alloc")]
120 fn dedup(&self) -> &Dedup<Self>
121 where
122 Self: Sized,
123 {
124 Dedup::new(self)
125 }
126
127 fn is_unique(&self) -> bool {
133 false
134 }
135
136 fn size(&self) -> Option<usize> {
144 None
145 }
146}
147
148impl<'a, P: Props + ?Sized> Props for &'a P {
149 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
150 &'kv self,
151 for_each: F,
152 ) -> ControlFlow<()> {
153 (**self).for_each(for_each)
154 }
155
156 fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
157 (**self).get(key)
158 }
159
160 fn pull<'kv, V: FromValue<'kv>, K: ToStr>(&'kv self, key: K) -> Option<V> {
161 (**self).pull(key)
162 }
163
164 fn is_unique(&self) -> bool {
165 (**self).is_unique()
166 }
167
168 fn size(&self) -> Option<usize> {
169 (**self).size()
170 }
171}
172
173impl<P: Props> Props for Option<P> {
174 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
175 &'kv self,
176 for_each: F,
177 ) -> ControlFlow<()> {
178 match self {
179 Some(props) => props.for_each(for_each),
180 None => ControlFlow::Continue(()),
181 }
182 }
183
184 fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
185 match self {
186 Some(props) => props.get(key),
187 None => None,
188 }
189 }
190
191 fn pull<'kv, V: FromValue<'kv>, K: ToStr>(&'kv self, key: K) -> Option<V> {
192 match self {
193 Some(props) => props.pull(key),
194 None => None,
195 }
196 }
197
198 fn is_unique(&self) -> bool {
199 match self {
200 Some(props) => props.is_unique(),
201 None => true,
202 }
203 }
204
205 fn size(&self) -> Option<usize> {
206 match self {
207 Some(props) => props.size(),
208 None => Some(0),
209 }
210 }
211}
212
213#[cfg(feature = "alloc")]
214impl<'a, P: Props + ?Sized + 'a> Props for alloc::boxed::Box<P> {
215 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
216 &'kv self,
217 for_each: F,
218 ) -> ControlFlow<()> {
219 (**self).for_each(for_each)
220 }
221
222 fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
223 (**self).get(key)
224 }
225
226 fn pull<'kv, V: FromValue<'kv>, K: ToStr>(&'kv self, key: K) -> Option<V> {
227 (**self).pull(key)
228 }
229
230 fn is_unique(&self) -> bool {
231 (**self).is_unique()
232 }
233
234 fn size(&self) -> Option<usize> {
235 (**self).size()
236 }
237}
238
239#[cfg(feature = "alloc")]
240impl<'a, P: Props + ?Sized + 'a> Props for alloc::sync::Arc<P> {
241 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
242 &'kv self,
243 for_each: F,
244 ) -> ControlFlow<()> {
245 (**self).for_each(for_each)
246 }
247
248 fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
249 (**self).get(key)
250 }
251
252 fn pull<'kv, V: FromValue<'kv>, K: ToStr>(&'kv self, key: K) -> Option<V> {
253 (**self).pull(key)
254 }
255
256 fn is_unique(&self) -> bool {
257 (**self).is_unique()
258 }
259
260 fn size(&self) -> Option<usize> {
261 (**self).size()
262 }
263}
264
265impl<K: ToStr, V: ToValue> Props for (K, V) {
266 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
267 &'kv self,
268 mut for_each: F,
269 ) -> ControlFlow<()> {
270 for_each(self.0.to_str(), self.1.to_value())
271 }
272
273 fn get<'v, G: ToStr>(&'v self, key: G) -> Option<Value<'v>> {
274 if key.to_str() == self.0.to_str() {
275 Some(self.1.to_value())
276 } else {
277 None
278 }
279 }
280
281 fn is_unique(&self) -> bool {
282 true
283 }
284
285 fn size(&self) -> Option<usize> {
286 Some(1)
287 }
288}
289
290impl<P: Props> Props for [P] {
291 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
292 &'kv self,
293 mut for_each: F,
294 ) -> ControlFlow<()> {
295 for p in self {
296 p.for_each(&mut for_each)?;
297 }
298
299 ControlFlow::Continue(())
300 }
301
302 fn get<'v, G: ToStr>(&'v self, key: G) -> Option<Value<'v>> {
303 let key = key.to_str();
304
305 for p in self {
306 if let Some(value) = p.get(key.by_ref()) {
307 return Some(value);
308 }
309 }
310
311 None
312 }
313
314 fn size(&self) -> Option<usize> {
315 let mut size = 0;
316
317 for p in self {
318 size += p.size()?;
319 }
320
321 Some(size)
322 }
323}
324
325impl<T, const N: usize> Props for [T; N]
326where
327 [T]: Props,
328{
329 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
330 &'kv self,
331 for_each: F,
332 ) -> ControlFlow<()> {
333 Props::for_each(self as &[_], for_each)
334 }
335
336 fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
337 Props::get(self as &[_], key)
338 }
339
340 fn pull<'kv, V: FromValue<'kv>, K: ToStr>(&'kv self, key: K) -> Option<V> {
341 Props::pull(self as &[_], key)
342 }
343
344 fn is_unique(&self) -> bool {
345 Props::is_unique(self as &[_])
346 }
347
348 fn size(&self) -> Option<usize> {
349 Props::size(self as &[_])
350 }
351}
352
353impl Props for Empty {
354 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
355 &'kv self,
356 _: F,
357 ) -> ControlFlow<()> {
358 ControlFlow::Continue(())
359 }
360
361 fn get<'v, K: ToStr>(&'v self, _: K) -> Option<Value<'v>> {
362 None
363 }
364
365 fn is_unique(&self) -> bool {
366 true
367 }
368
369 fn size(&self) -> Option<usize> {
370 Some(0)
371 }
372}
373
374impl<A: Props, B: Props> Props for And<A, B> {
375 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
376 &'kv self,
377 mut for_each: F,
378 ) -> ControlFlow<()> {
379 self.left().for_each(&mut for_each)?;
380 self.right().for_each(for_each)
381 }
382
383 fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
384 let key = key.borrow();
385
386 self.left().get(key).or_else(|| self.right().get(key))
387 }
388
389 fn size(&self) -> Option<usize> {
390 Some(self.left().size()? + self.right().size()?)
391 }
392}
393
394pub trait FromProps<'kv> {
398 fn from_props<P: Props + ?Sized>(props: &'kv P) -> Self;
405}
406
407#[cfg(feature = "alloc")]
408impl<'kv, 'a, C: FromProps<'kv> + 'a> FromProps<'kv> for alloc::boxed::Box<C> {
409 fn from_props<P: Props + ?Sized>(props: &'kv P) -> Self {
410 alloc::boxed::Box::new(C::from_props(props))
411 }
412}
413
414#[cfg(feature = "alloc")]
415impl<'kv, 'a, C: FromProps<'kv> + 'a> FromProps<'kv> for alloc::sync::Arc<C> {
416 fn from_props<P: Props + ?Sized>(props: &'kv P) -> Self {
417 alloc::sync::Arc::new(C::from_props(props))
418 }
419}
420
421#[cfg(feature = "alloc")]
422mod alloc_support {
423 use super::*;
424
425 use crate::value::OwnedValue;
426
427 use core::{cmp, iter, mem, ptr};
428
429 use alloc::{boxed::Box, collections::BTreeMap, sync::Arc, vec::Vec};
430
431 pub struct OwnedProps {
442 buckets: *const [OwnedPropsBucket],
443 nprops: usize,
444 owner: OwnedPropsOwner,
445 head: Option<*const OwnedProp>,
446 }
447
448 unsafe impl Send for OwnedProps {}
450 unsafe impl Sync for OwnedProps {}
452
453 impl Clone for OwnedProps {
454 fn clone(&self) -> Self {
455 match self.owner {
456 OwnedPropsOwner::Box(_) => {
457 let (nprops, props, head) = OwnedProps::cloned(self);
458
459 OwnedProps::new_owned(nprops, props, head)
460 }
461 OwnedPropsOwner::Shared(ref props) => {
462 OwnedProps::new_shared(self.nprops, props.clone(), self.head)
463 }
464 }
465 }
466 }
467
468 impl Drop for OwnedProps {
469 fn drop(&mut self) {
470 match self.owner {
471 OwnedPropsOwner::Box(boxed) => {
472 drop(unsafe { Box::from_raw(boxed) });
474 }
475 OwnedPropsOwner::Shared(_) => {
476 }
478 }
479 }
480 }
481
482 struct OwnedPropsBucket {
483 head: *mut OwnedProp,
484 tail: Vec<*mut OwnedProp>,
485 }
486
487 impl Drop for OwnedPropsBucket {
488 fn drop(&mut self) {
489 let mut guard = SliceDropGuard::new(&mut self.tail);
490
491 if !self.head.is_null() {
492 drop(unsafe { Box::from_raw(self.head) })
494 }
495
496 unsafe {
498 guard.drop();
499 }
500 }
501 }
502
503 struct OwnedProp {
504 key: Str<'static>,
505 value: OwnedValue,
506 next: Option<*const OwnedProp>,
507 }
508
509 enum OwnedPropsOwner {
510 Box(*mut [OwnedPropsBucket]),
511 Shared(Arc<[OwnedPropsBucket]>),
512 }
513
514 impl OwnedProps {
515 fn cloned(src: &Self) -> (usize, Box<[OwnedPropsBucket]>, Option<*const OwnedProp>) {
516 let nbuckets = src.buckets.len();
521 let mut nprops = 0;
522 let mut buckets = iter::from_fn(|| Some(OwnedPropsBucket::new()))
523 .take(nbuckets)
524 .collect::<Vec<_>>()
525 .into_boxed_slice();
526 let mut head = None::<*const OwnedProp>;
527 let mut tail = None::<*mut OwnedProp>;
528
529 let _ = src.for_each(|prop| {
533 let bucket = &mut buckets[idx(nbuckets, &prop.key)];
534
535 let prop = unsafe {
537 OwnedProp::new(&mut head, &mut tail, prop.key.clone(), prop.value.clone())
538 };
539
540 bucket.push(prop);
541 nprops += 1;
542
543 ControlFlow::Continue(())
544 });
545
546 (nprops, buckets, head)
547 }
548
549 fn new_owned(
550 nprops: usize,
551 buckets: Box<[OwnedPropsBucket]>,
552 head: Option<*const OwnedProp>,
553 ) -> Self {
554 let buckets = Box::into_raw(buckets);
555 let owner = OwnedPropsOwner::Box(buckets);
556
557 OwnedProps {
558 nprops,
559 buckets,
560 owner,
561 head,
562 }
563 }
564
565 fn new_shared(
566 nprops: usize,
567 buckets: Arc<[OwnedPropsBucket]>,
568 head: Option<*const OwnedProp>,
569 ) -> Self {
570 let ptr = Arc::as_ptr(&buckets);
571 let owner = OwnedPropsOwner::Shared(buckets);
572 let buckets = ptr;
573
574 OwnedProps {
575 nprops,
576 buckets,
577 owner,
578 head,
579 }
580 }
581
582 fn collect(
583 props: impl Props,
584 mut key: impl FnMut(Str) -> Str<'static>,
585 mut value: impl FnMut(Value) -> OwnedValue,
586 ) -> (usize, Box<[OwnedPropsBucket]>, Option<*const OwnedProp>) {
587 let nbuckets = cmp::min(128, props.size().unwrap_or(32));
590 let mut nprops = 0;
591 let mut buckets = iter::from_fn(|| Some(OwnedPropsBucket::new()))
592 .take(nbuckets)
593 .collect::<Vec<_>>()
594 .into_boxed_slice();
595 let mut head = None::<*const OwnedProp>;
596 let mut tail = None::<*mut OwnedProp>;
597
598 let _ = props.for_each(|k, v| {
599 let bucket = &mut buckets[idx(nbuckets, &k)];
600
601 if bucket.get(&k).is_some() {
602 ControlFlow::Continue(())
603 } else {
604 let prop = unsafe { OwnedProp::new(&mut head, &mut tail, key(k), value(v)) };
606
607 bucket.push(prop);
608 nprops += 1;
609
610 ControlFlow::Continue(())
611 }
612 });
613
614 (nprops, buckets, head)
615 }
616
617 pub fn collect_owned(props: impl Props) -> Self {
623 let (nprops, buckets, head) = Self::collect(props, |k| k.to_owned(), |v| v.to_owned());
624
625 let buckets = Box::into_raw(buckets);
626 let owner = OwnedPropsOwner::Box(buckets);
627
628 OwnedProps {
629 nprops,
630 buckets,
631 owner,
632 head,
633 }
634 }
635
636 pub fn collect_shared(props: impl Props) -> Self {
642 let (nprops, buckets, head) =
643 Self::collect(props, |k| k.to_shared(), |v| v.to_shared());
644
645 Self::new_shared(nprops, buckets.into(), head)
646 }
647
648 pub fn to_shared(&self) -> Self {
654 match self.owner {
655 OwnedPropsOwner::Box(_) => {
656 let (nprops, buckets, head) = OwnedProps::cloned(self);
658
659 Self::new_shared(nprops, Arc::from(buckets), head)
660 }
661 OwnedPropsOwner::Shared(ref owner) => {
662 OwnedProps::new_shared(self.nprops, owner.clone(), self.head)
663 }
664 }
665 }
666
667 fn for_each<'kv, F: FnMut(&'kv OwnedProp) -> ControlFlow<()>>(
668 &'kv self,
669 mut for_each: F,
670 ) -> ControlFlow<()> {
671 let mut next = self.head;
673
674 while let Some(current) = next.take() {
675 let current = unsafe { &*current };
678
679 for_each(¤t)?;
680
681 next = current.next;
682 }
683
684 ControlFlow::Continue(())
685 }
686
687 fn get<'v, K: ToStr>(&'v self, key: K) -> Option<&'v OwnedProp> {
688 let key = key.to_str();
689
690 let buckets = unsafe { &*self.buckets };
692
693 buckets[idx(buckets.len(), &key)].get(&key)
694 }
695 }
696
697 impl Props for OwnedProps {
698 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
699 &'kv self,
700 mut for_each: F,
701 ) -> ControlFlow<()> {
702 self.for_each(|prop| for_each(prop.key.by_ref(), prop.value.by_ref()))
703 }
704
705 fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
706 self.get(key).map(|prop| prop.value.by_ref())
707 }
708
709 fn is_unique(&self) -> bool {
710 true
711 }
712
713 fn size(&self) -> Option<usize> {
714 Some(self.nprops)
715 }
716 }
717
718 impl<'kv> FromProps<'kv> for OwnedProps {
719 fn from_props<P: Props + ?Sized>(props: &'kv P) -> Self {
720 Self::collect_owned(props)
721 }
722 }
723
724 impl OwnedPropsBucket {
725 fn new() -> OwnedPropsBucket {
726 OwnedPropsBucket {
727 head: ptr::null_mut(),
728 tail: Vec::new(),
729 }
730 }
731
732 fn push(&mut self, mut prop: PropDropGuard) {
733 if self.head.is_null() {
734 self.head = prop.take();
735 } else {
736 self.tail.reserve(1);
737 self.tail.push(prop.take());
738 }
739 }
740
741 fn get(&self, k: &Str) -> Option<&OwnedProp> {
742 if !self.head.is_null() {
743 let prop = unsafe { &*self.head };
745
746 if prop.key == *k {
747 return Some(&prop);
748 }
749 }
750
751 for prop in &self.tail {
752 let prop = unsafe { &**prop };
754
755 if prop.key == *k {
756 return Some(&prop);
757 }
758 }
759
760 None
761 }
762 }
763
764 impl OwnedProp {
765 unsafe fn new(
767 head: &mut Option<*const OwnedProp>,
768 tail: &mut Option<*mut OwnedProp>,
769 key: Str<'static>,
770 value: OwnedValue,
771 ) -> PropDropGuard {
772 let guard = PropDropGuard::new(Box::new(OwnedProp {
773 key,
774 value,
775 next: None,
776 }));
777
778 let prop_ptr = guard.0;
779
780 *head = head.or_else(|| Some(prop_ptr));
781
782 if let Some(tail) = tail {
783 debug_assert!(head.is_some());
784
785 let tail = unsafe { &mut **tail };
787
788 debug_assert!(tail.next.is_none());
789 tail.next = Some(prop_ptr);
790 }
791 *tail = Some(prop_ptr);
792
793 guard
794 }
795 }
796
797 struct SliceDropGuard<'a> {
798 idx: usize,
799 value: &'a mut [*mut OwnedProp],
800 }
801
802 impl<'a> Drop for SliceDropGuard<'a> {
803 fn drop(&mut self) {
804 unsafe {
807 self.drop();
808 }
809 }
810 }
811
812 impl<'a> SliceDropGuard<'a> {
813 fn new(value: &'a mut [*mut OwnedProp]) -> Self {
814 SliceDropGuard { value, idx: 0 }
815 }
816
817 unsafe fn drop(&mut self) {
819 while self.idx < self.value.len() {
820 let prop = self.value[self.idx];
821 self.idx += 1;
822
823 drop(unsafe { Box::from_raw(prop) });
825 }
826 }
827 }
828
829 struct PropDropGuard(*mut OwnedProp);
830
831 impl PropDropGuard {
832 fn new(prop: Box<OwnedProp>) -> Self {
833 PropDropGuard(Box::into_raw(prop))
834 }
835
836 fn take(&mut self) -> *mut OwnedProp {
837 mem::replace(&mut self.0, ptr::null_mut())
838 }
839 }
840
841 impl Drop for PropDropGuard {
842 fn drop(&mut self) {
843 if self.0.is_null() {
844 return;
845 }
846
847 drop(unsafe { Box::from_raw(self.0) });
849 }
850 }
851
852 fn idx(buckets: usize, k: &Str) -> usize {
853 let mut hash = 0xcbf29ce484222325;
854
855 for b in k.get().as_bytes() {
856 hash = hash ^ (*b as u64);
857 hash = hash.wrapping_mul(0x00000100000001b3);
858 }
859
860 (hash as usize) % buckets
861 }
862
863 #[repr(transparent)]
871 pub struct Dedup<P: ?Sized>(P);
872
873 impl<P: ?Sized> Dedup<P> {
874 pub(super) fn new<'a>(props: &'a P) -> &'a Dedup<P> {
875 unsafe { &*(props as *const P as *const Dedup<P>) }
877 }
878 }
879
880 impl<P: Props + ?Sized> Props for Dedup<P> {
881 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
882 &'kv self,
883 mut for_each: F,
884 ) -> ControlFlow<()> {
885 enum Filter<'a> {
891 Inline(Inline<'a, 16>),
892 Spilled(Spilled<'a>),
893 }
894
895 impl<'a> Filter<'a> {
896 fn new(size: Option<usize>) -> Self {
897 match size {
898 Some(size) if size <= 16 => Filter::Inline(Inline::new()),
899 _ => Filter::Spilled(Spilled::new()),
900 }
901 }
902
903 fn insert(&mut self, key: Str<'a>, value: Value<'a>) {
904 match self {
905 Filter::Inline(ref mut inline) => match inline.insert(key, value) {
906 Ok(()) => (),
907 Err((key, value)) => {
908 let mut spilled = Spilled::spill(inline.take());
909 spilled.insert(key, value);
910
911 *self = Filter::Spilled(spilled);
912 }
913 },
914 Filter::Spilled(ref mut spilled) => spilled.insert(key, value),
915 }
916 }
917
918 fn take<'b>(&'b mut self) -> impl Iterator<Item = (Str<'a>, Value<'a>)> + 'b {
919 enum Either<A, B> {
920 A(A),
921 B(B),
922 }
923
924 impl<T, A: Iterator<Item = T>, B: Iterator<Item = T>> Iterator for Either<A, B> {
925 type Item = T;
926
927 fn next(&mut self) -> Option<Self::Item> {
928 match self {
929 Either::A(a) => a.next(),
930 Either::B(b) => b.next(),
931 }
932 }
933 }
934
935 match self {
936 Filter::Inline(ref mut inline) => Either::A(inline.take()),
937 Filter::Spilled(ref mut spilled) => Either::B(spilled.take()),
938 }
939 }
940 }
941
942 struct Inline<'a, const N: usize> {
943 values: [(Str<'a>, Value<'a>); N],
944 len: usize,
945 }
946
947 impl<'a, const N: usize> Inline<'a, N> {
948 fn new() -> Self {
949 Inline {
950 values: [const { (Str::new(""), Value::null()) }; N],
951 len: 0,
952 }
953 }
954
955 fn insert(
956 &mut self,
957 key: Str<'a>,
958 value: Value<'a>,
959 ) -> Result<(), (Str<'a>, Value<'a>)> {
960 if self.len == N {
961 return Err((key, value));
962 }
963
964 for (seen, _) in &self.values[..self.len] {
965 if *seen == key {
966 return Ok(());
967 }
968 }
969
970 self.values[self.len] = (key, value);
971 self.len += 1;
972
973 Ok(())
974 }
975
976 fn take<'b>(&'b mut self) -> impl Iterator<Item = (Str<'a>, Value<'a>)> + 'b {
977 let len = self.len;
978 self.len = 0;
979
980 (&mut self.values[..len])
981 .into_iter()
982 .map(|v| mem::replace(v, (Str::new(""), Value::null())))
983 }
984 }
985
986 struct Spilled<'a> {
987 values: BTreeMap<Str<'a>, Value<'a>>,
988 }
989
990 impl<'a> Spilled<'a> {
991 fn new() -> Self {
992 Spilled {
993 values: Default::default(),
994 }
995 }
996
997 fn spill(seen: impl Iterator<Item = (Str<'a>, Value<'a>)>) -> Self {
998 Spilled {
999 values: seen.collect(),
1000 }
1001 }
1002
1003 fn insert(&mut self, key: Str<'a>, value: Value<'a>) {
1004 self.values.entry(key).or_insert(value);
1005 }
1006
1007 fn take<'b>(&'b mut self) -> impl Iterator<Item = (Str<'a>, Value<'a>)> + 'b {
1008 mem::take(&mut self.values).into_iter()
1009 }
1010 }
1011
1012 if self.0.is_unique() {
1014 return self.0.for_each(for_each);
1015 }
1016
1017 let mut filter = Filter::new(self.0.size());
1018
1019 let _ = self.0.for_each(|key, value| {
1023 filter.insert(key, value);
1024
1025 ControlFlow::Continue(())
1026 });
1027
1028 for (key, value) in filter.take() {
1029 for_each(key, value)?;
1030 }
1031
1032 ControlFlow::Continue(())
1033 }
1034
1035 fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
1036 self.0.get(key)
1037 }
1038
1039 fn is_unique(&self) -> bool {
1040 true
1041 }
1042
1043 fn size(&self) -> Option<usize> {
1044 self.0.size()
1047 }
1048 }
1049
1050 impl<T: Props> Props for Vec<T> {
1051 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
1052 &'kv self,
1053 for_each: F,
1054 ) -> ControlFlow<()> {
1055 Props::for_each(self as &[_], for_each)
1056 }
1057
1058 fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
1059 Props::get(self as &[_], key)
1060 }
1061
1062 fn pull<'kv, V: FromValue<'kv>, K: ToStr>(&'kv self, key: K) -> Option<V> {
1063 Props::pull(self as &[_], key)
1064 }
1065
1066 fn is_unique(&self) -> bool {
1067 Props::is_unique(self as &[_])
1068 }
1069
1070 fn size(&self) -> Option<usize> {
1071 Props::size(self as &[_])
1072 }
1073 }
1074
1075 impl<'kv, K, V> FromProps<'kv> for Vec<(K, V)>
1076 where
1077 K: From<Str<'kv>>,
1078 V: From<Value<'kv>>,
1079 {
1080 fn from_props<P: Props + ?Sized>(props: &'kv P) -> Self {
1081 let mut result = Vec::new();
1082
1083 let _ = props.for_each(|k, v| {
1084 result.push((k.into(), v.into()));
1085
1086 ControlFlow::Continue(())
1087 });
1088
1089 result
1090 }
1091 }
1092
1093 impl<K, V> Props for BTreeMap<K, V>
1094 where
1095 K: Ord + ToStr + Borrow<str>,
1096 V: ToValue,
1097 {
1098 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
1099 &'kv self,
1100 mut for_each: F,
1101 ) -> ControlFlow<()> {
1102 for (k, v) in self {
1103 for_each(k.to_str(), v.to_value())?;
1104 }
1105
1106 ControlFlow::Continue(())
1107 }
1108
1109 fn get<'v, Q: ToStr>(&'v self, key: Q) -> Option<Value<'v>> {
1110 self.get(key.to_str().as_ref()).map(|v| v.to_value())
1111 }
1112
1113 fn is_unique(&self) -> bool {
1114 true
1115 }
1116
1117 fn size(&self) -> Option<usize> {
1118 Some(self.len())
1119 }
1120 }
1121
1122 impl<'kv, K, V> FromProps<'kv> for BTreeMap<K, V>
1123 where
1124 K: Ord + From<Str<'kv>>,
1125 V: From<Value<'kv>>,
1126 {
1127 fn from_props<P: Props + ?Sized>(props: &'kv P) -> Self {
1128 let mut result = BTreeMap::new();
1129
1130 let _ = props.for_each(|k, v| {
1131 result.entry(k.into()).or_insert_with(|| v.into());
1132
1133 ControlFlow::Continue(())
1134 });
1135
1136 result
1137 }
1138 }
1139
1140 #[cfg(test)]
1141 mod tests {
1142 use super::*;
1143
1144 use crate::value::OwnedValue;
1145
1146 #[test]
1147 fn btreemap_props() {
1148 let props = BTreeMap::from_iter([("a", 1), ("b", 2), ("c", 3)]);
1149
1150 assert_eq!(1, Props::get(&props, "a").unwrap().cast::<i32>().unwrap());
1151 assert_eq!(2, Props::get(&props, "b").unwrap().cast::<i32>().unwrap());
1152 assert_eq!(3, Props::get(&props, "c").unwrap().cast::<i32>().unwrap());
1153
1154 assert_eq!(1, Props::pull::<i32, _>(&props, "a").unwrap());
1155 assert_eq!(2, Props::pull::<i32, _>(&props, "b").unwrap());
1156 assert_eq!(3, Props::pull::<i32, _>(&props, "c").unwrap());
1157
1158 assert!(props.is_unique());
1159 }
1160
1161 #[test]
1162 fn btreemap_from_props() {
1163 let props = BTreeMap::<String, OwnedValue>::from_props(&[("a", 1), ("a", 2), ("c", 3)]);
1164
1165 assert_eq!(1, Props::pull::<i32, _>(&props, "a").unwrap());
1166 assert_eq!(3, Props::pull::<i32, _>(&props, "c").unwrap());
1167 }
1168
1169 #[test]
1170 fn vec_from_props() {
1171 let props = Vec::<(String, OwnedValue)>::from_props(&[("a", 1), ("a", 2), ("c", 3)]);
1172
1173 assert_eq!(3, props.len());
1174
1175 assert_eq!(1, Props::pull::<i32, _>(&props, "a").unwrap());
1176 assert_eq!(3, Props::pull::<i32, _>(&props, "c").unwrap());
1177 }
1178
1179 #[test]
1180 fn dedup() {
1181 let props = [
1182 ("a", Value::from(1)),
1183 ("a", Value::from(2)),
1184 ("b", Value::from(1)),
1185 ];
1186
1187 let deduped = props.dedup();
1188
1189 let mut ac = 0;
1190 let mut bc = 0;
1191
1192 let _ = deduped.for_each(|k, v| {
1193 match k.get() {
1194 "a" => {
1195 assert_eq!(1, v.cast::<i32>().unwrap());
1196 ac += 1;
1197 }
1198 "b" => {
1199 assert_eq!(1, v.cast::<i32>().unwrap());
1200 bc += 1;
1201 }
1202 _ => (),
1203 }
1204
1205 ControlFlow::Continue(())
1206 });
1207
1208 assert_eq!(1, ac);
1209 assert_eq!(1, bc);
1210 }
1211
1212 #[test]
1213 fn dedup_many() {
1214 let props = [
1215 ("aumcgyiuerskg", 1),
1216 ("blvkmnfdigmgc", 2),
1217 ("cvojdfmcisemc", 3),
1218 ("dlkgjhmgkvnrd", 4),
1219 ("eiugrlgmvmgvd", 5),
1220 ("flfbjhmrimrtw", 6),
1221 ("goihudvngusrg", 7),
1222 ("hfjehrngviuwn", 8),
1223 ("ivojitvnjysns", 9),
1224 ("jciughnrhiens", 10),
1225 ("kofhfuernytnd", 11),
1226 ("lvgjrunfwwner", 12),
1227 ("mfjerukfnjhns", 13),
1228 ("nmorikjnnehsx", 14),
1229 ("oiovjrmunsnex", 15),
1230 ("pijdshfenrnfq", 16),
1231 ("aumcgyiuerskg", 11),
1232 ("blvkmnfdigmgc", 21),
1233 ("cvojdfmcisemc", 31),
1234 ("dlkgjhmgkvnrd", 41),
1235 ("eiugrlgmvmgvd", 51),
1236 ("flfbjhmrimrtw", 61),
1237 ("goihudvngusrg", 71),
1238 ("hfjehrngviuwn", 81),
1239 ("ivojitvnjysns", 91),
1240 ("jciughnrhiens", 101),
1241 ("kofhfuernytnd", 111),
1242 ("lvgjrunfwwner", 121),
1243 ("mfjerukfnjhns", 131),
1244 ("nmorikjnnehsx", 141),
1245 ("oiovjrmunsnex", 151),
1246 ("pijdshfenrnfq", 161),
1247 ];
1248
1249 let deduped = props.dedup();
1250
1251 let mut ac = 0;
1252 let mut bc = 0;
1253
1254 let _ = deduped.for_each(|k, v| {
1255 match k.get() {
1256 "aumcgyiuerskg" => {
1257 assert_eq!(1, v.cast::<i32>().unwrap());
1258 ac += 1;
1259 }
1260 "blvkmnfdigmgc" => {
1261 assert_eq!(2, v.cast::<i32>().unwrap());
1262 bc += 1;
1263 }
1264 _ => (),
1265 }
1266
1267 ControlFlow::Continue(())
1268 });
1269
1270 assert_eq!(1, ac);
1271 assert_eq!(1, bc);
1272 }
1273
1274 struct WrongSize<P> {
1275 props: P,
1276 size: Option<usize>,
1277 }
1278
1279 impl<P: Props> Props for WrongSize<P> {
1280 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
1281 &'kv self,
1282 for_each: F,
1283 ) -> ControlFlow<()> {
1284 self.props.for_each(for_each)
1285 }
1286
1287 fn size(&self) -> Option<usize> {
1288 self.size
1289 }
1290 }
1291
1292 #[test]
1293 fn dedup_low_ball_size() {
1294 let props = WrongSize {
1295 props: [
1296 ("aumcgyiuerskg", 1),
1297 ("blvkmnfdigmgc", 2),
1298 ("cvojdfmcisemc", 3),
1299 ("dlkgjhmgkvnrd", 4),
1300 ("eiugrlgmvmgvd", 5),
1301 ("flfbjhmrimrtw", 6),
1302 ("goihudvngusrg", 7),
1303 ("hfjehrngviuwn", 8),
1304 ("ivojitvnjysns", 9),
1305 ("jciughnrhiens", 10),
1306 ("kofhfuernytnd", 11),
1307 ("lvgjrunfwwner", 12),
1308 ("mfjerukfnjhns", 13),
1309 ("nmorikjnnehsx", 14),
1310 ("oiovjrmunsnex", 15),
1311 ("pijdshfenrnfq", 16),
1312 ("rkjhfngjrfnhf", 17),
1313 ],
1314 size: Some(1),
1315 };
1316
1317 let deduped = props.dedup();
1318
1319 let mut count = 0;
1320
1321 let _ = deduped.for_each(|_, _| {
1322 count += 1;
1323
1324 ControlFlow::Continue(())
1325 });
1326
1327 assert_eq!(17, count);
1328 }
1329
1330 #[test]
1331 fn dedup_high_ball_size() {
1332 let props = WrongSize {
1333 props: [("aumcgyiuerskg", 1)],
1334 size: Some(usize::MAX),
1335 };
1336
1337 let deduped = props.dedup();
1338
1339 let mut count = 0;
1340
1341 let _ = deduped.for_each(|_, _| {
1342 count += 1;
1343
1344 ControlFlow::Continue(())
1345 });
1346
1347 assert_eq!(1, count);
1348 }
1349
1350 #[test]
1351 fn owned_props_empty() {
1352 let props = OwnedProps::collect_owned([] as [(Str, Value); 0]);
1353
1354 assert_eq!(Some(0), props.size());
1355 assert!(props.is_unique());
1356
1357 let mut count = 0;
1358
1359 let _ = props.for_each(|_| {
1360 count += 1;
1361 ControlFlow::Continue(())
1362 });
1363
1364 assert_eq!(0, count);
1365 }
1366
1367 #[test]
1368 fn owned_props_collect() {
1369 for (description, case) in [
1370 (
1371 "owned",
1372 OwnedProps::collect_owned([
1373 ("b", 2),
1374 ("a", 1),
1375 ("c", 3),
1376 ("b", 12),
1377 ("a", 11),
1378 ("c", 13),
1379 ]),
1380 ),
1381 (
1382 "shared",
1383 OwnedProps::collect_shared([
1384 ("b", 2),
1385 ("a", 1),
1386 ("c", 3),
1387 ("b", 12),
1388 ("a", 11),
1389 ("c", 13),
1390 ]),
1391 ),
1392 (
1393 "owned -> shared",
1394 OwnedProps::collect_owned([
1395 ("b", 2),
1396 ("a", 1),
1397 ("c", 3),
1398 ("b", 12),
1399 ("a", 11),
1400 ("c", 13),
1401 ])
1402 .to_shared(),
1403 ),
1404 (
1405 "shared -> shared",
1406 OwnedProps::collect_shared([
1407 ("b", 2),
1408 ("a", 1),
1409 ("c", 3),
1410 ("b", 12),
1411 ("a", 11),
1412 ("c", 13),
1413 ])
1414 .to_shared(),
1415 ),
1416 (
1417 "owned -> clone",
1418 OwnedProps::collect_owned([
1419 ("b", 2),
1420 ("a", 1),
1421 ("c", 3),
1422 ("b", 12),
1423 ("a", 11),
1424 ("c", 13),
1425 ])
1426 .clone(),
1427 ),
1428 (
1429 "shared -> clone",
1430 OwnedProps::collect_shared([
1431 ("b", 2),
1432 ("a", 1),
1433 ("c", 3),
1434 ("b", 12),
1435 ("a", 11),
1436 ("c", 13),
1437 ])
1438 .clone(),
1439 ),
1440 ] {
1441 assert_eq!(Some(3), case.size());
1442 assert!(case.is_unique());
1443
1444 assert_eq!(Some(1), case.pull::<usize, _>("a"), "{description}");
1445 assert_eq!(Some(2), case.pull::<usize, _>("b"), "{description}");
1446 assert_eq!(Some(3), case.pull::<usize, _>("c"), "{description}");
1447
1448 let mut values = Vec::new();
1449
1450 let _ = case.for_each(|prop| {
1451 values.push((prop.key.get(), prop.value.by_ref().cast::<usize>()));
1452 ControlFlow::Continue(())
1453 });
1454
1455 assert_eq!(
1456 vec![("b", Some(2)), ("a", Some(1)), ("c", Some(3))],
1457 values,
1458 "{description}"
1459 );
1460 }
1461 }
1462 }
1463}
1464
1465#[cfg(feature = "alloc")]
1466pub use alloc_support::*;
1467
1468#[cfg(feature = "std")]
1469mod std_support {
1470 use super::*;
1471
1472 use std::{collections::HashMap, hash::Hash};
1473
1474 impl<K, V> Props for HashMap<K, V>
1475 where
1476 K: Eq + Hash + ToStr + Borrow<str>,
1477 V: ToValue,
1478 {
1479 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
1480 &'kv self,
1481 mut for_each: F,
1482 ) -> ControlFlow<()> {
1483 for (k, v) in self {
1484 for_each(k.to_str(), v.to_value())?;
1485 }
1486
1487 ControlFlow::Continue(())
1488 }
1489
1490 fn get<'v, Q: ToStr>(&'v self, key: Q) -> Option<Value<'v>> {
1491 self.get(key.to_str().as_ref()).map(|v| v.to_value())
1492 }
1493
1494 fn is_unique(&self) -> bool {
1495 true
1496 }
1497
1498 fn size(&self) -> Option<usize> {
1499 Some(self.len())
1500 }
1501 }
1502
1503 impl<'kv, K, V> FromProps<'kv> for HashMap<K, V>
1504 where
1505 K: Eq + Hash + From<Str<'kv>>,
1506 V: From<Value<'kv>>,
1507 {
1508 fn from_props<P: Props + ?Sized>(props: &'kv P) -> Self {
1509 let mut result = HashMap::new();
1510
1511 let _ = props.for_each(|k, v| {
1512 result.entry(k.into()).or_insert_with(|| v.into());
1513
1514 ControlFlow::Continue(())
1515 });
1516
1517 result
1518 }
1519 }
1520
1521 #[cfg(test)]
1522 mod tests {
1523 use super::*;
1524
1525 use crate::value::OwnedValue;
1526
1527 #[test]
1528 fn hashmap_props() {
1529 let props = HashMap::from_iter([("a", 1), ("b", 2), ("c", 3)]);
1530
1531 assert_eq!(1, Props::get(&props, "a").unwrap().cast::<i32>().unwrap());
1532 assert_eq!(2, Props::get(&props, "b").unwrap().cast::<i32>().unwrap());
1533 assert_eq!(3, Props::get(&props, "c").unwrap().cast::<i32>().unwrap());
1534
1535 assert_eq!(1, Props::pull::<i32, _>(&props, "a").unwrap());
1536 assert_eq!(2, Props::pull::<i32, _>(&props, "b").unwrap());
1537 assert_eq!(3, Props::pull::<i32, _>(&props, "c").unwrap());
1538
1539 assert!(props.is_unique());
1540 }
1541
1542 #[test]
1543 fn hashmap_from_props() {
1544 let props = HashMap::<String, OwnedValue>::from_props(&[("a", 1), ("a", 2), ("c", 3)]);
1545
1546 assert_eq!(1, Props::pull::<i32, _>(&props, "a").unwrap());
1547 assert_eq!(3, Props::pull::<i32, _>(&props, "c").unwrap());
1548 }
1549 }
1550}
1551
1552#[repr(transparent)]
1558pub struct AsMap<P: ?Sized>(P);
1559
1560impl<P: ?Sized> AsMap<P> {
1561 fn new<'a>(props: &'a P) -> &'a AsMap<P> {
1562 unsafe { &*(props as *const P as *const AsMap<P>) }
1564 }
1565}
1566
1567impl<P: Props + ?Sized> Props for AsMap<P> {
1568 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
1569 &'kv self,
1570 for_each: F,
1571 ) -> ControlFlow<()> {
1572 self.0.for_each(for_each)
1573 }
1574
1575 fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
1576 self.0.get(key)
1577 }
1578
1579 fn pull<'kv, V: FromValue<'kv>, K: ToStr>(&'kv self, key: K) -> Option<V> {
1580 self.0.pull(key)
1581 }
1582
1583 fn is_unique(&self) -> bool {
1584 self.0.is_unique()
1585 }
1586
1587 fn size(&self) -> Option<usize> {
1588 self.0.size()
1589 }
1590}
1591
1592#[cfg(feature = "sval")]
1593impl<P: Props + ?Sized> sval::Value for AsMap<P> {
1594 fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result {
1595 stream.map_begin(None)?;
1596
1597 let mut r = Ok(());
1598 let _ = self.for_each(|k, v| {
1599 r = (|| {
1600 stream.map_key_begin()?;
1601 sval_ref::stream_ref(&mut *stream, k)?;
1602 stream.map_key_end()?;
1603
1604 stream.map_value_begin()?;
1605 sval_ref::stream_ref(&mut *stream, v)?;
1606 stream.map_value_end()
1607 })();
1608
1609 if r.is_ok() {
1610 ControlFlow::Continue(())
1611 } else {
1612 ControlFlow::Break(())
1613 }
1614 });
1615 r?;
1616
1617 stream.map_end()
1618 }
1619}
1620
1621#[cfg(feature = "serde")]
1622impl<P: Props + ?Sized> serde::Serialize for AsMap<P> {
1623 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
1624 use serde::ser::SerializeMap as _;
1625
1626 let mut err = None;
1627
1628 let mut map = serializer.serialize_map(None)?;
1629
1630 let _ = self.for_each(|k, v| match map.serialize_entry(&k, &v) {
1631 Ok(()) => ControlFlow::Continue(()),
1632 Err(e) => {
1633 err = Some(e);
1634 ControlFlow::Break(())
1635 }
1636 });
1637
1638 if let Some(e) = err {
1639 return Err(e);
1640 }
1641
1642 map.end()
1643 }
1644}
1645
1646impl<P: Props + ?Sized> fmt::Debug for AsMap<P> {
1647 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1648 fmt::Display::fmt(self, f)
1649 }
1650}
1651
1652impl<P: Props + ?Sized> fmt::Display for AsMap<P> {
1653 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1654 let mut map = f.debug_map();
1655
1656 let _ = self.for_each(|k, v| {
1657 map.entry(&k, &v);
1658
1659 ControlFlow::Continue(())
1660 });
1661
1662 map.finish()
1663 }
1664}
1665
1666mod internal {
1667 use core::ops::ControlFlow;
1668
1669 use crate::{str::Str, value::Value};
1670
1671 pub trait DispatchProps {
1672 fn dispatch_for_each<'kv, 'f>(
1673 &'kv self,
1674 for_each: &'f mut dyn FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>,
1675 ) -> ControlFlow<()>;
1676
1677 fn dispatch_get(&self, key: Str) -> Option<Value<'_>>;
1678
1679 fn dispatch_is_unique(&self) -> bool;
1680
1681 fn dispatch_size(&self) -> Option<usize>;
1682 }
1683
1684 pub trait SealedProps {
1685 fn erase_props(&self) -> crate::internal::Erased<&dyn DispatchProps>;
1686 }
1687}
1688
1689pub trait ErasedProps: internal::SealedProps {}
1695
1696impl<P: Props> ErasedProps for P {}
1697
1698impl<P: Props> internal::SealedProps for P {
1699 fn erase_props(&self) -> crate::internal::Erased<&dyn internal::DispatchProps> {
1700 crate::internal::Erased(self)
1701 }
1702}
1703
1704impl<P: Props> internal::DispatchProps for P {
1705 fn dispatch_for_each<'kv, 'f>(
1706 &'kv self,
1707 for_each: &'f mut dyn FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>,
1708 ) -> ControlFlow<()> {
1709 self.for_each(for_each)
1710 }
1711
1712 fn dispatch_get<'v>(&'v self, key: Str) -> Option<Value<'v>> {
1713 self.get(key)
1714 }
1715
1716 fn dispatch_is_unique(&self) -> bool {
1717 self.is_unique()
1718 }
1719
1720 fn dispatch_size(&self) -> Option<usize> {
1721 self.size()
1722 }
1723}
1724
1725impl<'a> Props for dyn ErasedProps + 'a {
1726 fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
1727 &'kv self,
1728 mut for_each: F,
1729 ) -> ControlFlow<()> {
1730 self.erase_props().0.dispatch_for_each(&mut for_each)
1731 }
1732
1733 fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
1734 self.erase_props().0.dispatch_get(key.to_str())
1735 }
1736
1737 fn is_unique(&self) -> bool {
1738 self.erase_props().0.dispatch_is_unique()
1739 }
1740
1741 fn size(&self) -> Option<usize> {
1742 self.erase_props().0.dispatch_size()
1743 }
1744}
1745
1746#[cfg(test)]
1747mod tests {
1748 use super::*;
1749
1750 #[test]
1751 fn tuple_props() {
1752 let props = ("a", 1);
1753
1754 assert_eq!(1, props.get("a").unwrap().cast::<i32>().unwrap());
1755
1756 assert_eq!(1, props.pull::<i32, _>("a").unwrap());
1757
1758 assert!(props.is_unique());
1759 }
1760
1761 #[test]
1762 fn array_props() {
1763 let props = [("a", 1), ("b", 2), ("c", 3)];
1764
1765 assert_eq!(1, props.get("a").unwrap().cast::<i32>().unwrap());
1766 assert_eq!(2, props.get("b").unwrap().cast::<i32>().unwrap());
1767 assert_eq!(3, props.get("c").unwrap().cast::<i32>().unwrap());
1768
1769 assert_eq!(1, props.pull::<i32, _>("a").unwrap());
1770 assert_eq!(2, props.pull::<i32, _>("b").unwrap());
1771 assert_eq!(3, props.pull::<i32, _>("c").unwrap());
1772
1773 assert!(!props.is_unique());
1774 }
1775
1776 #[test]
1777 fn option_props() {
1778 for (props, expected) in [(Some(("a", 1)), Some(1)), (None, None)] {
1779 assert_eq!(expected, props.pull::<i32, _>("a"));
1780 }
1781 }
1782
1783 #[test]
1784 fn erased_props() {
1785 let props = ("a", 1);
1786
1787 let props = &props as &dyn ErasedProps;
1788
1789 assert_eq!(1, props.get("a").unwrap().cast::<i32>().unwrap());
1790
1791 assert_eq!(1, props.pull::<i32, _>("a").unwrap());
1792
1793 assert!(props.is_unique());
1794 }
1795
1796 #[test]
1797 fn get() {
1798 let props = [("a", 1), ("a", 2)];
1799
1800 assert_eq!(1, props.get("a").unwrap().cast::<i32>().unwrap());
1801 }
1802
1803 #[test]
1804 fn pull() {
1805 let props = [("a", 1), ("a", 2)];
1806
1807 assert_eq!(1, props.pull::<i32, _>("a").unwrap());
1808 }
1809
1810 #[test]
1811 fn size() {
1812 let props = [("a", 1), ("b", 2)].and_props([("c", 3)]);
1813
1814 assert_eq!(Some(3), props.size());
1815 }
1816
1817 #[test]
1818 fn and_props() {
1819 let a = ("a", 1);
1820 let b = [("b", 2), ("c", 3)];
1821
1822 let props = a.and_props(b);
1823
1824 assert_eq!(1, props.get("a").unwrap().cast::<i32>().unwrap());
1825 assert_eq!(2, props.get("b").unwrap().cast::<i32>().unwrap());
1826 assert_eq!(3, props.get("c").unwrap().cast::<i32>().unwrap());
1827
1828 assert_eq!(1, props.pull::<i32, _>("a").unwrap());
1829 assert_eq!(2, props.pull::<i32, _>("b").unwrap());
1830 assert_eq!(3, props.pull::<i32, _>("c").unwrap());
1831
1832 assert!(!props.is_unique());
1833 }
1834
1835 #[test]
1836 fn as_map() {
1837 let props = [("a", 1), ("b", 2)].as_map();
1838
1839 assert_eq!("{\"a\": 1, \"b\": 2}", props.to_string());
1840 }
1841
1842 #[cfg(feature = "sval")]
1843 #[test]
1844 fn as_map_stream() {
1845 let props = [("a", 1), ("b", 2)].as_map();
1846
1847 sval_test::assert_tokens(
1848 &props,
1849 &[
1850 sval_test::Token::MapBegin(None),
1851 sval_test::Token::MapKeyBegin,
1852 sval_test::Token::TextBegin(Some(1)),
1853 sval_test::Token::TextFragmentComputed("a".to_owned()),
1854 sval_test::Token::TextEnd,
1855 sval_test::Token::MapKeyEnd,
1856 sval_test::Token::MapValueBegin,
1857 sval_test::Token::I64(1),
1858 sval_test::Token::MapValueEnd,
1859 sval_test::Token::MapKeyBegin,
1860 sval_test::Token::TextBegin(Some(1)),
1861 sval_test::Token::TextFragmentComputed("b".to_owned()),
1862 sval_test::Token::TextEnd,
1863 sval_test::Token::MapKeyEnd,
1864 sval_test::Token::MapValueBegin,
1865 sval_test::Token::I64(2),
1866 sval_test::Token::MapValueEnd,
1867 sval_test::Token::MapEnd,
1868 ],
1869 );
1870 }
1871
1872 #[cfg(feature = "serde")]
1873 #[test]
1874 fn as_map_serialize() {
1875 let props = [("a", 1), ("b", 2)].as_map();
1876
1877 serde_test::assert_ser_tokens(
1878 &props,
1879 &[
1880 serde_test::Token::Map { len: None },
1881 serde_test::Token::Str("a"),
1882 serde_test::Token::I64(1),
1883 serde_test::Token::Str("b"),
1884 serde_test::Token::I64(2),
1885 serde_test::Token::MapEnd,
1886 ],
1887 );
1888 }
1889}