ptr_union/
lib.rs

1//! Pointer union types the size of a pointer
2//! by storing the tag in the alignment bits.
3
4#![warn(missing_docs, missing_debug_implementations)]
5#![no_std]
6
7use {
8    core::{
9        fmt,
10        hash::{self, Hash},
11        hint::unreachable_unchecked,
12        marker::PhantomData,
13        mem::ManuallyDrop,
14        ops::Deref,
15        ptr,
16    },
17    erasable::{ErasablePtr, ErasedPtr},
18};
19
20const MASK_2: usize = 0b0001;
21const MASK_4: usize = 0b0011;
22const MASK_8: usize = 0b0111;
23const MASK_16: usize = 0b1111;
24const TAG_A: usize = 0b0000;
25const TAG_B: usize = 0b0001;
26const TAG_C: usize = 0b0010;
27const TAG_D: usize = 0b0011;
28const TAG_E: usize = 0b0100;
29const TAG_F: usize = 0b0101;
30const TAG_G: usize = 0b0110;
31const TAG_H: usize = 0b0111;
32const TAG_I: usize = 0b1000;
33const TAG_J: usize = 0b1001;
34const TAG_K: usize = 0b1010;
35const TAG_L: usize = 0b1011;
36const TAG_M: usize = 0b1100;
37const TAG_N: usize = 0b1101;
38const TAG_O: usize = 0b1110;
39const TAG_P: usize = 0b1111;
40
41fn ptr_addr<T>(this: *mut T) -> usize {
42    #[cfg(not(has_strict_provenance))]
43    {
44        this as usize
45    }
46    #[cfg(has_strict_provenance)]
47    {
48        this.addr()
49    }
50}
51
52#[cfg(not(has_strict_provenance))]
53fn ptr_with_addr<T>(this: *mut T, addr: usize) -> *mut T {
54    // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
55    //
56    // In the mean-time, this operation is defined to be "as if" it was
57    // a wrapping_offset, so we can emulate it as such. This should properly
58    // restore pointer provenance even under today's compiler.
59    let this_addr = ptr_addr(this) as isize;
60    let dest_addr = addr as isize;
61    let offset = dest_addr.wrapping_sub(this_addr);
62
63    // This is the canonical desugarring of this operation
64    this.cast::<u8>().wrapping_offset(offset).cast::<T>()
65}
66
67fn ptr_map_addr<T>(this: *mut T, f: impl FnOnce(usize) -> usize) -> *mut T {
68    #[cfg(not(has_strict_provenance))]
69    {
70        ptr_with_addr(this, f(ptr_addr(this)))
71    }
72    #[cfg(has_strict_provenance)]
73    {
74        this.map_addr(f)
75    }
76}
77
78fn ptr_tag<T>(this: *mut T, tag: usize) -> *mut T {
79    ptr_map_addr(this, |addr| addr | tag)
80}
81
82fn ptr_mask<T>(this: *mut T, mask: usize) -> *mut T {
83    ptr_map_addr(this, |addr| addr & mask)
84}
85
86#[inline(always)]
87fn check_tag(ptr: ErasedPtr, mask: usize, tag: usize) -> bool {
88    debug_assert_eq!(tag & mask, tag);
89    ptr_addr(ptr_mask(ptr.as_ptr(), mask)) == tag
90}
91
92#[inline(always)]
93fn set_tag(ptr: ErasedPtr, mask: usize, tag: usize) -> ErasedPtr {
94    debug_assert_eq!(tag & mask, tag);
95    debug_assert!(check_tag(ptr, mask, 0));
96    unsafe { ErasedPtr::new_unchecked(ptr_tag(ptr.as_ptr(), tag)) }
97}
98
99#[inline(always)]
100fn unset_tag(ptr: ErasedPtr, mask: usize, tag: usize) -> ErasedPtr {
101    debug_assert_eq!(tag & mask, tag);
102    debug_assert!(check_tag(ptr, mask, tag));
103    unsafe { ErasedPtr::new_unchecked(ptr_mask(ptr.as_ptr(), !mask)) }
104}
105
106#[inline(always)]
107fn unset_any_tag(ptr: ErasedPtr, mask: usize) -> ErasedPtr {
108    unsafe { ErasedPtr::new_unchecked(ptr_mask(ptr.as_ptr(), !mask)) }
109}
110
111#[cfg(has_never)]
112pub type NeverPtr = !;
113#[cfg(not(has_never))]
114use never_ptr::NeverPtr;
115#[cfg(not(has_never))]
116mod never_ptr {
117    use super::*;
118    #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
119    pub enum NeverPtr {}
120    unsafe impl ErasablePtr for NeverPtr {
121        #[inline]
122        fn erase(this: Self) -> ErasedPtr {
123            match this {}
124        }
125        #[inline]
126        unsafe fn unerase(_this: ErasedPtr) -> Self {
127            unreachable!()
128        }
129    }
130}
131
132/// A pointer union of two pointer types.
133///
134/// This is a tagged union of two pointer types such as `Box`, `Arc`, or `&`
135/// that is only as big as a single pointer. This is accomplished by storing
136/// the tag in the alignment bits of the pointer.
137///
138/// As such, the pointer must be aligned to at least `u16` (`align(2)`).
139/// This is enforced through the use of [`Builder2`].
140pub struct Union2<A: ErasablePtr, B: ErasablePtr> {
141    raw: ErasedPtr,
142    phantom: PhantomData<Enum2<A, B>>,
143}
144
145/// A pointer union of four pointer types.
146///
147/// This is a tagged union of four pointer types such as `Box`, `Arc`, or `&`
148/// that is only as big as a single pointer. This is accomplished by storing
149/// the tag in the alignment bits of the pointer.
150///
151/// As such, the pointer must be aligned to at least `u32` (`align(4)`).
152/// This is enforced through the use of [`Builder4`].
153///
154/// The fourth pointer type may be omitted to create a three pointer union.
155/// The default type, `NeverPtr`, will be an alias for `!` once it is stable.
156/// This will not be considered a breaking change.
157pub struct Union4<A: ErasablePtr, B: ErasablePtr, C: ErasablePtr, D: ErasablePtr = NeverPtr> {
158    raw: ErasedPtr,
159    phantom: PhantomData<Enum4<A, B, C, D>>,
160}
161
162/// A pointer union of eight pointer types.
163///
164/// This is a tagged union of eight pointer types such as `Box`, `Arc`, or `&`
165/// that is only as big as a single pointer. This is accomplished by storing
166/// the tag in the alignment bits of the pointer.
167///
168/// As such, the pointer must be aligned to at least `u64` (`align(8)`).
169/// This is enforced through the use of [`Builder8`].
170///
171/// Pointers beyond the fifth may be ommitted to create smaller unions.
172/// The default type, `NeverPtr`, will be an alias for `!` once it is stable.
173/// This will not be considered a breaking change.
174pub struct Union8<
175    A: ErasablePtr,
176    B: ErasablePtr,
177    C: ErasablePtr,
178    D: ErasablePtr,
179    E: ErasablePtr,
180    F: ErasablePtr = NeverPtr,
181    G: ErasablePtr = NeverPtr,
182    H: ErasablePtr = NeverPtr,
183> {
184    raw: ErasedPtr,
185    #[allow(clippy::type_complexity)]
186    phantom: PhantomData<Enum8<A, B, C, D, E, F, G, H>>,
187}
188
189/// A pointer union of up to sixteen pointer types.
190///
191/// This is a tagged union of sixteen pointer types such as `Box`, `Arc`, or `&`
192/// that is only as big as a single pointer. This is accomplished by storing
193/// the tag in the alignment bits of the pointer.
194///
195/// As such, the pointer must be aligned to at least `align(16)`.
196/// This is enforced through the use of [`Builder16`].
197///
198/// Pointers beyond the ninth may be ommitted to create smaller unions.
199/// The default type, `NeverPtr`, will be an alias for `!` once it is stable.
200/// This will not be considered a breaking change.
201pub struct Union16<
202    A: ErasablePtr,
203    B: ErasablePtr,
204    C: ErasablePtr,
205    D: ErasablePtr,
206    E: ErasablePtr,
207    F: ErasablePtr,
208    G: ErasablePtr,
209    H: ErasablePtr,
210    I: ErasablePtr,
211    J: ErasablePtr = NeverPtr,
212    K: ErasablePtr = NeverPtr,
213    L: ErasablePtr = NeverPtr,
214    M: ErasablePtr = NeverPtr,
215    N: ErasablePtr = NeverPtr,
216    O: ErasablePtr = NeverPtr,
217    P: ErasablePtr = NeverPtr,
218> {
219    raw: ErasedPtr,
220    #[allow(clippy::type_complexity)]
221    phantom: PhantomData<Enum16<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P>>,
222}
223
224/// An unpacked version of [`Union2`].
225#[allow(missing_docs)]
226#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
227pub enum Enum2<A, B> {
228    A(A),
229    B(B),
230}
231
232/// An unpacked version of [`Union4`].
233#[allow(missing_docs)]
234#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
235pub enum Enum4<A, B, C, D> {
236    A(A),
237    B(B),
238    C(C),
239    D(D),
240}
241
242/// An unpacked version of [`Union4`].
243#[allow(missing_docs)]
244#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
245pub enum Enum8<A, B, C, D, E, F, G, H> {
246    A(A),
247    B(B),
248    C(C),
249    D(D),
250    E(E),
251    F(F),
252    G(G),
253    H(H),
254}
255
256/// An unpacked version of [`Union8`].
257#[allow(missing_docs)]
258#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
259pub enum Enum16<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P> {
260    A(A),
261    B(B),
262    C(C),
263    D(D),
264    E(E),
265    F(F),
266    G(G),
267    H(H),
268    I(I),
269    J(J),
270    K(K),
271    L(L),
272    M(M),
273    N(N),
274    O(O),
275    P(P),
276}
277
278/// A builder for [`Union2`].
279///
280/// An instance of this builder means that `Union2` parameterized
281/// with the same type arguments are safe to construct.
282pub struct Builder2<A, B> {
283    phantom: PhantomData<Enum2<A, B>>,
284}
285
286/// A builder for [`Union4`].
287///
288/// An instance of this builder means that `Union4` parameterized
289/// with the same type arguments are safe to construct.
290pub struct Builder4<A, B, C, D = NeverPtr> {
291    phantom: PhantomData<Enum4<A, B, C, D>>,
292}
293
294/// A builder for [`Union8`].
295///
296/// An instance of this builder means that `Union8` parameterized
297/// with the same type arguments are safe to construct.
298pub struct Builder8<A, B, C, D, E, F = NeverPtr, G = NeverPtr, H = NeverPtr> {
299    #[allow(clippy::type_complexity)]
300    phantom: PhantomData<Enum8<A, B, C, D, E, F, G, H>>,
301}
302
303/// A builder for [`Union16`].
304///
305/// An instance of this builder means that `Union16` parameterized
306/// with the same type arguments are safe to construct.
307pub struct Builder16<
308    A,
309    B,
310    C,
311    D,
312    E,
313    F = NeverPtr,
314    G = NeverPtr,
315    H = NeverPtr,
316    I = NeverPtr,
317    J = NeverPtr,
318    K = NeverPtr,
319    L = NeverPtr,
320    M = NeverPtr,
321    N = NeverPtr,
322    O = NeverPtr,
323    P = NeverPtr,
324> {
325    #[allow(clippy::type_complexity)]
326    phantom: PhantomData<Enum16<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P>>,
327}
328
329macro_rules! impl_builder {
330    ($UnionName:ident $Union:ty, $BuilderName:ident $Builder:ty: $mask:ident $([$a:ident $A:ident])*) => {
331        impl<$($A),*> $Builder {
332            /// Assert that creating pointer unions of these types is safe.
333            ///
334            /// # Safety
335            ///
336            /// The pointer types must be [erasable](`ErasablePtr`), and their
337            /// alignment must meet the requirements of the target union type.
338            pub const unsafe fn new_unchecked() -> Self {
339                Self { phantom: PhantomData }
340            }
341        }
342
343        impl<$($A: ErasablePtr),*> $Builder {
344            paste::paste! {
345                $(
346                    /// Construct a union at this variant.
347                    pub fn $a(self, this: $A) -> $Union {
348                        $UnionName {
349                            raw: set_tag($A::erase(this), $mask, [<TAG_ $A>]),
350                            phantom: PhantomData,
351                        }
352                    }
353                )*
354            }
355        }
356
357        impl<$($A),*> Copy for $Builder {}
358        impl<$($A),*> Clone for $Builder {
359            fn clone(&self) -> Self {
360                *self
361            }
362        }
363    };
364}
365
366macro_rules! impl_union {
367    ($Union:ident, $Enum:ident, $Builder:ident: $mask:ident $([$a:ident $A:ident])*) => {
368        impl_builder!($Union $Union<$($A),*>, $Builder $Builder<$($A),*>: $mask $([$a $A])*);
369
370        impl<$($A: ErasablePtr),*> $Union<$($A),*> {
371            paste::paste! {
372                $(
373                    /// Construct a varaint of this union with a dynamic alignment check.
374                    pub fn [<new_ $a>]($a: $A) -> Result<Self, $A> {
375                        let $a = $A::erase($a);
376                        if check_tag($a, $mask, 0) {
377                            Ok($Union {
378                                raw: set_tag($a, $mask, [<TAG_ $A>]),
379                                phantom: PhantomData,
380                            })
381                        } else {
382                            Err(unsafe { $A::unerase($a) })
383                        }
384                    }
385
386                    /// Check if the union is this variant.
387                    pub fn [<is_ $a>](&self) -> bool {
388                        check_tag(self.raw, $mask, [<TAG_ $A>])
389                    }
390
391                    /// Extract this variant from the union.
392                    ///
393                    /// Returns the union on error.
394                    pub fn [<into_ $a>](self) -> Result<$A, Self> {
395                        if self.[<is_ $a>]() {
396                            let this = ManuallyDrop::new(self);
397                            unsafe { Ok($A::unerase(unset_tag(this.raw, $mask, [<TAG_ $A>]))) }
398                        } else {
399                            Err(self)
400                        }
401                    }
402
403                    /// Run a closure with this variant.
404                    pub fn [<with_ $a>]<R>(&self, f: impl FnOnce(&$A) -> R) -> Option<R> {
405                        if self.[<is_ $a>]() {
406                            unsafe {
407                                let this = ManuallyDrop::new($A::unerase(unset_tag(self.raw, $mask, [<TAG_ $A>])));
408                                Some(f(&this))
409                            }
410                        } else {
411                            None
412                        }
413                    }
414
415                    /// Get a reference to this variant's target.
416                    pub fn $a(&self) -> Option<&$A::Target>
417                    where $A: Deref
418                    {
419                        self.[<with_ $a>](|this| unsafe { erase_lt(&**this) })
420                    }
421
422                    /// Clone this variant out of the union.
423                    pub fn [<clone_ $a>](&self) -> Option<$A>
424                    where $A: Clone
425                    {
426                        self.[<with_ $a>](|this| this.clone())
427                    }
428
429                    /// Copy this variant out of the union.
430                    pub fn [<copy_ $a>](&self) -> Option<$A>
431                    where $A: Copy
432                    {
433                        self.[<with_ $a>](|this| *this)
434                    }
435                )*
436
437                /// Unpack this union into an enum.
438                pub fn unpack(self) -> $Enum<$($A),*> {
439                    Err(self)
440                        $(.or_else(|this| this.[<into_ $a>]().map($Enum::$A)))*
441                        .unwrap_or_else(|_| unsafe { unreachable_unchecked() })
442                }
443            }
444
445            /// Check if two unions are the same variant and point to
446            /// the same value (not that the values compare as equal).
447            pub fn ptr_eq(&self, other: &Self) -> bool {
448                self.raw == other.raw
449            }
450
451            /// Dereference the current pointer.
452            pub fn as_deref<'a>(
453                &'a self,
454                builder: $Builder<$(&'a $A::Target),*>
455            ) -> $Union<$(&'a $A::Target),*>
456            where
457                $($A: Deref,)*
458                $(&'a $A::Target: ErasablePtr,)*
459            {
460                $(if let Some(this) = self.$a() {
461                    builder.$a(this)
462                } else)* {
463                    unsafe { unreachable_unchecked() }
464                }
465            }
466
467            /// Dereference the current pointer.
468            ///
469            /// # Safety
470            ///
471            /// The reference produced must be properly aligned. Note that only
472            /// the actually produced reference is restricted, not the result
473            /// of dereferencing any of the other types in this union.
474            pub unsafe fn as_deref_unchecked<'a>(&'a self) -> $Union<$(&'a $A::Target),*>
475            where
476                $($A: Deref,)*
477                $(&'a $A::Target: ErasablePtr,)*
478            {
479                self.as_deref($Builder::new_unchecked())
480            }
481
482            /// Get the raw type-erased untagged pointer to the payload.
483            pub fn as_untagged_ptr(&self) -> ErasedPtr {
484                unset_any_tag(self.raw, $mask)
485            }
486
487            paste::paste! {
488                /// Dereference the current pointer.
489                ///
490                /// Performs a dynamic alignment check on the dereferenced pointer.
491                pub fn try_deref<'a>(&'a self) -> Option<$Union<$(&'a $A::Target),*>>
492                where
493                    $($A: Deref,)*
494                    $(&'a $A::Target: ErasablePtr,)*
495                {
496                    $(if let Some(this) = self.$a() {
497                        $Union::[<new_ $a>](this).ok()
498                    } else)* {
499                        None
500                    }
501                }
502            }
503        }
504
505        impl<$($A: ErasablePtr),*> $Enum<$($A),*> {
506            /// Pack this loose enum into a pointer union.
507            pub fn pack(self, builder: $Builder<$($A),*>) -> $Union<$($A),*> {
508                match self {
509                    $($Enum::$A(this) => builder.$a(this),)*
510                }
511            }
512
513            paste::paste! {
514                /// Pack this loose enum into a pointer union.
515                pub fn try_pack(self) -> Result<$Union<$($A),*>, Self> {
516                    match self {
517                        $($Enum::$A(this) => $Union::[<new_ $a>](this).map_err(Self::$A),)*
518                    }
519                }
520            }
521
522            /// Pack this loose enum into a pointer union.
523            ///
524            /// # Safety
525            ///
526            /// The pointer packed must be properly aligned. Note that only
527            /// the actually packed pointer is restricted, not any other
528            /// pointer type involved in this definition.
529            pub unsafe fn pack_unchecked(self) -> $Union<$($A),*> {
530                self.pack($Builder::new_unchecked())
531            }
532        }
533
534        unsafe impl<$($A: ErasablePtr),*> ErasablePtr for $Union<$($A),*> {
535            fn erase(this: Self) -> ErasedPtr {
536                ManuallyDrop::new(this).raw
537            }
538
539            unsafe fn unerase(this: ErasedPtr) -> Self {
540                Self {
541                    raw: this,
542                    phantom: PhantomData,
543                }
544            }
545        }
546
547        impl<$($A: ErasablePtr),*> Drop for $Union<$($A),*> {
548            fn drop(&mut self) {
549                unsafe { drop(ptr::read(self).unpack()) }
550            }
551        }
552
553        impl<$($A: ErasablePtr),*> fmt::Debug for $Union<$($A),*>
554        where $($A: fmt::Debug),*
555        {
556            paste::paste! {
557                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
558                    None
559                        $(.or_else(|| self.[<with_ $a>](|this| f
560                            .debug_tuple(stringify!($A))
561                            .field(this)
562                            .finish()
563                        )))*
564                        .unwrap_or_else(|| unsafe { unreachable_unchecked() })
565                }
566            }
567        }
568
569        impl<$($A: ErasablePtr),*> Clone for $Union<$($A),*>
570        where $($A: Clone),*
571        {
572            paste::paste! {
573                fn clone(&self) -> Self {
574                    #[cold]
575                    #[inline(never)]
576                    fn clone_error<A>() -> ! {
577                        panic!("Tried to clone {} in a {}, but the cloned pointer wasn't sufficiently aligned", core::any::type_name::<A>(), stringify!($Union))
578                    }
579
580                    None
581                        $(.or_else(|| self.[<clone_ $a>]().map(|this| Self::[<new_ $a>](this).unwrap_or_else(|_| clone_error::<$A>()))))*
582                        .unwrap_or_else(|| unsafe { unreachable_unchecked() })
583                }
584            }
585        }
586
587        impl<$($A: ErasablePtr,)*> Eq for $Union<$($A),*> where $($A: Eq,)* {}
588        impl<$($A: ErasablePtr),*> PartialEq for $Union<$($A),*>
589        where $($A: PartialEq),*
590        {
591            paste::paste! {
592                fn eq(&self, other: &Self) -> bool {
593                    None
594                        $(.or_else(|| self.[<with_ $a>](|this|
595                            other.[<with_ $a>](|that|
596                                this == that
597                            ).unwrap_or(false)
598                        )))*
599                        .unwrap_or(false)
600                }
601            }
602        }
603
604        impl<$($A: ErasablePtr,)*> Hash for $Union<$($A),*>
605        where $($A: Hash),*
606        {
607            paste::paste! {
608                fn hash<Hasher>(&self, state: &mut Hasher)
609                where Hasher: hash::Hasher
610                {
611                    None
612                        $(.or_else(|| self.[<with_ $a>](|this| this.hash(state))))*
613                        .unwrap_or_else(|| unsafe { unreachable_unchecked() })
614                }
615            }
616        }
617
618        unsafe impl<$($A: ErasablePtr,)*> Send for $Union<$($A),*> where $($A: Send),* {}
619        unsafe impl<$($A: ErasablePtr,)*> Sync for $Union<$($A),*> where $($A: Sync),* {}
620    };
621}
622
623impl_union!(Union2, Enum2, Builder2: MASK_2 [a A] [b B]);
624impl_union!(Union4, Enum4, Builder4: MASK_4 [a A] [b B] [c C] [d D]);
625impl_union!(Union8, Enum8, Builder8: MASK_8 [a A] [b B] [c C] [d D] [e E] [f F] [g G] [h H]);
626impl_union!(Union16, Enum16, Builder16: MASK_16 [a A] [b B] [c C] [d D] [e E] [f F] [g G] [h H] [i I] [j J] [k K] [l L] [m M] [n N] [o O] [p P]);
627
628impl<A, B> fmt::Debug for Builder2<A, B> {
629    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
630        f.debug_tuple("Builder2")
631            .field(&format_args!(
632                "Union2<{}, {}>",
633                core::any::type_name::<A>(),
634                core::any::type_name::<B>(),
635            ))
636            .finish()
637    }
638}
639
640impl<A, B, C, D> fmt::Debug for Builder4<A, B, C, D> {
641    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
642        f.debug_tuple("Builder4")
643            .field(&format_args!(
644                "Union4<{}, {}, {}, {}>",
645                core::any::type_name::<A>(),
646                core::any::type_name::<B>(),
647                core::any::type_name::<C>(),
648                core::any::type_name::<D>(),
649            ))
650            .finish()
651    }
652}
653
654impl<A, B, C, D, E, F, G, H> fmt::Debug for Builder8<A, B, C, D, E, F, G, H> {
655    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
656        f.debug_tuple("Builder8")
657            .field(&format_args!(
658                "Union8<{}, {}, {}, {}, {}, {}, {}, {},>",
659                core::any::type_name::<A>(),
660                core::any::type_name::<B>(),
661                core::any::type_name::<C>(),
662                core::any::type_name::<D>(),
663                core::any::type_name::<E>(),
664                core::any::type_name::<F>(),
665                core::any::type_name::<G>(),
666                core::any::type_name::<H>(),
667            ))
668            .finish()
669    }
670}
671
672impl<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P> fmt::Debug
673    for Builder16<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P>
674{
675    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
676        f.debug_tuple("Builder16")
677            .field(&format_args!(
678                "Union16<{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}>",
679                core::any::type_name::<A>(),
680                core::any::type_name::<B>(),
681                core::any::type_name::<C>(),
682                core::any::type_name::<D>(),
683                core::any::type_name::<E>(),
684                core::any::type_name::<F>(),
685                core::any::type_name::<G>(),
686                core::any::type_name::<H>(),
687                core::any::type_name::<I>(),
688                core::any::type_name::<J>(),
689                core::any::type_name::<K>(),
690                core::any::type_name::<L>(),
691                core::any::type_name::<M>(),
692                core::any::type_name::<N>(),
693                core::any::type_name::<O>(),
694                core::any::type_name::<P>(),
695            ))
696            .finish()
697    }
698}
699
700#[allow(clippy::needless_lifetimes)]
701unsafe fn erase_lt<'a, 'b, T: ?Sized>(r: &'a T) -> &'b T {
702    &*(r as *const T)
703}