Skip to main content

nblf_queue/core/
packed.rs

1use core::{
2    marker::PhantomData,
3    num::{NonZeroI8, NonZeroI16, NonZeroI32, NonZeroU8, NonZeroU16, NonZeroU32},
4    ptr::NonNull,
5};
6
7// TODO add safety comments in branch `allow_empty`
8
9/// This trait is used to store the value in a `Slot`.
10/// The slot may truncate the value to `MIN_BIT_WIDTH` bits.
11/// Types implementing `AsPackedValue` may be stored in slots with `MAX_CARGO_BIT_WIDTH` >= `MIN_BIT_WIDTH`. This will be checked at compile time.
12/// `MIN_BIT_WIDTH` cannot be larger than 64
13/// # SAFETY
14/// - both `decode` and `encode` must be atomic and non-blocking
15/// - `decode` must only be called on a value returned by `encode`
16/// - the encoded value must be reconstructable fully from the lower `MIN_BIT_WIDTH` bits
17pub unsafe trait AsPackedValue: Sized {
18    /// The minimal bit width from which this type may be reconstructed.
19    const MIN_BIT_WIDTH: usize;
20    /// Truncates `Self` to the lower `MIN_BIT_WIDTH` bits.
21    /// The caller is responsible for reconstructing this value usign `decode`
22    fn encode(zelf: Self) -> TruncatedU64<Self>;
23
24    /// Reconstructs `Self` from the lower `MIN_BIT_WIDTH` bits returned by `encode`.
25    /// # SAFETY
26    /// The caller must ensure that the passed value is a valid value returned by `encode`
27    unsafe fn decode(raw: TruncatedU64<Self>) -> Self;
28
29    /// Validates wether self is actually safe to pack into Self::MIN_BIT_WIDTH bits at runtime.
30    fn is_rt_safe() -> bool {
31        true
32    }
33}
34
35/// An U64, with the upper N bits set to 0.
36#[repr(transparent)]
37#[derive(Debug, PartialEq, Eq)]
38pub struct TruncatedU64<T> {
39    v: u64,
40    _phantom: PhantomData<T>,
41}
42
43impl<T> Clone for TruncatedU64<T> {
44    fn clone(&self) -> Self {
45        *self
46    }
47}
48
49impl<T> Copy for TruncatedU64<T> {}
50
51impl<T> TruncatedU64<T> {
52    /// Returns the raw u64 stored in this type
53    pub fn read(&self) -> u64 {
54        self.v
55    }
56}
57
58impl<T: AsPackedValue> TruncatedU64<T> {
59    /// Contructs a new `TruncatedU64` from an u64.
60    /// This method will zero the upper 64 - `T::MIN_BIT_WIDTH` bits.
61    pub fn new(mut value: u64) -> Self {
62        // TODO make this a const created mask
63        if T::MIN_BIT_WIDTH < 64 {
64            value = unpack!((value): T::MIN_BIT_WIDTH).1;
65        }
66        Self {
67            v: value,
68            _phantom: PhantomData,
69        }
70    }
71}
72
73macro_rules! atomic_encode_primitive {
74    ($type:ty) => {
75        // Safety:
76        // primitve numeric types with size <= WIDTH can be typecast safely
77        unsafe impl $crate::core::AsPackedValue for $type {
78            const MIN_BIT_WIDTH: usize = size_of::<$type>() * 8;
79
80            fn encode(zelf: Self) -> $crate::core::TruncatedU64<Self> {
81                $crate::core::TruncatedU64::new(zelf as u64)
82            }
83
84            unsafe fn decode(raw: $crate::core::TruncatedU64<Self>) -> Self {
85                (raw.read()) as Self
86            }
87        }
88    };
89}
90
91macro_rules! atomic_encode_non_zero_primitive {
92    ($type:ty, $raw:ty) => {
93        // Safety:
94        // primitve numeric types with size <= WIDTH can be typecast safely
95        unsafe impl $crate::core::AsPackedValue for $type {
96            const MIN_BIT_WIDTH: usize = size_of::<$type>() * 8;
97
98            fn encode(zelf: Self) -> $crate::core::TruncatedU64<Self> {
99                $crate::core::TruncatedU64::new(zelf.get() as u64)
100            }
101
102            unsafe fn decode(raw: $crate::core::TruncatedU64<Self>) -> Self {
103                Self::new(raw.read() as $raw)
104                    .expect("trying to construct a NonZero from a zero value")
105            }
106        }
107    };
108}
109
110atomic_encode_primitive!(u32);
111atomic_encode_primitive!(u16);
112atomic_encode_primitive!(u8);
113atomic_encode_primitive!(i32);
114atomic_encode_primitive!(i16);
115atomic_encode_primitive!(i8);
116
117atomic_encode_non_zero_primitive!(NonZeroU32, u32);
118atomic_encode_non_zero_primitive!(NonZeroU16, u16);
119atomic_encode_non_zero_primitive!(NonZeroU8, u8);
120atomic_encode_non_zero_primitive!(NonZeroI32, i32);
121atomic_encode_non_zero_primitive!(NonZeroI16, i16);
122atomic_encode_non_zero_primitive!(NonZeroI8, i8);
123
124// Safety:
125// () has no size and data
126unsafe impl AsPackedValue for () {
127    const MIN_BIT_WIDTH: usize = 0;
128
129    fn encode(_zelf: Self) -> TruncatedU64<Self> {
130        TruncatedU64::new(0)
131    }
132
133    // Safety:
134    // nothing to do
135    unsafe fn decode(_raw: TruncatedU64<Self>) -> Self {}
136}
137
138// TODO for targets with ptr width <=48 bits, we could also atomic_encode_primitive ptrs + usize
139
140// Some x86_64 based hardware has support for level 5 pagetables. These implementations are not safe on this hardware
141#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
142mod x86_64 {
143    use super::*;
144
145    fn assert_ptr_safety() {
146        let dummy = 42;
147        let raw = &dummy as *const i32;
148        let addr = raw as u64;
149        let top_16 = addr >> 48;
150        let bit_47 = (addr >> 47) & 1;
151
152        assert!(
153            (bit_47 == 0 && top_16 == 0) || (bit_47 == 1 && top_16 == 0xFFFF),
154            "Pointer {:p} exceeds 48-bit address space! AsPackedValue is unsafe here. Consider using a PooledQueue or a Tagged128 Slot.",
155            raw
156        );
157    }
158
159    // Safety:
160    // This implementation assumes that pointers may be reconstructed from 48-bits using sign extenion.
161    //
162    // WARNING: This implementation is unsound on systems using more than 48 bits
163    unsafe impl<T> AsPackedValue for *const T
164    where
165        T: Sized,
166    {
167        const MIN_BIT_WIDTH: usize = 48;
168
169        fn encode(zelf: Self) -> TruncatedU64<Self> {
170            TruncatedU64::new(zelf as u64)
171        }
172
173        unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
174            crate::utils::sign_extend(raw.read()) as *const T
175        }
176
177        fn is_rt_safe() -> bool {
178            assert_ptr_safety();
179            true
180        }
181    }
182
183    // Safety:
184    // This implementation assumes that pointers may be reconstructed from 48-bits using sign extenion.
185    //
186    // WARNING: This implementation is unsound on systems using more than 48 bits
187    unsafe impl<T> AsPackedValue for *mut T
188    where
189        T: Sized,
190    {
191        const MIN_BIT_WIDTH: usize = 48;
192
193        fn encode(zelf: Self) -> TruncatedU64<Self> {
194            TruncatedU64::new(zelf as u64)
195        }
196
197        unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
198            crate::utils::sign_extend(raw.read()) as *mut T
199        }
200
201        fn is_rt_safe() -> bool {
202            assert_ptr_safety();
203            true
204        }
205    }
206
207    // Safety:
208    // This implementation assumes that pointers may be reconstructed from 48-bits using sign extenion.
209    //
210    // WARNING: This implementation is unsound on systems using more than 48 bits
211    unsafe impl<T> AsPackedValue for NonNull<T>
212    where
213        T: Sized,
214    {
215        const MIN_BIT_WIDTH: usize = 48;
216
217        fn encode(zelf: Self) -> TruncatedU64<Self> {
218            TruncatedU64::new(zelf.as_ptr() as u64)
219        }
220
221        unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
222            Self::new(crate::utils::sign_extend(raw.read()) as *mut T)
223                .expect("tried to recosntruct a NonNull from 0")
224        }
225
226        fn is_rt_safe() -> bool {
227            assert_ptr_safety();
228            true
229        }
230    }
231
232    // Safety:
233    // This implementation assumes that pointers may be reconstructed from 48-bits using sign extenion.
234    //
235    // WARNING: This implementation is unsound on systems using more than 48 bits
236    unsafe impl<T> AsPackedValue for &'static T {
237        const MIN_BIT_WIDTH: usize = 48;
238
239        fn encode(zelf: Self) -> TruncatedU64<Self> {
240            TruncatedU64::new(zelf as *const T as u64)
241        }
242
243        unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
244            // Safety:
245            // The caller must ensure that this is called on a value created by `encode` and the reference is still valid
246            unsafe { &*(crate::utils::sign_extend(raw.read()) as *const T) }
247        }
248
249        fn is_rt_safe() -> bool {
250            assert_ptr_safety();
251            true
252        }
253    }
254
255    // Safety:
256    // This implementation assumes that pointers may be reconstructed from 48-bits using sign extenion.
257    //
258    // WARNING: This implementation is unsound on systems using more than 48 bits
259    unsafe impl<T> AsPackedValue for &'static mut T {
260        const MIN_BIT_WIDTH: usize = 48;
261
262        fn encode(zelf: Self) -> TruncatedU64<Self> {
263            TruncatedU64::new(zelf as *mut T as u64)
264        }
265
266        unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
267            // Safety:
268            // The caller must ensure that this is called only once on a value created by `encode` and the reference is still valid
269            unsafe { &mut *(crate::utils::sign_extend(raw.read()) as *mut T) }
270        }
271
272        fn is_rt_safe() -> bool {
273            assert_ptr_safety();
274            true
275        }
276    }
277
278    #[cfg(any(feature = "alloc", test))]
279    mod alloc_ {
280        use alloc::{
281            boxed::Box,
282            rc::{self, Rc},
283            sync::{self, Arc},
284        };
285
286        use super::*;
287
288        // Safety:
289        // This implementation assumes that pointers may be reconstructed from 48-bits using sign extenion.
290        //
291        // WARNING: This implementation is unsound on systems using more than 48 bits
292        unsafe impl<T> AsPackedValue for Box<T> {
293            const MIN_BIT_WIDTH: usize = 48;
294
295            fn encode(zelf: Self) -> TruncatedU64<Self> {
296                let raw = Box::into_raw(zelf);
297                TruncatedU64::new(raw as u64)
298            }
299
300            unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
301                // Safety:
302                // The caller must ensure that this is called only once on a value created by `encode` and the underlying allocation is still valid
303                unsafe { Box::from_raw(crate::utils::sign_extend(raw.read()) as *mut T) }
304            }
305
306            fn is_rt_safe() -> bool {
307                assert_ptr_safety();
308                true
309            }
310        }
311
312        // Safety:
313        // This implementation assumes that pointers may be reconstructed from 48-bits using sign extenion.
314        //
315        // WARNING: This implementation is unsound on systems using more than 48 bits
316        unsafe impl<T> AsPackedValue for Rc<T> {
317            const MIN_BIT_WIDTH: usize = 48;
318
319            fn encode(zelf: Self) -> TruncatedU64<Self> {
320                let raw = Rc::into_raw(zelf);
321                TruncatedU64::new(raw as u64)
322            }
323
324            unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
325                // Safety:
326                // The caller must ensure that this is called only once on a value created by `encode` and the underlying allocation is still valid
327                unsafe { Rc::from_raw(crate::utils::sign_extend(raw.read()) as *mut T) }
328            }
329
330            fn is_rt_safe() -> bool {
331                assert_ptr_safety();
332                true
333            }
334        }
335
336        // Safety:
337        // This implementation assumes that pointers may be reconstructed from 48-bits using sign extenion.
338        //
339        // WARNING: This implementation is unsound on systems using more than 48 bits
340        unsafe impl<T> AsPackedValue for Arc<T> {
341            const MIN_BIT_WIDTH: usize = 48;
342
343            fn encode(zelf: Self) -> TruncatedU64<Self> {
344                let raw = Arc::into_raw(zelf);
345                TruncatedU64::new(raw as u64)
346            }
347
348            unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
349                // Safety:
350                // The caller must ensure that this is called only once on a value created by `encode` and the underlying allocation is still valid
351                unsafe { Arc::from_raw(crate::utils::sign_extend(raw.read()) as *mut T) }
352            }
353
354            fn is_rt_safe() -> bool {
355                assert_ptr_safety();
356                true
357            }
358        }
359
360        // Safety:
361        // This implementation assumes that pointers may be reconstructed from 48-bits using sign extenion.
362        //
363        // WARNING: This implementation is unsound on systems using more than 48 bits
364        unsafe impl<T> AsPackedValue for rc::Weak<T> {
365            const MIN_BIT_WIDTH: usize = 48;
366
367            fn encode(zelf: Self) -> TruncatedU64<Self> {
368                let raw = rc::Weak::into_raw(zelf);
369                TruncatedU64::new(raw as u64)
370            }
371
372            unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
373                // Safety:
374                // The caller must ensure that this is called only once on a value created by `encode` and the underlying allocation is still valid
375                unsafe { rc::Weak::from_raw(crate::utils::sign_extend(raw.read()) as *mut T) }
376            }
377
378            fn is_rt_safe() -> bool {
379                assert_ptr_safety();
380                true
381            }
382        }
383
384        // Safety:
385        // This implementation assumes that pointers may be reconstructed from 48-bits using sign extenion.
386        //
387        // WARNING: This implementation is unsound on systems using more than 48 bits
388        unsafe impl<T> AsPackedValue for sync::Weak<T> {
389            const MIN_BIT_WIDTH: usize = 48;
390
391            fn encode(zelf: Self) -> TruncatedU64<Self> {
392                let raw = sync::Weak::into_raw(zelf);
393                TruncatedU64::new(raw as u64)
394            }
395
396            unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
397                // Safety:
398                // The caller must ensure that this is called only once on a value created by `encode` and the underlying allocation is still valid
399                unsafe { sync::Weak::from_raw(crate::utils::sign_extend(raw.read()) as *mut T) }
400            }
401
402            fn is_rt_safe() -> bool {
403                assert_ptr_safety();
404                true
405            }
406        }
407    }
408}
409
410#[cfg(all(not(target_arch = "x86_64"), target_pointer_width = "64"))]
411mod full_bit64 {
412    use super::*;
413
414    // Safety:
415    // casting *const T from and to u64 is safe
416    unsafe impl<T> AsPackedValue for *const T
417    where
418        T: Sized,
419    {
420        const MIN_BIT_WIDTH: usize = 64;
421
422        fn encode(zelf: Self) -> TruncatedU64<Self> {
423            TruncatedU64::new(zelf as u64)
424        }
425
426        unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
427            raw.read() as *const T
428        }
429    }
430
431    // Safety:
432    // casting *const T from and to u64 is safe
433    unsafe impl<T> AsPackedValue for *mut T
434    where
435        T: Sized,
436    {
437        const MIN_BIT_WIDTH: usize = 64;
438
439        fn encode(zelf: Self) -> TruncatedU64<Self> {
440            TruncatedU64::new(zelf as u64)
441        }
442
443        unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
444            raw.read() as *mut T
445        }
446    }
447
448    // Safety:
449    // casting *const T from and to u64 is safe
450    // casting from u64 to NonNull<T> is safe, if that u64 was obtained from a NonNull<T>
451    unsafe impl<T> AsPackedValue for NonNull<T>
452    where
453        T: Sized,
454    {
455        const MIN_BIT_WIDTH: usize = 64;
456
457        fn encode(zelf: Self) -> TruncatedU64<Self> {
458            TruncatedU64::new(zelf.as_ptr() as u64)
459        }
460
461        unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
462            Self::new(raw.read() as *mut T).expect("tried to recosntruct a NonNull from 0")
463        }
464    }
465
466    // Safety:
467    // casting *const T from and to u64 is safe
468    unsafe impl<T> AsPackedValue for &'static T {
469        const MIN_BIT_WIDTH: usize = 64;
470
471        fn encode(zelf: Self) -> TruncatedU64<Self> {
472            TruncatedU64::new(zelf as *const T as u64)
473        }
474
475        unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
476            // Safety:
477            // The caller must ensure that the value was returned by `encode` and the reference is still valid
478            unsafe { &*(raw.read() as *const T) }
479        }
480    }
481
482    // Safety:
483    // casting *const T from and to u64 is safe
484    unsafe impl<T> AsPackedValue for &'static mut T {
485        const MIN_BIT_WIDTH: usize = 64;
486
487        fn encode(zelf: Self) -> TruncatedU64<Self> {
488            TruncatedU64::new(zelf as *mut T as u64)
489        }
490
491        unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
492            // Safety:
493            // The caller must ensure that this is called only once on a value returned by `encode` and the reference is still valid
494            unsafe { &mut *(raw.read() as *mut T) }
495        }
496    }
497
498    #[cfg(any(feature = "alloc", test))]
499    mod alloc_ {
500        use alloc::{
501            boxed::Box,
502            rc::{self, Rc},
503            sync::{self, Arc},
504        };
505
506        use super::*;
507
508        // Safety:
509        // casting *const T from and to u64 is safe
510        unsafe impl<T> AsPackedValue for Box<T> {
511            const MIN_BIT_WIDTH: usize = 64;
512
513            fn encode(zelf: Self) -> TruncatedU64<Self> {
514                TruncatedU64::new(Box::into_raw(zelf) as u64)
515            }
516
517            unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
518                // Safety:
519                // The caller must ensure that this is called only once on a value returned by `encode` and the allocation is still valid
520                unsafe { Box::from_raw(raw.read() as *mut T) }
521            }
522        }
523
524        // Safety:
525        // casting *const T from and to u64 is safe
526        unsafe impl<T> AsPackedValue for Rc<T> {
527            const MIN_BIT_WIDTH: usize = 64;
528
529            fn encode(zelf: Self) -> TruncatedU64<Self> {
530                let raw = Rc::into_raw(zelf);
531                TruncatedU64::new(raw as u64)
532            }
533
534            unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
535                // Safety:
536                // The caller must ensure that this is called only once on a value created by `encode` and the underlying allocation is still valid
537                unsafe { Rc::from_raw(raw.read() as *mut T) }
538            }
539        }
540
541        // Safety:
542        // casting *const T from and to u64 is safe
543        unsafe impl<T> AsPackedValue for Arc<T> {
544            const MIN_BIT_WIDTH: usize = 64;
545
546            fn encode(zelf: Self) -> TruncatedU64<Self> {
547                let raw = Arc::into_raw(zelf);
548                TruncatedU64::new(raw as u64)
549            }
550
551            unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
552                // Safety:
553                // The caller must ensure that this is called only once on a value created by `encode` and the underlying allocation is still valid
554                unsafe { Arc::from_raw(raw.read() as *mut T) }
555            }
556        }
557
558        // Safety:
559        // casting *const T from and to u64 is safe
560        unsafe impl<T> AsPackedValue for rc::Weak<T> {
561            const MIN_BIT_WIDTH: usize = 64;
562
563            fn encode(zelf: Self) -> TruncatedU64<Self> {
564                let raw = rc::Weak::into_raw(zelf);
565                TruncatedU64::new(raw as u64)
566            }
567
568            unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
569                // Safety:
570                // The caller must ensure that this is called only once on a value created by `encode` and the underlying allocation is still valid
571                unsafe { rc::Weak::from_raw(raw.read() as *mut T) }
572            }
573        }
574
575        // Safety:
576        // casting *const T from and to u64 is safe
577        unsafe impl<T> AsPackedValue for sync::Weak<T> {
578            const MIN_BIT_WIDTH: usize = 64;
579
580            fn encode(zelf: Self) -> TruncatedU64<Self> {
581                let raw = sync::Weak::into_raw(zelf);
582                TruncatedU64::new(raw as u64)
583            }
584
585            unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
586                // Safety:
587                // The caller must ensure that this is called only once on a value created by `encode` and the underlying allocation is still valid
588                unsafe { sync::Weak::from_raw(raw.read() as *mut T) }
589            }
590        }
591    }
592}
593
594#[cfg(not(target_pointer_width = "64"))]
595mod bit32 {
596    use core::num::NonZeroUsize;
597
598    use super::*;
599
600    // Safety:
601    // Casting from a ptr to a usize is safe
602    unsafe impl<T> AsPackedValue for *const T
603    where
604        T: Sized,
605    {
606        const MIN_BIT_WIDTH: usize = size_of::<usize>() * 8;
607
608        fn encode(zelf: Self) -> TruncatedU64<Self> {
609            TruncatedU64::new(zelf as u64)
610        }
611
612        unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
613            raw.read() as *const T
614        }
615    }
616
617    // Safety:
618    // Casting from a ptr to a usize is safe
619    unsafe impl<T> AsPackedValue for *mut T
620    where
621        T: Sized,
622    {
623        const MIN_BIT_WIDTH: usize = size_of::<usize>() * 8;
624
625        fn encode(zelf: Self) -> TruncatedU64<Self> {
626            TruncatedU64::new(zelf as u64)
627        }
628
629        unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
630            raw.read() as *mut T
631        }
632    }
633
634    // Safety:
635    // Casting from a ptr to a usize is safe
636    unsafe impl<T> AsPackedValue for NonNull<T>
637    where
638        T: Sized,
639    {
640        const MIN_BIT_WIDTH: usize = size_of::<usize>() * 8;
641
642        fn encode(zelf: Self) -> TruncatedU64<Self> {
643            TruncatedU64::new(zelf.as_ptr() as u64)
644        }
645
646        unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
647            Self::new(raw.read() as *mut T)
648                .expect("Constructing a NonNull form a null ptr wich was not obtained from encode")
649        }
650    }
651
652    // Safety:
653    // Casting from a ptr to a usize is safe
654    unsafe impl<T> AsPackedValue for &'static T {
655        const MIN_BIT_WIDTH: usize = size_of::<usize>() * 8;
656
657        fn encode(zelf: Self) -> TruncatedU64<Self> {
658            TruncatedU64::new(zelf as *const T as u64)
659        }
660
661        unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
662            // Safety:
663            // The caller must ensure that this is called only on a value returned by `encode` and the reference is still valid
664            unsafe { &*(raw.read() as *const T) }
665        }
666    }
667
668    // Safety:
669    // Casting from a ptr to a usize is safe
670    unsafe impl<T> AsPackedValue for &'static mut T {
671        const MIN_BIT_WIDTH: usize = size_of::<usize>() * 8;
672
673        fn encode(zelf: Self) -> TruncatedU64<Self> {
674            TruncatedU64::new(zelf as *mut T as u64)
675        }
676
677        unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
678            // Safety:
679            // The caller must ensure that this is called only once on a value returned by `encode` and the reference is still valid
680            unsafe { &mut *(raw.read() as *mut T) }
681        }
682    }
683
684    #[cfg(feature = "alloc")]
685    mod alloc_ {
686        use alloc::{
687            boxed::Box,
688            rc::{self, Rc},
689            sync::{self, Arc},
690        };
691
692        use super::*;
693
694        // Safety:
695        // Casting from a ptr to a usize is safe
696        unsafe impl<T> AsPackedValue for Box<T> {
697            const MIN_BIT_WIDTH: usize = size_of::<usize>() * 8;
698
699            fn encode(zelf: Self) -> TruncatedU64<Self> {
700                TruncatedU64::new(Box::into_raw(zelf) as u64)
701            }
702
703            unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
704                // Safety:
705                // The caller must ensure that this is called only once on a value returned by `encode` and the allocation is still valid
706                unsafe { Box::from_raw(raw.read() as *mut T) }
707            }
708        }
709
710        // Safety:
711        // Casting from a ptr to a usize is safe
712        unsafe impl<T> AsPackedValue for Rc<T> {
713            const MIN_BIT_WIDTH: usize = size_of::<usize>() * 8;
714
715            fn encode(zelf: Self) -> TruncatedU64<Self> {
716                let raw = Rc::into_raw(zelf);
717                TruncatedU64::new(raw as u64)
718            }
719
720            unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
721                // Safety:
722                // The caller must ensure that this is called only once on a value created by `encode` and the underlying allocation is still valid
723                unsafe { Rc::from_raw(raw.read() as *mut T) }
724            }
725        }
726
727        // Safety:
728        // Casting from a ptr to a usize is safe
729        unsafe impl<T> AsPackedValue for Arc<T> {
730            const MIN_BIT_WIDTH: usize = size_of::<usize>() * 8;
731
732            fn encode(zelf: Self) -> TruncatedU64<Self> {
733                let raw = Arc::into_raw(zelf);
734                TruncatedU64::new(raw as u64)
735            }
736
737            unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
738                // Safety:
739                // The caller must ensure that this is called only once on a value created by `encode` and the underlying allocation is still valid
740                unsafe { Arc::from_raw(raw.read() as *mut T) }
741            }
742        }
743
744        // Safety:
745        // Casting from a ptr to a usize is safe
746        unsafe impl<T> AsPackedValue for rc::Weak<T> {
747            const MIN_BIT_WIDTH: usize = size_of::<usize>() * 8;
748
749            fn encode(zelf: Self) -> TruncatedU64<Self> {
750                let raw = rc::Weak::into_raw(zelf);
751                TruncatedU64::new(raw as u64)
752            }
753
754            unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
755                // Safety:
756                // The caller must ensure that this is called only once on a value created by `encode` and the underlying allocation is still valid
757                unsafe { rc::Weak::from_raw(raw.read() as *mut T) }
758            }
759        }
760
761        // Safety:
762        // Casting from a ptr to a usize is safe
763        unsafe impl<T> AsPackedValue for sync::Weak<T> {
764            const MIN_BIT_WIDTH: usize = size_of::<usize>() * 8;
765
766            fn encode(zelf: Self) -> TruncatedU64<Self> {
767                let raw = sync::Weak::into_raw(zelf);
768                TruncatedU64::new(raw as u64)
769            }
770
771            unsafe fn decode(raw: TruncatedU64<Self>) -> Self {
772                // Safety:
773                // The caller must ensure that this is called only once on a value created by `encode` and the underlying allocation is still valid
774                unsafe { sync::Weak::from_raw(raw.read() as *mut T) }
775            }
776        }
777    }
778
779    atomic_encode_primitive!(usize);
780    atomic_encode_non_zero_primitive!(NonZeroUsize, usize);
781}
782
783#[cfg(test)]
784mod tests {
785    use super::*;
786
787    macro_rules! generate_test {
788        ($name:ident: $constructor:expr, $type:ty, $deref:expr) => {
789            #[test]
790            fn $name() {
791                #[allow(dead_code)]
792                static VALUE: i32 = 42;
793                const WIDTH: usize = <$type as AsPackedValue>::MIN_BIT_WIDTH;
794
795                let ptr1 = $constructor;
796                let expected = $deref(&ptr1);
797
798                let mut encoded = AsPackedValue::encode(ptr1);
799
800                if WIDTH < 64 {
801                    let packed_encoded = pack!((!0, encoded.read()): WIDTH);
802                    encoded = TruncatedU64::new(packed_encoded);
803                }
804
805                // Safety:
806                // we just encoded this value
807                let decoded = unsafe { AsPackedValue::decode(encoded) };
808
809                assert_eq!($deref(&decoded), expected);
810            }
811        };
812        ($name:ident: $constructor:expr, $type:ty) => {
813            generate_test!($name: $constructor, $type, |x: &$type| x.clone());
814        };
815    }
816
817    generate_test!(raw: &VALUE as *const i32, *const i32);
818    generate_test!(raw_mut: &VALUE as *const i32 as *mut i32, *mut i32);
819    generate_test!(r#ref: &VALUE, &'static i32);
820    generate_test!(nonnull: NonNull::new(&VALUE as *const i32 as *mut i32).unwrap(), NonNull<i32>);
821    generate_test!(primitive_u32: 42, u32);
822    generate_test!(primitive_nonzero_u32: NonZeroU32::new(42).unwrap(), NonZeroU32);
823    generate_test!(unit: (), ());
824
825    #[cfg(feature = "alloc")]
826    mod alloc_ {
827        use alloc::{
828            boxed::Box,
829            rc::{self, Rc},
830            sync::{self, Arc},
831        };
832
833        use super::*;
834
835        generate_test!(r#box: Box::new(VALUE), Box<i32>);
836        generate_test!(r#arc: Arc::new(VALUE), Arc<i32>);
837        generate_test!(r#rc: Rc::new(VALUE), Rc<i32>);
838        generate_test!(weak_rc: Rc::downgrade(&Rc::new(VALUE)), rc::Weak<i32>, |x: &rc::Weak<i32>| x.as_ptr());
839        generate_test!(weak_arc: Arc::downgrade(&Arc::new(VALUE)), sync::Weak<i32>, |x: &sync::Weak<i32>| x.as_ptr());
840    }
841}