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    Collect these properties into another collection type.
97
98    This method defers to the [`FromProps`] implementation on `C`.
99    */
100    fn collect<'kv, C: FromProps<'kv>>(&'kv self) -> C {
101        C::from_props(self)
102    }
103
104    /**
105    Get an adapter that will serialize properties as a map.
106    */
107    fn as_map(&self) -> &AsMap<Self>
108    where
109        Self: Sized,
110    {
111        AsMap::new(self)
112    }
113
114    /**
115    Lazily de-duplicate properties in the collection.
116
117    Properties are de-duplicated by taking the first value for a given key.
118    */
119    #[cfg(feature = "alloc")]
120    fn dedup(&self) -> &Dedup<Self>
121    where
122        Self: Sized,
123    {
124        Dedup::new(self)
125    }
126
127    /**
128    Whether the collection is known not to contain any duplicate keys.
129
130    If there's any possibility a key may be duplicated, this method should return `false`.
131    */
132    fn is_unique(&self) -> bool {
133        false
134    }
135
136    /**
137    A hint on the number of properties in the collection.
138
139    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.
140
141    If the collection can't determine its size without needing to walk its values then this method will return `None`.
142    */
143    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
394/**
395A type that can be constructed from [`Props`].
396*/
397pub trait FromProps<'kv> {
398    /**
399    Convert from `P`.
400
401    Implementors of this method may re-order or deduplicate key-values in `P`.
402    If any deduplication occurs, it must take _the first_ value seen for a given key.
403    */
404    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    /**
432    A set of owned [`Props`].
433
434    Properties are deduplicated, but the original iteration order is retained. If the collection is created from [`OwnedProps::collect_shared`] then cloning is also cheap.
435
436    ## Implementation details
437
438    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.
439    The hash algorithm used is FNV-1a.
440    */
441    pub struct OwnedProps {
442        buckets: *const [OwnedPropsBucket],
443        nprops: usize,
444        owner: OwnedPropsOwner,
445        head: Option<*const OwnedProp>,
446    }
447
448    // SAFETY: `OwnedProps` synchronizes through `Arc` when ownership is shared
449    unsafe impl Send for OwnedProps {}
450    // SAFETY: `OwnedProps` does not use interior mutability
451    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                    // SAFETY: We're dropping the box through our exclusive reference
473                    drop(unsafe { Box::from_raw(boxed) });
474                }
475                OwnedPropsOwner::Shared(_) => {
476                    // No special drop handling is needed for `Arc`
477                }
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                // SAFETY: We're dropping the box through our exclusive reference
493                drop(unsafe { Box::from_raw(self.head) })
494            }
495
496            // SAFETY: We're dropping the value through our exclusive reference
497            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            // NOTE: This could be better optimized
517            // We already know what size each bucket should be, we could store
518            // the index of the bucket on each entry to re-assemble them
519
520            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            // This method creates an independent copy of a set of owned props
530            // We can't simply clone the underlying collections, because they hold
531            // internal pointers that would be invalidated
532            let _ = src.for_each(|prop| {
533                let bucket = &mut buckets[idx(nbuckets, &prop.key)];
534
535                // SAFETY: `head` and `tail` point to values in `collected`, which outlives this function call
536                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            // We want a reasonable number of buckets to reduce the number of keys to scan
588            // We don't want to overallocate if `props.size()` returns a nonsense value though
589            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                    // SAFETY: `head` and `tail` point to values in `collected`, which outlives this function call
605                    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        /**
618        Collect a set of [`Props`] into an owned collection.
619
620        Cloning will involve cloning the collection.
621        */
622        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        /**
637        Collect a set of [`Props`] into an owned collection.
638
639        Cloning will involve cloning the `Arc`, which may be cheaper than cloning the collection itself.
640        */
641        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        /**
649        Get a new collection, taking an owned copy of the data in this one.
650
651        If the collection already contains an `Arc` value then this method is a cheap referenced counted clone.
652        */
653        pub fn to_shared(&self) -> Self {
654            match self.owner {
655                OwnedPropsOwner::Box(_) => {
656                    // We need to clone the data into new allocations, since we don't own them
657                    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            // Properties are iterated in insertion order
672            let mut next = self.head;
673
674            while let Some(current) = next.take() {
675                // SAFETY: The data in `current` is owned by `self`,
676                // which outlives this dereference
677                let current = unsafe { &*current };
678
679                for_each(&current)?;
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            // SAFETY: `buckets` is owned by `Self`, which outlives this function call
691            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                // SAFETY: `prop` is owned by `Self` and follows normal borrowing rules
744                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                // SAFETY: `prop` is owned by `Self` and follows normal borrowing rules
753                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        // SAFETY: `head` and `tail` must be valid to dereference within this function call
766        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                // SAFETY: The contract of `new` requires `tail` be valid to dereference
786                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            // Attempt to resume dropping if a destructor panics
805            // SAFETY: We're dropping the value through our exclusive reference
806            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        // SAFETY: The value referenced by this guard must be getting dropped
818        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                // SAFETY: We're dropping the value through our exclusive reference
824                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            // SAFETY: We're dropping the value through our exclusive reference
848            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    /**
864    The result of calling [`Props::dedup`].
865
866    Properties are de-duplicated by taking the first value for a given key.
867
868    Deduplication may allocate internally.
869    */
870    #[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            // SAFETY: `Dedup<P>` and `P` have the same ABI
876            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            // A filter that checks for duplicate keys, avoiding allocating if possible.
886            //
887            // For small numbers of keys, it's more efficient to simply brute-force compare them
888            // than it is to hash or binary search. In these cases we also avoid allocating for
889            // the filter.
890            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            // Optimization for props that are already unique
1013            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            // Ignore any break from this iteration
1020            // We need to iterate twice here because we need to maintain a reference
1021            // to keys to check them for duplicates before passing them by-value to the `for_each` fn
1022            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            // NOTE: The size here may be larger than the actual number of properties yielded
1045            // after deduplication. `size` isn't required to be exact, just not too small.
1046            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/**
1553The result of calling [`Props::as_map`].
1554
1555This type implements serialization traits, serializing properties as a map of key-value pairs.
1556*/
1557#[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        // SAFETY: `AsMap<P>` and `P` have the same ABI
1563        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
1689/**
1690An object-safe [`Props`].
1691
1692A `dyn ErasedProps` can be treated as `impl Props`.
1693*/
1694pub 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}