emit_core/
props.rs

1/*!
2The [`Props`] type.
3
4Properties, also called attributes in some systems, are the structured data associated with an [`crate::event::Event`]. They are the dimensions an event can be categorized and queried on. Each property is a pair of [`Str`] and [`Value`] that can be inspected or serialized.
5
6[`Props`] allow duplicate keys, but can be de-duplicated by taking the first value seen for a given key. This lets consumers searching for a key short-circuit once they see it instead of needing to scan to the end in case a duplicate is found.
7
8[`Props`] can be fed to a [`crate::template::Template`] to render it into a user-facing message.
9
10Well-known properties described in [`crate::well_known`] are used to extend `emit`'s event model with different kinds of diagnostic data.
11*/
12
13use 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
22/**
23A collection of [`Str`] and [`Value`] pairs.
24
25The [`Props::for_each`] method can be used to enumerate properties.
26
27# Uniqueness
28
29Properties may be duplicated in a set of `Props`. When a property is duplicated, the _first_ for a given key is the one to use.
30
31# Typed and untyped properties
32
33The [`Props::get`] method will return a property as an untyped [`Value`] that can be formatted or serialized. If you're looking for a specific type, you can use [`Props::pull`] instead.
34*/
35pub trait Props {
36    /**
37    Enumerate the [`Str`] and [`Value`] pairs.
38
39    The function `for_each` will be called for each property until all properties are visited, or it returns `ControlFlow::Break`.
40
41    Properties may be repeated, but can be de-duplicated by taking the first seen for a given key.
42    */
43    fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
44        &'kv self,
45        for_each: F,
46    ) -> ControlFlow<()>;
47
48    /**
49    Get the value for a given key, if it's present.
50
51    If the key is present then this method will return `Some`. Otherwise this method will return `None`.
52
53    If the key appears multiple times, the first value seen should be returned.
54
55    Implementors are encouraged to override this method with a more efficient implementation.
56    */
57    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    /**
75    Get the value for a given key, if it's present as an instance of `V`.
76
77    If the key is present, and the raw value can be converted into `V` through [`Value::cast`] then this method will return `Some`. Otherwise this method will return `None`.
78
79    If the key appears multiple times, the first value seen should be returned.
80    */
81    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    /**
86    Concatenate `other` to the end of `self`.
87    */
88    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    /**
96    Filter the set of properties.
97
98    Only properties where the filter `F` returns `true` will be included.
99    */
100    fn filter<F: Fn(Str, Value) -> bool>(self, filter: F) -> Filter<Self, F>
101    where
102        Self: Sized,
103    {
104        Filter::new(self, filter)
105    }
106
107    /**
108    Collect these properties into another collection type.
109
110    This method defers to the [`FromProps`] implementation on `C`.
111    */
112    fn collect<'kv, C: FromProps<'kv>>(&'kv self) -> C {
113        C::from_props(self)
114    }
115
116    /**
117    Get an adapter that will serialize properties as a map.
118    */
119    fn as_map(&self) -> &AsMap<Self>
120    where
121        Self: Sized,
122    {
123        AsMap::new(self)
124    }
125
126    /**
127    Lazily de-duplicate properties in the collection.
128
129    Properties are de-duplicated by taking the first value for a given key.
130    */
131    #[cfg(feature = "alloc")]
132    fn dedup(&self) -> &Dedup<Self>
133    where
134        Self: Sized,
135    {
136        Dedup::new(self)
137    }
138
139    /**
140    Whether the collection is known not to contain any duplicate keys.
141
142    If there's any possibility a key may be duplicated, this method should return `false`.
143    */
144    fn is_unique(&self) -> bool {
145        false
146    }
147
148    /**
149    A hint on the number of properties in the collection.
150
151    The returned size isn't guaranteed to be exact, but should not be less than the number of times [`Props::for_each`] will call its given closure.
152
153    If the collection can't determine its size without needing to walk its values then this method will return `None`.
154    */
155    fn size(&self) -> Option<usize> {
156        None
157    }
158}
159
160impl<'a, P: Props + ?Sized> Props for &'a P {
161    fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
162        &'kv self,
163        for_each: F,
164    ) -> ControlFlow<()> {
165        (**self).for_each(for_each)
166    }
167
168    fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
169        (**self).get(key)
170    }
171
172    fn pull<'kv, V: FromValue<'kv>, K: ToStr>(&'kv self, key: K) -> Option<V> {
173        (**self).pull(key)
174    }
175
176    fn is_unique(&self) -> bool {
177        (**self).is_unique()
178    }
179
180    fn size(&self) -> Option<usize> {
181        (**self).size()
182    }
183}
184
185impl<P: Props> Props for Option<P> {
186    fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
187        &'kv self,
188        for_each: F,
189    ) -> ControlFlow<()> {
190        match self {
191            Some(props) => props.for_each(for_each),
192            None => ControlFlow::Continue(()),
193        }
194    }
195
196    fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
197        match self {
198            Some(props) => props.get(key),
199            None => None,
200        }
201    }
202
203    fn pull<'kv, V: FromValue<'kv>, K: ToStr>(&'kv self, key: K) -> Option<V> {
204        match self {
205            Some(props) => props.pull(key),
206            None => None,
207        }
208    }
209
210    fn is_unique(&self) -> bool {
211        match self {
212            Some(props) => props.is_unique(),
213            None => true,
214        }
215    }
216
217    fn size(&self) -> Option<usize> {
218        match self {
219            Some(props) => props.size(),
220            None => Some(0),
221        }
222    }
223}
224
225#[cfg(feature = "alloc")]
226impl<'a, P: Props + ?Sized + 'a> Props for alloc::boxed::Box<P> {
227    fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
228        &'kv self,
229        for_each: F,
230    ) -> ControlFlow<()> {
231        (**self).for_each(for_each)
232    }
233
234    fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
235        (**self).get(key)
236    }
237
238    fn pull<'kv, V: FromValue<'kv>, K: ToStr>(&'kv self, key: K) -> Option<V> {
239        (**self).pull(key)
240    }
241
242    fn is_unique(&self) -> bool {
243        (**self).is_unique()
244    }
245
246    fn size(&self) -> Option<usize> {
247        (**self).size()
248    }
249}
250
251#[cfg(feature = "alloc")]
252impl<'a, P: Props + ?Sized + 'a> Props for alloc::sync::Arc<P> {
253    fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
254        &'kv self,
255        for_each: F,
256    ) -> ControlFlow<()> {
257        (**self).for_each(for_each)
258    }
259
260    fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
261        (**self).get(key)
262    }
263
264    fn pull<'kv, V: FromValue<'kv>, K: ToStr>(&'kv self, key: K) -> Option<V> {
265        (**self).pull(key)
266    }
267
268    fn is_unique(&self) -> bool {
269        (**self).is_unique()
270    }
271
272    fn size(&self) -> Option<usize> {
273        (**self).size()
274    }
275}
276
277impl<K: ToStr, V: ToValue> Props for (K, V) {
278    fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
279        &'kv self,
280        mut for_each: F,
281    ) -> ControlFlow<()> {
282        for_each(self.0.to_str(), self.1.to_value())
283    }
284
285    fn get<'v, G: ToStr>(&'v self, key: G) -> Option<Value<'v>> {
286        if key.to_str() == self.0.to_str() {
287            Some(self.1.to_value())
288        } else {
289            None
290        }
291    }
292
293    fn is_unique(&self) -> bool {
294        true
295    }
296
297    fn size(&self) -> Option<usize> {
298        Some(1)
299    }
300}
301
302impl<P: Props> Props for [P] {
303    fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
304        &'kv self,
305        mut for_each: F,
306    ) -> ControlFlow<()> {
307        for p in self {
308            p.for_each(&mut for_each)?;
309        }
310
311        ControlFlow::Continue(())
312    }
313
314    fn get<'v, G: ToStr>(&'v self, key: G) -> Option<Value<'v>> {
315        let key = key.to_str();
316
317        for p in self {
318            if let Some(value) = p.get(key.by_ref()) {
319                return Some(value);
320            }
321        }
322
323        None
324    }
325
326    fn size(&self) -> Option<usize> {
327        let mut size = 0;
328
329        for p in self {
330            size += p.size()?;
331        }
332
333        Some(size)
334    }
335}
336
337impl<T, const N: usize> Props for [T; N]
338where
339    [T]: Props,
340{
341    fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
342        &'kv self,
343        for_each: F,
344    ) -> ControlFlow<()> {
345        Props::for_each(self as &[_], for_each)
346    }
347
348    fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
349        Props::get(self as &[_], key)
350    }
351
352    fn pull<'kv, V: FromValue<'kv>, K: ToStr>(&'kv self, key: K) -> Option<V> {
353        Props::pull(self as &[_], key)
354    }
355
356    fn is_unique(&self) -> bool {
357        Props::is_unique(self as &[_])
358    }
359
360    fn size(&self) -> Option<usize> {
361        Props::size(self as &[_])
362    }
363}
364
365impl Props for Empty {
366    fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
367        &'kv self,
368        _: F,
369    ) -> ControlFlow<()> {
370        ControlFlow::Continue(())
371    }
372
373    fn get<'v, K: ToStr>(&'v self, _: K) -> Option<Value<'v>> {
374        None
375    }
376
377    fn is_unique(&self) -> bool {
378        true
379    }
380
381    fn size(&self) -> Option<usize> {
382        Some(0)
383    }
384}
385
386impl<A: Props, B: Props> Props for And<A, B> {
387    fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
388        &'kv self,
389        mut for_each: F,
390    ) -> ControlFlow<()> {
391        self.left().for_each(&mut for_each)?;
392        self.right().for_each(for_each)
393    }
394
395    fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
396        let key = key.borrow();
397
398        self.left().get(key).or_else(|| self.right().get(key))
399    }
400
401    fn size(&self) -> Option<usize> {
402        Some(self.left().size()? + self.right().size()?)
403    }
404}
405
406/**
407The result of calling [`Props::filter`].
408*/
409pub struct Filter<P, F> {
410    props: P,
411    filter: F,
412}
413
414impl<P, F> Filter<P, F> {
415    fn new(props: P, filter: F) -> Self {
416        Filter { props, filter }
417    }
418}
419
420impl<P: Props, F: Fn(Str, Value) -> bool> Props for Filter<P, F> {
421    fn for_each<'kv, T: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
422        &'kv self,
423        mut for_each: T,
424    ) -> ControlFlow<()> {
425        self.props.for_each(|key, value| {
426            if !(self.filter)(key.by_ref(), value.by_ref()) {
427                return ControlFlow::Continue(());
428            }
429
430            for_each(key, value)
431        })
432    }
433
434    fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
435        let key = key.to_str();
436
437        self.props
438            .get(key.by_ref())
439            .filter(|v| (self.filter)(key, v.by_ref()))
440    }
441
442    fn is_unique(&self) -> bool {
443        self.props.is_unique()
444    }
445
446    fn size(&self) -> Option<usize> {
447        None
448    }
449}
450
451/**
452A type that can be constructed from [`Props`].
453*/
454pub trait FromProps<'kv> {
455    /**
456    Convert from `P`.
457
458    Implementors of this method may re-order or deduplicate key-values in `P`.
459    If any deduplication occurs, it must take _the first_ value seen for a given key.
460    */
461    fn from_props<P: Props + ?Sized>(props: &'kv P) -> Self;
462}
463
464#[cfg(feature = "alloc")]
465impl<'kv, 'a, C: FromProps<'kv> + 'a> FromProps<'kv> for alloc::boxed::Box<C> {
466    fn from_props<P: Props + ?Sized>(props: &'kv P) -> Self {
467        alloc::boxed::Box::new(C::from_props(props))
468    }
469}
470
471#[cfg(feature = "alloc")]
472impl<'kv, 'a, C: FromProps<'kv> + 'a> FromProps<'kv> for alloc::sync::Arc<C> {
473    fn from_props<P: Props + ?Sized>(props: &'kv P) -> Self {
474        alloc::sync::Arc::new(C::from_props(props))
475    }
476}
477
478#[cfg(feature = "alloc")]
479mod alloc_support {
480    use super::*;
481
482    use crate::value::OwnedValue;
483
484    use core::{cmp, iter, mem, ptr};
485
486    use alloc::{boxed::Box, collections::BTreeMap, sync::Arc, vec::Vec};
487
488    /**
489    A set of owned [`Props`].
490
491    Properties are deduplicated, but the original iteration order is retained. If the collection is created from [`OwnedProps::collect_shared`] then cloning is also cheap.
492
493    ## Implementation details
494
495    Internally, `OwnedProps` is backed by a hashtable to make key lookup efficient. Each entry in the table also forms a linked list in iteration order.
496    The hash algorithm used is FNV-1a.
497    */
498    pub struct OwnedProps {
499        buckets: *const [OwnedPropsBucket],
500        nprops: usize,
501        owner: OwnedPropsOwner,
502        head: Option<*const OwnedProp>,
503    }
504
505    // SAFETY: `OwnedProps` synchronizes through `Arc` when ownership is shared
506    unsafe impl Send for OwnedProps {}
507    // SAFETY: `OwnedProps` does not use interior mutability
508    unsafe impl Sync for OwnedProps {}
509
510    impl Clone for OwnedProps {
511        fn clone(&self) -> Self {
512            match self.owner {
513                OwnedPropsOwner::Box(_) => {
514                    let (nprops, props, head) = OwnedProps::cloned(self);
515
516                    OwnedProps::new_owned(nprops, props, head)
517                }
518                OwnedPropsOwner::Shared(ref props) => {
519                    OwnedProps::new_shared(self.nprops, props.clone(), self.head)
520                }
521            }
522        }
523    }
524
525    impl Drop for OwnedProps {
526        fn drop(&mut self) {
527            match self.owner {
528                OwnedPropsOwner::Box(boxed) => {
529                    // SAFETY: We're dropping the box through our exclusive reference
530                    drop(unsafe { Box::from_raw(boxed) });
531                }
532                OwnedPropsOwner::Shared(_) => {
533                    // No special drop handling is needed for `Arc`
534                }
535            }
536        }
537    }
538
539    struct OwnedPropsBucket {
540        head: *mut OwnedProp,
541        tail: Vec<*mut OwnedProp>,
542    }
543
544    impl Drop for OwnedPropsBucket {
545        fn drop(&mut self) {
546            let mut guard = SliceDropGuard::new(&mut self.tail);
547
548            if !self.head.is_null() {
549                // SAFETY: We're dropping the box through our exclusive reference
550                drop(unsafe { Box::from_raw(self.head) })
551            }
552
553            // SAFETY: We're dropping the value through our exclusive reference
554            unsafe {
555                guard.drop();
556            }
557        }
558    }
559
560    struct OwnedProp {
561        key: Str<'static>,
562        value: OwnedValue,
563        next: Option<*const OwnedProp>,
564    }
565
566    enum OwnedPropsOwner {
567        Box(*mut [OwnedPropsBucket]),
568        Shared(Arc<[OwnedPropsBucket]>),
569    }
570
571    impl OwnedProps {
572        fn cloned(src: &Self) -> (usize, Box<[OwnedPropsBucket]>, Option<*const OwnedProp>) {
573            // NOTE: This could be better optimized
574            // We already know what size each bucket should be, we could store
575            // the index of the bucket on each entry to re-assemble them
576
577            let nbuckets = src.buckets.len();
578            let mut nprops = 0;
579            let mut buckets = iter::from_fn(|| Some(OwnedPropsBucket::new()))
580                .take(nbuckets)
581                .collect::<Vec<_>>()
582                .into_boxed_slice();
583            let mut head = None::<*const OwnedProp>;
584            let mut tail = None::<*mut OwnedProp>;
585
586            // This method creates an independent copy of a set of owned props
587            // We can't simply clone the underlying collections, because they hold
588            // internal pointers that would be invalidated
589            let _ = src.for_each(|prop| {
590                let bucket = &mut buckets[idx(nbuckets, &prop.key)];
591
592                // SAFETY: `head` and `tail` point to values in `collected`, which outlives this function call
593                let prop = unsafe {
594                    OwnedProp::new(&mut head, &mut tail, prop.key.clone(), prop.value.clone())
595                };
596
597                bucket.push(prop);
598                nprops += 1;
599
600                ControlFlow::Continue(())
601            });
602
603            (nprops, buckets, head)
604        }
605
606        fn new_owned(
607            nprops: usize,
608            buckets: Box<[OwnedPropsBucket]>,
609            head: Option<*const OwnedProp>,
610        ) -> Self {
611            let buckets = Box::into_raw(buckets);
612            let owner = OwnedPropsOwner::Box(buckets);
613
614            OwnedProps {
615                nprops,
616                buckets,
617                owner,
618                head,
619            }
620        }
621
622        fn new_shared(
623            nprops: usize,
624            buckets: Arc<[OwnedPropsBucket]>,
625            head: Option<*const OwnedProp>,
626        ) -> Self {
627            let ptr = Arc::as_ptr(&buckets);
628            let owner = OwnedPropsOwner::Shared(buckets);
629            let buckets = ptr;
630
631            OwnedProps {
632                nprops,
633                buckets,
634                owner,
635                head,
636            }
637        }
638
639        fn collect(
640            props: impl Props,
641            mut key: impl FnMut(Str) -> Str<'static>,
642            mut value: impl FnMut(Value) -> OwnedValue,
643        ) -> (usize, Box<[OwnedPropsBucket]>, Option<*const OwnedProp>) {
644            // We want a reasonable number of buckets to reduce the number of keys to scan
645            // We don't want to overallocate if `props.size()` returns a nonsense value though
646            let nbuckets = cmp::min(128, props.size().unwrap_or(32));
647            let mut nprops = 0;
648            let mut buckets = iter::from_fn(|| Some(OwnedPropsBucket::new()))
649                .take(nbuckets)
650                .collect::<Vec<_>>()
651                .into_boxed_slice();
652            let mut head = None::<*const OwnedProp>;
653            let mut tail = None::<*mut OwnedProp>;
654
655            let _ = props.for_each(|k, v| {
656                let bucket = &mut buckets[idx(nbuckets, &k)];
657
658                if bucket.get(&k).is_some() {
659                    ControlFlow::Continue(())
660                } else {
661                    // SAFETY: `head` and `tail` point to values in `collected`, which outlives this function call
662                    let prop = unsafe { OwnedProp::new(&mut head, &mut tail, key(k), value(v)) };
663
664                    bucket.push(prop);
665                    nprops += 1;
666
667                    ControlFlow::Continue(())
668                }
669            });
670
671            (nprops, buckets, head)
672        }
673
674        /**
675        Collect a set of [`Props`] into an owned collection.
676
677        Cloning will involve cloning the collection.
678        */
679        pub fn collect_owned(props: impl Props) -> Self {
680            let (nprops, buckets, head) = Self::collect(props, |k| k.to_owned(), |v| v.to_owned());
681
682            let buckets = Box::into_raw(buckets);
683            let owner = OwnedPropsOwner::Box(buckets);
684
685            OwnedProps {
686                nprops,
687                buckets,
688                owner,
689                head,
690            }
691        }
692
693        /**
694        Collect a set of [`Props`] into an owned collection.
695
696        Cloning will involve cloning the `Arc`, which may be cheaper than cloning the collection itself.
697        */
698        pub fn collect_shared(props: impl Props) -> Self {
699            let (nprops, buckets, head) =
700                Self::collect(props, |k| k.to_shared(), |v| v.to_shared());
701
702            Self::new_shared(nprops, buckets.into(), head)
703        }
704
705        /**
706        Get a new collection, taking an owned copy of the data in this one.
707
708        If the collection already contains an `Arc` value then this method is a cheap referenced counted clone.
709        */
710        pub fn to_shared(&self) -> Self {
711            match self.owner {
712                OwnedPropsOwner::Box(_) => {
713                    // We need to clone the data into new allocations, since we don't own them
714                    let (nprops, buckets, head) = OwnedProps::cloned(self);
715
716                    Self::new_shared(nprops, Arc::from(buckets), head)
717                }
718                OwnedPropsOwner::Shared(ref owner) => {
719                    OwnedProps::new_shared(self.nprops, owner.clone(), self.head)
720                }
721            }
722        }
723
724        fn for_each<'kv, F: FnMut(&'kv OwnedProp) -> ControlFlow<()>>(
725            &'kv self,
726            mut for_each: F,
727        ) -> ControlFlow<()> {
728            // Properties are iterated in insertion order
729            let mut next = self.head;
730
731            while let Some(current) = next.take() {
732                // SAFETY: The data in `current` is owned by `self`,
733                // which outlives this dereference
734                let current = unsafe { &*current };
735
736                for_each(&current)?;
737
738                next = current.next;
739            }
740
741            ControlFlow::Continue(())
742        }
743
744        fn get<'v, K: ToStr>(&'v self, key: K) -> Option<&'v OwnedProp> {
745            let key = key.to_str();
746
747            // SAFETY: `buckets` is owned by `Self`, which outlives this function call
748            let buckets = unsafe { &*self.buckets };
749
750            buckets[idx(buckets.len(), &key)].get(&key)
751        }
752    }
753
754    impl Props for OwnedProps {
755        fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
756            &'kv self,
757            mut for_each: F,
758        ) -> ControlFlow<()> {
759            self.for_each(|prop| for_each(prop.key.by_ref(), prop.value.by_ref()))
760        }
761
762        fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
763            self.get(key).map(|prop| prop.value.by_ref())
764        }
765
766        fn is_unique(&self) -> bool {
767            true
768        }
769
770        fn size(&self) -> Option<usize> {
771            Some(self.nprops)
772        }
773    }
774
775    impl<'kv> FromProps<'kv> for OwnedProps {
776        fn from_props<P: Props + ?Sized>(props: &'kv P) -> Self {
777            Self::collect_owned(props)
778        }
779    }
780
781    impl OwnedPropsBucket {
782        fn new() -> OwnedPropsBucket {
783            OwnedPropsBucket {
784                head: ptr::null_mut(),
785                tail: Vec::new(),
786            }
787        }
788
789        fn push(&mut self, mut prop: PropDropGuard) {
790            if self.head.is_null() {
791                self.head = prop.take();
792            } else {
793                self.tail.reserve(1);
794                self.tail.push(prop.take());
795            }
796        }
797
798        fn get(&self, k: &Str) -> Option<&OwnedProp> {
799            if !self.head.is_null() {
800                // SAFETY: `prop` is owned by `Self` and follows normal borrowing rules
801                let prop = unsafe { &*self.head };
802
803                if prop.key == *k {
804                    return Some(&prop);
805                }
806            }
807
808            for prop in &self.tail {
809                // SAFETY: `prop` is owned by `Self` and follows normal borrowing rules
810                let prop = unsafe { &**prop };
811
812                if prop.key == *k {
813                    return Some(&prop);
814                }
815            }
816
817            None
818        }
819    }
820
821    impl OwnedProp {
822        // SAFETY: `head` and `tail` must be valid to dereference within this function call
823        unsafe fn new(
824            head: &mut Option<*const OwnedProp>,
825            tail: &mut Option<*mut OwnedProp>,
826            key: Str<'static>,
827            value: OwnedValue,
828        ) -> PropDropGuard {
829            let guard = PropDropGuard::new(Box::new(OwnedProp {
830                key,
831                value,
832                next: None,
833            }));
834
835            let prop_ptr = guard.0;
836
837            *head = head.or_else(|| Some(prop_ptr));
838
839            if let Some(tail) = tail {
840                debug_assert!(head.is_some());
841
842                // SAFETY: The contract of `new` requires `tail` be valid to dereference
843                let tail = unsafe { &mut **tail };
844
845                debug_assert!(tail.next.is_none());
846                tail.next = Some(prop_ptr);
847            }
848            *tail = Some(prop_ptr);
849
850            guard
851        }
852    }
853
854    struct SliceDropGuard<'a> {
855        idx: usize,
856        value: &'a mut [*mut OwnedProp],
857    }
858
859    impl<'a> Drop for SliceDropGuard<'a> {
860        fn drop(&mut self) {
861            // Attempt to resume dropping if a destructor panics
862            // SAFETY: We're dropping the value through our exclusive reference
863            unsafe {
864                self.drop();
865            }
866        }
867    }
868
869    impl<'a> SliceDropGuard<'a> {
870        fn new(value: &'a mut [*mut OwnedProp]) -> Self {
871            SliceDropGuard { value, idx: 0 }
872        }
873
874        // SAFETY: The value referenced by this guard must be getting dropped
875        unsafe fn drop(&mut self) {
876            while self.idx < self.value.len() {
877                let prop = self.value[self.idx];
878                self.idx += 1;
879
880                // SAFETY: We're dropping the value through our exclusive reference
881                drop(unsafe { Box::from_raw(prop) });
882            }
883        }
884    }
885
886    struct PropDropGuard(*mut OwnedProp);
887
888    impl PropDropGuard {
889        fn new(prop: Box<OwnedProp>) -> Self {
890            PropDropGuard(Box::into_raw(prop))
891        }
892
893        fn take(&mut self) -> *mut OwnedProp {
894            mem::replace(&mut self.0, ptr::null_mut())
895        }
896    }
897
898    impl Drop for PropDropGuard {
899        fn drop(&mut self) {
900            if self.0.is_null() {
901                return;
902            }
903
904            // SAFETY: We're dropping the value through our exclusive reference
905            drop(unsafe { Box::from_raw(self.0) });
906        }
907    }
908
909    fn idx(buckets: usize, k: &Str) -> usize {
910        let mut hash = 0xcbf29ce484222325;
911
912        for b in k.get().as_bytes() {
913            hash = hash ^ (*b as u64);
914            hash = hash.wrapping_mul(0x00000100000001b3);
915        }
916
917        (hash as usize) % buckets
918    }
919
920    /**
921    The result of calling [`Props::dedup`].
922
923    Properties are de-duplicated by taking the first value for a given key.
924
925    Deduplication may allocate internally.
926    */
927    #[repr(transparent)]
928    pub struct Dedup<P: ?Sized>(P);
929
930    impl<P: ?Sized> Dedup<P> {
931        pub(super) fn new<'a>(props: &'a P) -> &'a Dedup<P> {
932            // SAFETY: `Dedup<P>` and `P` have the same ABI
933            unsafe { &*(props as *const P as *const Dedup<P>) }
934        }
935    }
936
937    impl<P: Props + ?Sized> Props for Dedup<P> {
938        fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
939            &'kv self,
940            mut for_each: F,
941        ) -> ControlFlow<()> {
942            // A filter that checks for duplicate keys, avoiding allocating if possible.
943            //
944            // For small numbers of keys, it's more efficient to simply brute-force compare them
945            // than it is to hash or binary search. In these cases we also avoid allocating for
946            // the filter.
947            enum Filter<'a> {
948                Inline(Inline<'a, 16>),
949                Spilled(Spilled<'a>),
950            }
951
952            impl<'a> Filter<'a> {
953                fn new(size: Option<usize>) -> Self {
954                    match size {
955                        Some(size) if size <= 16 => Filter::Inline(Inline::new()),
956                        _ => Filter::Spilled(Spilled::new()),
957                    }
958                }
959
960                fn insert(&mut self, key: Str<'a>, value: Value<'a>) {
961                    match self {
962                        Filter::Inline(ref mut inline) => match inline.insert(key, value) {
963                            Ok(()) => (),
964                            Err((key, value)) => {
965                                let mut spilled = Spilled::spill(inline.take());
966                                spilled.insert(key, value);
967
968                                *self = Filter::Spilled(spilled);
969                            }
970                        },
971                        Filter::Spilled(ref mut spilled) => spilled.insert(key, value),
972                    }
973                }
974
975                fn take<'b>(&'b mut self) -> impl Iterator<Item = (Str<'a>, Value<'a>)> + 'b {
976                    enum Either<A, B> {
977                        A(A),
978                        B(B),
979                    }
980
981                    impl<T, A: Iterator<Item = T>, B: Iterator<Item = T>> Iterator for Either<A, B> {
982                        type Item = T;
983
984                        fn next(&mut self) -> Option<Self::Item> {
985                            match self {
986                                Either::A(a) => a.next(),
987                                Either::B(b) => b.next(),
988                            }
989                        }
990                    }
991
992                    match self {
993                        Filter::Inline(ref mut inline) => Either::A(inline.take()),
994                        Filter::Spilled(ref mut spilled) => Either::B(spilled.take()),
995                    }
996                }
997            }
998
999            struct Inline<'a, const N: usize> {
1000                values: [(Str<'a>, Value<'a>); N],
1001                len: usize,
1002            }
1003
1004            impl<'a, const N: usize> Inline<'a, N> {
1005                fn new() -> Self {
1006                    Inline {
1007                        values: [const { (Str::new(""), Value::null()) }; N],
1008                        len: 0,
1009                    }
1010                }
1011
1012                fn insert(
1013                    &mut self,
1014                    key: Str<'a>,
1015                    value: Value<'a>,
1016                ) -> Result<(), (Str<'a>, Value<'a>)> {
1017                    if self.len == N {
1018                        return Err((key, value));
1019                    }
1020
1021                    for (seen, _) in &self.values[..self.len] {
1022                        if *seen == key {
1023                            return Ok(());
1024                        }
1025                    }
1026
1027                    self.values[self.len] = (key, value);
1028                    self.len += 1;
1029
1030                    Ok(())
1031                }
1032
1033                fn take<'b>(&'b mut self) -> impl Iterator<Item = (Str<'a>, Value<'a>)> + 'b {
1034                    let len = self.len;
1035                    self.len = 0;
1036
1037                    (&mut self.values[..len])
1038                        .into_iter()
1039                        .map(|v| mem::replace(v, (Str::new(""), Value::null())))
1040                }
1041            }
1042
1043            struct Spilled<'a> {
1044                values: BTreeMap<Str<'a>, Value<'a>>,
1045            }
1046
1047            impl<'a> Spilled<'a> {
1048                fn new() -> Self {
1049                    Spilled {
1050                        values: Default::default(),
1051                    }
1052                }
1053
1054                fn spill(seen: impl Iterator<Item = (Str<'a>, Value<'a>)>) -> Self {
1055                    Spilled {
1056                        values: seen.collect(),
1057                    }
1058                }
1059
1060                fn insert(&mut self, key: Str<'a>, value: Value<'a>) {
1061                    self.values.entry(key).or_insert(value);
1062                }
1063
1064                fn take<'b>(&'b mut self) -> impl Iterator<Item = (Str<'a>, Value<'a>)> + 'b {
1065                    mem::take(&mut self.values).into_iter()
1066                }
1067            }
1068
1069            // Optimization for props that are already unique
1070            if self.0.is_unique() {
1071                return self.0.for_each(for_each);
1072            }
1073
1074            let mut filter = Filter::new(self.0.size());
1075
1076            // Ignore any break from this iteration
1077            // We need to iterate twice here because we need to maintain a reference
1078            // to keys to check them for duplicates before passing them by-value to the `for_each` fn
1079            let _ = self.0.for_each(|key, value| {
1080                filter.insert(key, value);
1081
1082                ControlFlow::Continue(())
1083            });
1084
1085            for (key, value) in filter.take() {
1086                for_each(key, value)?;
1087            }
1088
1089            ControlFlow::Continue(())
1090        }
1091
1092        fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
1093            self.0.get(key)
1094        }
1095
1096        fn is_unique(&self) -> bool {
1097            true
1098        }
1099
1100        fn size(&self) -> Option<usize> {
1101            // NOTE: The size here may be larger than the actual number of properties yielded
1102            // after deduplication. `size` isn't required to be exact, just not too small.
1103            self.0.size()
1104        }
1105    }
1106
1107    impl<T: Props> Props for Vec<T> {
1108        fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
1109            &'kv self,
1110            for_each: F,
1111        ) -> ControlFlow<()> {
1112            Props::for_each(self as &[_], for_each)
1113        }
1114
1115        fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
1116            Props::get(self as &[_], key)
1117        }
1118
1119        fn pull<'kv, V: FromValue<'kv>, K: ToStr>(&'kv self, key: K) -> Option<V> {
1120            Props::pull(self as &[_], key)
1121        }
1122
1123        fn is_unique(&self) -> bool {
1124            Props::is_unique(self as &[_])
1125        }
1126
1127        fn size(&self) -> Option<usize> {
1128            Props::size(self as &[_])
1129        }
1130    }
1131
1132    impl<'kv, K, V> FromProps<'kv> for Vec<(K, V)>
1133    where
1134        K: From<Str<'kv>>,
1135        V: From<Value<'kv>>,
1136    {
1137        fn from_props<P: Props + ?Sized>(props: &'kv P) -> Self {
1138            let mut result = Vec::new();
1139
1140            let _ = props.for_each(|k, v| {
1141                result.push((k.into(), v.into()));
1142
1143                ControlFlow::Continue(())
1144            });
1145
1146            result
1147        }
1148    }
1149
1150    impl<K, V> Props for BTreeMap<K, V>
1151    where
1152        K: Ord + ToStr + Borrow<str>,
1153        V: ToValue,
1154    {
1155        fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
1156            &'kv self,
1157            mut for_each: F,
1158        ) -> ControlFlow<()> {
1159            for (k, v) in self {
1160                for_each(k.to_str(), v.to_value())?;
1161            }
1162
1163            ControlFlow::Continue(())
1164        }
1165
1166        fn get<'v, Q: ToStr>(&'v self, key: Q) -> Option<Value<'v>> {
1167            self.get(key.to_str().as_ref()).map(|v| v.to_value())
1168        }
1169
1170        fn is_unique(&self) -> bool {
1171            true
1172        }
1173
1174        fn size(&self) -> Option<usize> {
1175            Some(self.len())
1176        }
1177    }
1178
1179    impl<'kv, K, V> FromProps<'kv> for BTreeMap<K, V>
1180    where
1181        K: Ord + From<Str<'kv>>,
1182        V: From<Value<'kv>>,
1183    {
1184        fn from_props<P: Props + ?Sized>(props: &'kv P) -> Self {
1185            let mut result = BTreeMap::new();
1186
1187            let _ = props.for_each(|k, v| {
1188                result.entry(k.into()).or_insert_with(|| v.into());
1189
1190                ControlFlow::Continue(())
1191            });
1192
1193            result
1194        }
1195    }
1196
1197    #[cfg(test)]
1198    mod tests {
1199        use super::*;
1200
1201        use crate::value::OwnedValue;
1202
1203        #[test]
1204        fn btreemap_props() {
1205            let props = BTreeMap::from_iter([("a", 1), ("b", 2), ("c", 3)]);
1206
1207            assert_eq!(1, Props::get(&props, "a").unwrap().cast::<i32>().unwrap());
1208            assert_eq!(2, Props::get(&props, "b").unwrap().cast::<i32>().unwrap());
1209            assert_eq!(3, Props::get(&props, "c").unwrap().cast::<i32>().unwrap());
1210
1211            assert_eq!(1, Props::pull::<i32, _>(&props, "a").unwrap());
1212            assert_eq!(2, Props::pull::<i32, _>(&props, "b").unwrap());
1213            assert_eq!(3, Props::pull::<i32, _>(&props, "c").unwrap());
1214
1215            assert!(props.is_unique());
1216        }
1217
1218        #[test]
1219        fn btreemap_from_props() {
1220            let props = BTreeMap::<String, OwnedValue>::from_props(&[("a", 1), ("a", 2), ("c", 3)]);
1221
1222            assert_eq!(1, Props::pull::<i32, _>(&props, "a").unwrap());
1223            assert_eq!(3, Props::pull::<i32, _>(&props, "c").unwrap());
1224        }
1225
1226        #[test]
1227        fn vec_from_props() {
1228            let props = Vec::<(String, OwnedValue)>::from_props(&[("a", 1), ("a", 2), ("c", 3)]);
1229
1230            assert_eq!(3, props.len());
1231
1232            assert_eq!(1, Props::pull::<i32, _>(&props, "a").unwrap());
1233            assert_eq!(3, Props::pull::<i32, _>(&props, "c").unwrap());
1234        }
1235
1236        #[test]
1237        fn dedup() {
1238            let props = [
1239                ("a", Value::from(1)),
1240                ("a", Value::from(2)),
1241                ("b", Value::from(1)),
1242            ];
1243
1244            let deduped = props.dedup();
1245
1246            let mut ac = 0;
1247            let mut bc = 0;
1248
1249            let _ = deduped.for_each(|k, v| {
1250                match k.get() {
1251                    "a" => {
1252                        assert_eq!(1, v.cast::<i32>().unwrap());
1253                        ac += 1;
1254                    }
1255                    "b" => {
1256                        assert_eq!(1, v.cast::<i32>().unwrap());
1257                        bc += 1;
1258                    }
1259                    _ => (),
1260                }
1261
1262                ControlFlow::Continue(())
1263            });
1264
1265            assert_eq!(1, ac);
1266            assert_eq!(1, bc);
1267        }
1268
1269        #[test]
1270        fn dedup_many() {
1271            let props = [
1272                ("aumcgyiuerskg", 1),
1273                ("blvkmnfdigmgc", 2),
1274                ("cvojdfmcisemc", 3),
1275                ("dlkgjhmgkvnrd", 4),
1276                ("eiugrlgmvmgvd", 5),
1277                ("flfbjhmrimrtw", 6),
1278                ("goihudvngusrg", 7),
1279                ("hfjehrngviuwn", 8),
1280                ("ivojitvnjysns", 9),
1281                ("jciughnrhiens", 10),
1282                ("kofhfuernytnd", 11),
1283                ("lvgjrunfwwner", 12),
1284                ("mfjerukfnjhns", 13),
1285                ("nmorikjnnehsx", 14),
1286                ("oiovjrmunsnex", 15),
1287                ("pijdshfenrnfq", 16),
1288                ("aumcgyiuerskg", 11),
1289                ("blvkmnfdigmgc", 21),
1290                ("cvojdfmcisemc", 31),
1291                ("dlkgjhmgkvnrd", 41),
1292                ("eiugrlgmvmgvd", 51),
1293                ("flfbjhmrimrtw", 61),
1294                ("goihudvngusrg", 71),
1295                ("hfjehrngviuwn", 81),
1296                ("ivojitvnjysns", 91),
1297                ("jciughnrhiens", 101),
1298                ("kofhfuernytnd", 111),
1299                ("lvgjrunfwwner", 121),
1300                ("mfjerukfnjhns", 131),
1301                ("nmorikjnnehsx", 141),
1302                ("oiovjrmunsnex", 151),
1303                ("pijdshfenrnfq", 161),
1304            ];
1305
1306            let deduped = props.dedup();
1307
1308            let mut ac = 0;
1309            let mut bc = 0;
1310
1311            let _ = deduped.for_each(|k, v| {
1312                match k.get() {
1313                    "aumcgyiuerskg" => {
1314                        assert_eq!(1, v.cast::<i32>().unwrap());
1315                        ac += 1;
1316                    }
1317                    "blvkmnfdigmgc" => {
1318                        assert_eq!(2, v.cast::<i32>().unwrap());
1319                        bc += 1;
1320                    }
1321                    _ => (),
1322                }
1323
1324                ControlFlow::Continue(())
1325            });
1326
1327            assert_eq!(1, ac);
1328            assert_eq!(1, bc);
1329        }
1330
1331        struct WrongSize<P> {
1332            props: P,
1333            size: Option<usize>,
1334        }
1335
1336        impl<P: Props> Props for WrongSize<P> {
1337            fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
1338                &'kv self,
1339                for_each: F,
1340            ) -> ControlFlow<()> {
1341                self.props.for_each(for_each)
1342            }
1343
1344            fn size(&self) -> Option<usize> {
1345                self.size
1346            }
1347        }
1348
1349        #[test]
1350        fn dedup_low_ball_size() {
1351            let props = WrongSize {
1352                props: [
1353                    ("aumcgyiuerskg", 1),
1354                    ("blvkmnfdigmgc", 2),
1355                    ("cvojdfmcisemc", 3),
1356                    ("dlkgjhmgkvnrd", 4),
1357                    ("eiugrlgmvmgvd", 5),
1358                    ("flfbjhmrimrtw", 6),
1359                    ("goihudvngusrg", 7),
1360                    ("hfjehrngviuwn", 8),
1361                    ("ivojitvnjysns", 9),
1362                    ("jciughnrhiens", 10),
1363                    ("kofhfuernytnd", 11),
1364                    ("lvgjrunfwwner", 12),
1365                    ("mfjerukfnjhns", 13),
1366                    ("nmorikjnnehsx", 14),
1367                    ("oiovjrmunsnex", 15),
1368                    ("pijdshfenrnfq", 16),
1369                    ("rkjhfngjrfnhf", 17),
1370                ],
1371                size: Some(1),
1372            };
1373
1374            let deduped = props.dedup();
1375
1376            let mut count = 0;
1377
1378            let _ = deduped.for_each(|_, _| {
1379                count += 1;
1380
1381                ControlFlow::Continue(())
1382            });
1383
1384            assert_eq!(17, count);
1385        }
1386
1387        #[test]
1388        fn dedup_high_ball_size() {
1389            let props = WrongSize {
1390                props: [("aumcgyiuerskg", 1)],
1391                size: Some(usize::MAX),
1392            };
1393
1394            let deduped = props.dedup();
1395
1396            let mut count = 0;
1397
1398            let _ = deduped.for_each(|_, _| {
1399                count += 1;
1400
1401                ControlFlow::Continue(())
1402            });
1403
1404            assert_eq!(1, count);
1405        }
1406
1407        #[test]
1408        fn owned_props_empty() {
1409            let props = OwnedProps::collect_owned([] as [(Str, Value); 0]);
1410
1411            assert_eq!(Some(0), props.size());
1412            assert!(props.is_unique());
1413
1414            let mut count = 0;
1415
1416            let _ = props.for_each(|_| {
1417                count += 1;
1418                ControlFlow::Continue(())
1419            });
1420
1421            assert_eq!(0, count);
1422        }
1423
1424        #[test]
1425        fn owned_props_collect() {
1426            for (description, case) in [
1427                (
1428                    "owned",
1429                    OwnedProps::collect_owned([
1430                        ("b", 2),
1431                        ("a", 1),
1432                        ("c", 3),
1433                        ("b", 12),
1434                        ("a", 11),
1435                        ("c", 13),
1436                    ]),
1437                ),
1438                (
1439                    "shared",
1440                    OwnedProps::collect_shared([
1441                        ("b", 2),
1442                        ("a", 1),
1443                        ("c", 3),
1444                        ("b", 12),
1445                        ("a", 11),
1446                        ("c", 13),
1447                    ]),
1448                ),
1449                (
1450                    "owned -> shared",
1451                    OwnedProps::collect_owned([
1452                        ("b", 2),
1453                        ("a", 1),
1454                        ("c", 3),
1455                        ("b", 12),
1456                        ("a", 11),
1457                        ("c", 13),
1458                    ])
1459                    .to_shared(),
1460                ),
1461                (
1462                    "shared -> shared",
1463                    OwnedProps::collect_shared([
1464                        ("b", 2),
1465                        ("a", 1),
1466                        ("c", 3),
1467                        ("b", 12),
1468                        ("a", 11),
1469                        ("c", 13),
1470                    ])
1471                    .to_shared(),
1472                ),
1473                (
1474                    "owned -> clone",
1475                    OwnedProps::collect_owned([
1476                        ("b", 2),
1477                        ("a", 1),
1478                        ("c", 3),
1479                        ("b", 12),
1480                        ("a", 11),
1481                        ("c", 13),
1482                    ])
1483                    .clone(),
1484                ),
1485                (
1486                    "shared -> clone",
1487                    OwnedProps::collect_shared([
1488                        ("b", 2),
1489                        ("a", 1),
1490                        ("c", 3),
1491                        ("b", 12),
1492                        ("a", 11),
1493                        ("c", 13),
1494                    ])
1495                    .clone(),
1496                ),
1497            ] {
1498                assert_eq!(Some(3), case.size());
1499                assert!(case.is_unique());
1500
1501                assert_eq!(Some(1), case.pull::<usize, _>("a"), "{description}");
1502                assert_eq!(Some(2), case.pull::<usize, _>("b"), "{description}");
1503                assert_eq!(Some(3), case.pull::<usize, _>("c"), "{description}");
1504
1505                let mut values = Vec::new();
1506
1507                let _ = case.for_each(|prop| {
1508                    values.push((prop.key.get(), prop.value.by_ref().cast::<usize>()));
1509                    ControlFlow::Continue(())
1510                });
1511
1512                assert_eq!(
1513                    vec![("b", Some(2)), ("a", Some(1)), ("c", Some(3))],
1514                    values,
1515                    "{description}"
1516                );
1517            }
1518        }
1519    }
1520}
1521
1522#[cfg(feature = "alloc")]
1523pub use alloc_support::*;
1524
1525#[cfg(feature = "std")]
1526mod std_support {
1527    use super::*;
1528
1529    use std::{collections::HashMap, hash::Hash};
1530
1531    impl<K, V> Props for HashMap<K, V>
1532    where
1533        K: Eq + Hash + ToStr + Borrow<str>,
1534        V: ToValue,
1535    {
1536        fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
1537            &'kv self,
1538            mut for_each: F,
1539        ) -> ControlFlow<()> {
1540            for (k, v) in self {
1541                for_each(k.to_str(), v.to_value())?;
1542            }
1543
1544            ControlFlow::Continue(())
1545        }
1546
1547        fn get<'v, Q: ToStr>(&'v self, key: Q) -> Option<Value<'v>> {
1548            self.get(key.to_str().as_ref()).map(|v| v.to_value())
1549        }
1550
1551        fn is_unique(&self) -> bool {
1552            true
1553        }
1554
1555        fn size(&self) -> Option<usize> {
1556            Some(self.len())
1557        }
1558    }
1559
1560    impl<'kv, K, V> FromProps<'kv> for HashMap<K, V>
1561    where
1562        K: Eq + Hash + From<Str<'kv>>,
1563        V: From<Value<'kv>>,
1564    {
1565        fn from_props<P: Props + ?Sized>(props: &'kv P) -> Self {
1566            let mut result = HashMap::new();
1567
1568            let _ = props.for_each(|k, v| {
1569                result.entry(k.into()).or_insert_with(|| v.into());
1570
1571                ControlFlow::Continue(())
1572            });
1573
1574            result
1575        }
1576    }
1577
1578    #[cfg(test)]
1579    mod tests {
1580        use super::*;
1581
1582        use crate::value::OwnedValue;
1583
1584        #[test]
1585        fn hashmap_props() {
1586            let props = HashMap::from_iter([("a", 1), ("b", 2), ("c", 3)]);
1587
1588            assert_eq!(1, Props::get(&props, "a").unwrap().cast::<i32>().unwrap());
1589            assert_eq!(2, Props::get(&props, "b").unwrap().cast::<i32>().unwrap());
1590            assert_eq!(3, Props::get(&props, "c").unwrap().cast::<i32>().unwrap());
1591
1592            assert_eq!(1, Props::pull::<i32, _>(&props, "a").unwrap());
1593            assert_eq!(2, Props::pull::<i32, _>(&props, "b").unwrap());
1594            assert_eq!(3, Props::pull::<i32, _>(&props, "c").unwrap());
1595
1596            assert!(props.is_unique());
1597        }
1598
1599        #[test]
1600        fn hashmap_from_props() {
1601            let props = HashMap::<String, OwnedValue>::from_props(&[("a", 1), ("a", 2), ("c", 3)]);
1602
1603            assert_eq!(1, Props::pull::<i32, _>(&props, "a").unwrap());
1604            assert_eq!(3, Props::pull::<i32, _>(&props, "c").unwrap());
1605        }
1606    }
1607}
1608
1609/**
1610The result of calling [`Props::as_map`].
1611
1612This type implements serialization traits, serializing properties as a map of key-value pairs.
1613*/
1614#[repr(transparent)]
1615pub struct AsMap<P: ?Sized>(P);
1616
1617impl<P: ?Sized> AsMap<P> {
1618    fn new<'a>(props: &'a P) -> &'a AsMap<P> {
1619        // SAFETY: `AsMap<P>` and `P` have the same ABI
1620        unsafe { &*(props as *const P as *const AsMap<P>) }
1621    }
1622}
1623
1624impl<P: Props + ?Sized> Props for AsMap<P> {
1625    fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
1626        &'kv self,
1627        for_each: F,
1628    ) -> ControlFlow<()> {
1629        self.0.for_each(for_each)
1630    }
1631
1632    fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
1633        self.0.get(key)
1634    }
1635
1636    fn pull<'kv, V: FromValue<'kv>, K: ToStr>(&'kv self, key: K) -> Option<V> {
1637        self.0.pull(key)
1638    }
1639
1640    fn is_unique(&self) -> bool {
1641        self.0.is_unique()
1642    }
1643
1644    fn size(&self) -> Option<usize> {
1645        self.0.size()
1646    }
1647}
1648
1649#[cfg(feature = "sval")]
1650impl<P: Props + ?Sized> sval::Value for AsMap<P> {
1651    fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result {
1652        stream.map_begin(None)?;
1653
1654        let mut r = Ok(());
1655        let _ = self.for_each(|k, v| {
1656            r = (|| {
1657                stream.map_key_begin()?;
1658                sval_ref::stream_ref(&mut *stream, k)?;
1659                stream.map_key_end()?;
1660
1661                stream.map_value_begin()?;
1662                sval_ref::stream_ref(&mut *stream, v)?;
1663                stream.map_value_end()
1664            })();
1665
1666            if r.is_ok() {
1667                ControlFlow::Continue(())
1668            } else {
1669                ControlFlow::Break(())
1670            }
1671        });
1672        r?;
1673
1674        stream.map_end()
1675    }
1676}
1677
1678#[cfg(feature = "serde")]
1679impl<P: Props + ?Sized> serde::Serialize for AsMap<P> {
1680    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
1681        use serde::ser::SerializeMap as _;
1682
1683        let mut err = None;
1684
1685        let mut map = serializer.serialize_map(None)?;
1686
1687        let _ = self.for_each(|k, v| match map.serialize_entry(&k, &v) {
1688            Ok(()) => ControlFlow::Continue(()),
1689            Err(e) => {
1690                err = Some(e);
1691                ControlFlow::Break(())
1692            }
1693        });
1694
1695        if let Some(e) = err {
1696            return Err(e);
1697        }
1698
1699        map.end()
1700    }
1701}
1702
1703impl<P: Props + ?Sized> fmt::Debug for AsMap<P> {
1704    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1705        fmt::Display::fmt(self, f)
1706    }
1707}
1708
1709impl<P: Props + ?Sized> fmt::Display for AsMap<P> {
1710    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1711        let mut map = f.debug_map();
1712
1713        let _ = self.for_each(|k, v| {
1714            map.entry(&k, &v);
1715
1716            ControlFlow::Continue(())
1717        });
1718
1719        map.finish()
1720    }
1721}
1722
1723mod internal {
1724    use core::ops::ControlFlow;
1725
1726    use crate::{str::Str, value::Value};
1727
1728    pub trait DispatchProps {
1729        fn dispatch_for_each<'kv, 'f>(
1730            &'kv self,
1731            for_each: &'f mut dyn FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>,
1732        ) -> ControlFlow<()>;
1733
1734        fn dispatch_get(&self, key: Str) -> Option<Value<'_>>;
1735
1736        fn dispatch_is_unique(&self) -> bool;
1737
1738        fn dispatch_size(&self) -> Option<usize>;
1739    }
1740
1741    pub trait SealedProps {
1742        fn erase_props(&self) -> crate::internal::Erased<&dyn DispatchProps>;
1743    }
1744}
1745
1746/**
1747An object-safe [`Props`].
1748
1749A `dyn ErasedProps` can be treated as `impl Props`.
1750*/
1751pub trait ErasedProps: internal::SealedProps {}
1752
1753impl<P: Props> ErasedProps for P {}
1754
1755impl<P: Props> internal::SealedProps for P {
1756    fn erase_props(&self) -> crate::internal::Erased<&dyn internal::DispatchProps> {
1757        crate::internal::Erased(self)
1758    }
1759}
1760
1761impl<P: Props> internal::DispatchProps for P {
1762    fn dispatch_for_each<'kv, 'f>(
1763        &'kv self,
1764        for_each: &'f mut dyn FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>,
1765    ) -> ControlFlow<()> {
1766        self.for_each(for_each)
1767    }
1768
1769    fn dispatch_get<'v>(&'v self, key: Str) -> Option<Value<'v>> {
1770        self.get(key)
1771    }
1772
1773    fn dispatch_is_unique(&self) -> bool {
1774        self.is_unique()
1775    }
1776
1777    fn dispatch_size(&self) -> Option<usize> {
1778        self.size()
1779    }
1780}
1781
1782impl<'a> Props for dyn ErasedProps + 'a {
1783    fn for_each<'kv, F: FnMut(Str<'kv>, Value<'kv>) -> ControlFlow<()>>(
1784        &'kv self,
1785        mut for_each: F,
1786    ) -> ControlFlow<()> {
1787        self.erase_props().0.dispatch_for_each(&mut for_each)
1788    }
1789
1790    fn get<'v, K: ToStr>(&'v self, key: K) -> Option<Value<'v>> {
1791        self.erase_props().0.dispatch_get(key.to_str())
1792    }
1793
1794    fn is_unique(&self) -> bool {
1795        self.erase_props().0.dispatch_is_unique()
1796    }
1797
1798    fn size(&self) -> Option<usize> {
1799        self.erase_props().0.dispatch_size()
1800    }
1801}
1802
1803#[cfg(test)]
1804mod tests {
1805    use super::*;
1806
1807    #[test]
1808    fn tuple_props() {
1809        let props = ("a", 1);
1810
1811        assert_eq!(1, props.get("a").unwrap().cast::<i32>().unwrap());
1812
1813        assert_eq!(1, props.pull::<i32, _>("a").unwrap());
1814
1815        assert!(props.is_unique());
1816    }
1817
1818    #[test]
1819    fn array_props() {
1820        let props = [("a", 1), ("b", 2), ("c", 3)];
1821
1822        assert_eq!(1, props.get("a").unwrap().cast::<i32>().unwrap());
1823        assert_eq!(2, props.get("b").unwrap().cast::<i32>().unwrap());
1824        assert_eq!(3, props.get("c").unwrap().cast::<i32>().unwrap());
1825
1826        assert_eq!(1, props.pull::<i32, _>("a").unwrap());
1827        assert_eq!(2, props.pull::<i32, _>("b").unwrap());
1828        assert_eq!(3, props.pull::<i32, _>("c").unwrap());
1829
1830        assert!(!props.is_unique());
1831    }
1832
1833    #[test]
1834    fn option_props() {
1835        for (props, expected) in [(Some(("a", 1)), Some(1)), (None, None)] {
1836            assert_eq!(expected, props.pull::<i32, _>("a"));
1837        }
1838    }
1839
1840    #[test]
1841    fn erased_props() {
1842        let props = ("a", 1);
1843
1844        let props = &props as &dyn ErasedProps;
1845
1846        assert_eq!(1, props.get("a").unwrap().cast::<i32>().unwrap());
1847
1848        assert_eq!(1, props.pull::<i32, _>("a").unwrap());
1849
1850        assert!(props.is_unique());
1851    }
1852
1853    #[test]
1854    fn get() {
1855        let props = [("a", 1), ("a", 2)];
1856
1857        assert_eq!(1, props.get("a").unwrap().cast::<i32>().unwrap());
1858    }
1859
1860    #[test]
1861    fn pull() {
1862        let props = [("a", 1), ("a", 2)];
1863
1864        assert_eq!(1, props.pull::<i32, _>("a").unwrap());
1865    }
1866
1867    #[test]
1868    fn size() {
1869        let props = [("a", 1), ("b", 2)].and_props([("c", 3)]);
1870
1871        assert_eq!(Some(3), props.size());
1872    }
1873
1874    #[test]
1875    fn and_props() {
1876        let a = ("a", 1);
1877        let b = [("b", 2), ("c", 3)];
1878
1879        let props = a.and_props(b);
1880
1881        assert_eq!(1, props.get("a").unwrap().cast::<i32>().unwrap());
1882        assert_eq!(2, props.get("b").unwrap().cast::<i32>().unwrap());
1883        assert_eq!(3, props.get("c").unwrap().cast::<i32>().unwrap());
1884
1885        assert_eq!(1, props.pull::<i32, _>("a").unwrap());
1886        assert_eq!(2, props.pull::<i32, _>("b").unwrap());
1887        assert_eq!(3, props.pull::<i32, _>("c").unwrap());
1888
1889        assert!(!props.is_unique());
1890    }
1891
1892    #[test]
1893    fn as_map() {
1894        let props = [("a", 1), ("b", 2)].as_map();
1895
1896        assert_eq!("{\"a\": 1, \"b\": 2}", props.to_string());
1897    }
1898
1899    #[cfg(feature = "sval")]
1900    #[test]
1901    fn as_map_stream() {
1902        let props = [("a", 1), ("b", 2)].as_map();
1903
1904        sval_test::assert_tokens(
1905            &props,
1906            &[
1907                sval_test::Token::MapBegin(None),
1908                sval_test::Token::MapKeyBegin,
1909                sval_test::Token::TextBegin(Some(1)),
1910                sval_test::Token::TextFragmentComputed("a".to_owned()),
1911                sval_test::Token::TextEnd,
1912                sval_test::Token::MapKeyEnd,
1913                sval_test::Token::MapValueBegin,
1914                sval_test::Token::I64(1),
1915                sval_test::Token::MapValueEnd,
1916                sval_test::Token::MapKeyBegin,
1917                sval_test::Token::TextBegin(Some(1)),
1918                sval_test::Token::TextFragmentComputed("b".to_owned()),
1919                sval_test::Token::TextEnd,
1920                sval_test::Token::MapKeyEnd,
1921                sval_test::Token::MapValueBegin,
1922                sval_test::Token::I64(2),
1923                sval_test::Token::MapValueEnd,
1924                sval_test::Token::MapEnd,
1925            ],
1926        );
1927    }
1928
1929    #[cfg(feature = "serde")]
1930    #[test]
1931    fn as_map_serialize() {
1932        let props = [("a", 1), ("b", 2)].as_map();
1933
1934        serde_test::assert_ser_tokens(
1935            &props,
1936            &[
1937                serde_test::Token::Map { len: None },
1938                serde_test::Token::Str("a"),
1939                serde_test::Token::I64(1),
1940                serde_test::Token::Str("b"),
1941                serde_test::Token::I64(2),
1942                serde_test::Token::MapEnd,
1943            ],
1944        );
1945    }
1946
1947    #[test]
1948    fn filter() {
1949        let props =
1950            [("a", 1), ("b", 2), ("c", 3)].filter(|k, v| k == "a" || v.cast::<usize>() == Some(3));
1951
1952        assert!(props.get("a").is_some());
1953        assert!(props.get("b").is_none());
1954        assert!(props.get("c").is_some());
1955    }
1956}