Skip to main content

atomic_tagged_ptr/
impl.rs

1//! A platform-adaptive atomic tagged pointer implementation with robust ABA protection.
2//!
3//! # Background & Hardware Realities
4//!
5//! In lock-free concurrent programming, particularly when constructing intrusive data structures
6//! such as a Treiber Stack, the **ABA problem** frequently arises. The traditional mitigation involves
7//! pairing the physical pointer with a generation tag, updating both atomically.
8//!
9//! However, this incurs CPU architecture constraints:
10//! 1. **64-bit Systems with High Virtual Addresses (52/57-bit)**:
11//!    Modern operating systems on x86_64 (using Intel 5-level paging for 57-bit address space) or AArch64
12//!    (using 52-bit virtual addresses) utilize pointer spaces beyond the typical 48-bit region. Assumed
13//!    48-bit address layout limits lead to pointer truncation and severe wild-pointer crashes.
14//!    This module splits the 64-bit word dynamically: reserving the **lower 56 bits** for the physical pointer
15//!    (covering the entire `007f_ffff_ffff_ffff` user-space boundary) and the **upper 8 bits** for the tag.
16//!    This provides absolute pointer integrity across all current server environments.
17//! 2. **32-bit Systems**:
18//!    Pointer width is 32 bits. We pair it with a 32-bit generation tag to form a double-word 64-bit composite.
19//!    This leverages hardware-level 64-bit atomic operations (such as `cmpxchg8b` on x86 or `ldrd/strd` on ARMv7)
20//!    to complete CAS transitions natively, without making raw address size assumptions.
21//! 3. **Non-AtomicFallback Systems**:
22//!    Under highly customized secure hypervisors (using full MTE tagging) or extremely constrained microcontrollers
23//!    without native 64-bit atomics, the implementation seamlessly falls back to standard Mutex synchronization.
24//!    This guarantees 100% compilation safety without sacrificing API consistency or memory efficiency.
25use core::fmt;
26use core::ptr::NonNull;
27use core::sync::atomic::Ordering;
28
29use crate::ptr::{Ptr, TaggedPtr};
30
31// --- Platform Routing Conditional Compile Sections ---
32
33#[cfg(all(target_pointer_width = "64", not(atomic_fallback)))]
34mod ptr64;
35
36#[cfg(all(target_pointer_width = "64", not(atomic_fallback)))]
37use ptr64::AtomicTaggedPtrImpl;
38
39#[cfg(all(target_pointer_width = "64", not(atomic_fallback)))]
40pub use ptr64::TAG_MASK;
41
42#[cfg(all(target_pointer_width = "32", not(atomic_fallback)))]
43mod ptr32;
44
45#[cfg(all(target_pointer_width = "32", not(atomic_fallback)))]
46use ptr32::AtomicTaggedPtrImpl;
47
48#[cfg(all(target_pointer_width = "32", not(atomic_fallback)))]
49pub use ptr32::TAG_MASK;
50
51#[cfg(atomic_fallback)]
52mod fallback;
53
54#[cfg(atomic_fallback)]
55pub use fallback::TAG_MASK;
56
57#[cfg(atomic_fallback)]
58use fallback::AtomicTaggedPtrImpl;
59
60/// Represents a generation tag used for ABA protection in `AtomicTaggedPtr`.
61///
62/// `Tag` wraps a platform-specific generation count and ensures that any operations
63/// (like wrapping addition or creation) respect the hardware platform's limits and bit-width.
64#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
65pub struct Tag(pub(crate) usize);
66
67impl Tag {
68    /// Creates a new `Tag` from a raw value, applying the platform-specific mask.
69    #[inline]
70    pub const fn new(value: usize) -> Self {
71        Self(value & TAG_MASK)
72    }
73
74    /// Gets the raw tag value.
75    #[inline]
76    pub const fn value(self) -> usize {
77        self.0
78    }
79
80    /// Performs wrapping addition on the tag value.
81    #[inline]
82    pub const fn wrapping_add(self, rhs: usize) -> Self {
83        Self::new(self.0.wrapping_add(rhs))
84    }
85
86    /// Performs wrapping subtraction on the tag value.
87    #[inline]
88    pub const fn wrapping_sub(self, rhs: usize) -> Self {
89        Self::new(self.0.wrapping_sub(rhs))
90    }
91
92    /// Returns the next tag value, wrapping around on overflow.
93    #[inline]
94    pub const fn next(self) -> Self {
95        self.wrapping_add(1)
96    }
97
98    /// Returns the maximum tag value allowed on this platform.
99    #[inline]
100    pub const fn max_value() -> Self {
101        Self(TAG_MASK)
102    }
103}
104
105impl fmt::Debug for Tag {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        write!(f, "Tag({:#X})", self.0)
108    }
109}
110
111impl fmt::Display for Tag {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        write!(f, "{}", self.0)
114    }
115}
116
117impl From<usize> for Tag {
118    #[inline]
119    fn from(value: usize) -> Self {
120        Self::new(value)
121    }
122}
123
124impl From<Tag> for usize {
125    #[inline]
126    fn from(tag: Tag) -> usize {
127        tag.0
128    }
129}
130
131impl core::ops::Add<usize> for Tag {
132    type Output = Self;
133
134    #[inline]
135    fn add(self, rhs: usize) -> Self::Output {
136        self.wrapping_add(rhs)
137    }
138}
139
140impl core::ops::AddAssign<usize> for Tag {
141    #[inline]
142    fn add_assign(&mut self, rhs: usize) {
143        *self = *self + rhs;
144    }
145}
146
147impl core::ops::Sub<usize> for Tag {
148    type Output = Self;
149
150    #[inline]
151    fn sub(self, rhs: usize) -> Self::Output {
152        self.wrapping_sub(rhs)
153    }
154}
155
156impl core::ops::SubAssign<usize> for Tag {
157    #[inline]
158    fn sub_assign(&mut self, rhs: usize) {
159        *self = *self - rhs;
160    }
161}
162
163/// Type alias representing the result of atomic compare and exchange operations.
164pub type TaggedPtrResult<T> = Result<TaggedPtr<T>, TaggedPtr<T>>;
165
166/// Type alias for raw results returned by internal platform implementations.
167pub(crate) type RawTaggedPtrResult<T> =
168    Result<(Option<NonNull<T>>, Tag), (Option<NonNull<T>>, Tag)>;
169
170/// A platform-adaptive atomic tagged pointer supporting thread-safe ABA protection.
171pub struct AtomicTaggedPtr<T> {
172    inner: AtomicTaggedPtrImpl<T>,
173}
174
175// Safety: AtomicTaggedPtr is an atomic synchronizer wrapping pointer locations, safe to send/share across threads.
176unsafe impl<T> Send for AtomicTaggedPtr<T> {}
177unsafe impl<T> Sync for AtomicTaggedPtr<T> {}
178
179impl<T> AtomicTaggedPtr<T> {
180    /// Creates a new `AtomicTaggedPtr` initialized with the given tagged pointer.
181    ///
182    /// # Examples
183    ///
184    /// ```
185    /// use std::ptr::NonNull;
186    /// use atomic_tagged_ptr::{AtomicTaggedPtr, TaggedPtr, Tag};
187    ///
188    /// let value = 42;
189    /// let ptr = NonNull::new(&value as *const i32 as *mut i32);
190    /// let atom = AtomicTaggedPtr::new(TaggedPtr::new(ptr, Tag::new(0)));
191    /// ```
192    #[inline]
193    pub fn new(val: impl Into<TaggedPtr<T>>) -> Self {
194        let val = val.into();
195        Self {
196            inner: AtomicTaggedPtrImpl::new(val.ptr.option(), val.tag),
197        }
198    }
199
200    /// Loads the current values of the pointer and tag atomically.
201    ///
202    /// # Panics
203    ///
204    /// Panics if `order` is `Release` or `AcqRel`.
205    #[inline]
206    pub fn load(&self, order: Ordering) -> TaggedPtr<T> {
207        let (raw_ptr, tag) = self.inner.load(order);
208        TaggedPtr {
209            ptr: Ptr::new(raw_ptr),
210            tag,
211        }
212    }
213
214    /// Stores a new pointer and tag atomically.
215    ///
216    /// # Panics
217    ///
218    /// Panics if `order` is `Acquire` or `AcqRel`.
219    #[inline]
220    pub fn store(&self, val: impl Into<TaggedPtr<T>>, order: Ordering) {
221        let val = val.into();
222        self.inner.store(val.ptr.option(), val.tag, order);
223    }
224
225    /// Exchanges the current values with new ones if the current values match expectations.
226    ///
227    /// On success, returns `Ok` containing the previous pointer and tag.
228    /// On failure, returns `Err` containing the actual loaded pointer and tag.
229    #[inline]
230    pub fn compare_exchange(
231        &self,
232        current: impl Into<TaggedPtr<T>>,
233        new: impl Into<TaggedPtr<T>>,
234        success: Ordering,
235        failure: Ordering,
236    ) -> TaggedPtrResult<T> {
237        let current = current.into();
238        let new = new.into();
239        match self.inner.compare_exchange(
240            (current.ptr.option(), current.tag),
241            (new.ptr.option(), new.tag),
242            success,
243            failure,
244        ) {
245            Ok((raw_ptr, tag)) => Ok(TaggedPtr {
246                ptr: Ptr::new(raw_ptr),
247                tag,
248            }),
249            Err((raw_ptr, tag)) => Err(TaggedPtr {
250                ptr: Ptr::new(raw_ptr),
251                tag,
252            }),
253        }
254    }
255
256    /// Exchanges the current values with new ones using weak semantics.
257    ///
258    /// This is a weaker variant of `compare_exchange` which is allowed to fail spuriously,
259    /// but can be significantly more efficient on certain LL/SC-based architectures (such as ARM).
260    #[inline]
261    pub fn compare_exchange_weak(
262        &self,
263        current: impl Into<TaggedPtr<T>>,
264        new: impl Into<TaggedPtr<T>>,
265        success: Ordering,
266        failure: Ordering,
267    ) -> TaggedPtrResult<T> {
268        let current = current.into();
269        let new = new.into();
270        match self.inner.compare_exchange_weak(
271            (current.ptr.option(), current.tag),
272            (new.ptr.option(), new.tag),
273            success,
274            failure,
275        ) {
276            Ok((raw_ptr, tag)) => Ok(TaggedPtr {
277                ptr: Ptr::new(raw_ptr),
278                tag,
279            }),
280            Err((raw_ptr, tag)) => Err(TaggedPtr {
281                ptr: Ptr::new(raw_ptr),
282                tag,
283            }),
284        }
285    }
286
287    /// Atomically exchanges the value and returns the old value.
288    #[inline]
289    pub fn swap(&self, val: impl Into<TaggedPtr<T>>, order: Ordering) -> TaggedPtr<T> {
290        let val = val.into();
291        let (raw_ptr, tag) = self.inner.swap(val.ptr.option(), val.tag, order);
292        TaggedPtr {
293            ptr: Ptr::new(raw_ptr),
294            tag,
295        }
296    }
297
298    /// Consumes the atomic and returns the inner value.
299    #[inline]
300    pub fn into_inner(self) -> TaggedPtr<T> {
301        let (raw_ptr, tag) = self.inner.into_inner();
302        TaggedPtr {
303            ptr: Ptr::new(raw_ptr),
304            tag,
305        }
306    }
307
308    /// Fetches the value, applies a function to it, and attempts to store the result.
309    ///
310    /// This is a convenience method for compare-and-swap loops.
311    #[inline]
312    pub fn fetch_update<F>(
313        &self,
314        set_order: Ordering,
315        fetch_order: Ordering,
316        mut f: F,
317    ) -> Result<TaggedPtr<T>, TaggedPtr<T>>
318    where
319        F: FnMut(TaggedPtr<T>) -> Option<TaggedPtr<T>>,
320    {
321        let mut prev = self.load(fetch_order);
322        while let Some(next) = f(prev) {
323            match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
324                Ok(x) => return Ok(x),
325                Err(next_prev) => prev = next_prev,
326            }
327        }
328        Err(prev)
329    }
330}
331
332// --- Common Trait Implementations ---
333
334impl<T> Default for AtomicTaggedPtr<T> {
335    #[inline]
336    fn default() -> Self {
337        Self::new(TaggedPtr::default())
338    }
339}
340
341impl<T> fmt::Debug for AtomicTaggedPtr<T> {
342    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343        // Safe load under Relaxed ordering to capture debug state snapshot
344        let val = self.load(Ordering::Relaxed);
345        f.debug_struct("AtomicTaggedPtr")
346            .field("pointer", &val.ptr)
347            .field("tag", &val.tag)
348            .finish()
349    }
350}
351
352impl<T> From<TaggedPtr<T>> for AtomicTaggedPtr<T> {
353    #[inline]
354    fn from(val: TaggedPtr<T>) -> Self {
355        Self::new(val)
356    }
357}
358
359impl<T> From<(Ptr<T>, Tag)> for AtomicTaggedPtr<T> {
360    #[inline]
361    fn from(val: (Ptr<T>, Tag)) -> Self {
362        Self::new(val)
363    }
364}
365
366// --- Built-in Local Integration Tests ---
367
368#[cfg(all(test, feature = "std"))]
369mod tests {
370    use super::*;
371    use std::format;
372
373    #[test]
374    fn test_default_initializer() {
375        let atom: AtomicTaggedPtr<i32> = Default::default();
376        let loaded = atom.load(Ordering::Relaxed);
377        assert!(loaded.ptr.is_none());
378        assert_eq!(loaded.tag, Tag::new(0));
379    }
380
381    #[test]
382    fn test_debug_formatter() {
383        let val = 12345;
384        let ptr = NonNull::new(&val as *const i32 as *mut i32);
385        let atom = AtomicTaggedPtr::new(TaggedPtr::new(ptr, Tag::new(0)));
386        atom.store(TaggedPtr::new(ptr, Tag::new(88)), Ordering::Relaxed);
387
388        let debug_str = format!("{:?}", atom);
389        assert!(debug_str.contains("AtomicTaggedPtr"));
390        assert!(debug_str.contains("tag: Tag(0x58)"));
391    }
392
393    #[test]
394    fn test_multithreaded_atomic_exchanges() {
395        use std::sync::Arc;
396        use std::thread;
397
398        let val = 777;
399        let ptr = NonNull::new(&val as *const i32 as *mut i32);
400        let ptr_usize = ptr.unwrap().as_ptr() as usize;
401        let atom = Arc::new(AtomicTaggedPtr::new(TaggedPtr::new(ptr, Tag::new(0))));
402
403        let atom_clone = Arc::clone(&atom);
404        let handle = thread::spawn(move || {
405            let loaded = atom_clone.load(Ordering::Acquire);
406            let local_ptr = NonNull::new(ptr_usize as *mut i32);
407            if loaded.ptr == local_ptr && loaded.tag == Tag::new(0) {
408                let _ = atom_clone.compare_exchange(
409                    TaggedPtr::new(local_ptr, Tag::new(0)),
410                    TaggedPtr::new(None, Tag::new(55)),
411                    Ordering::SeqCst,
412                    Ordering::SeqCst,
413                );
414            }
415        });
416
417        handle.join().unwrap();
418        let final_state = atom.load(Ordering::Acquire);
419
420        // Assert state was safely transitioned or remained valid
421        assert!(final_state.tag == Tag::new(55) || final_state.tag == Tag::new(0));
422    }
423
424    #[test]
425    fn test_into_ptr_api() {
426        let val1 = 111;
427        let raw_ptr1 = &val1 as *const i32;
428        let mut_ptr1 = &val1 as *const i32 as *mut i32;
429        let non_null1 = NonNull::new(mut_ptr1).unwrap();
430
431        // 1. 测试 new
432        // 传入 NonNull<T>
433        let atom = AtomicTaggedPtr::new(TaggedPtr::new(non_null1, Tag::new(0)));
434        assert_eq!(atom.load(Ordering::Relaxed).ptr.option(), Some(non_null1));
435
436        // 传入 Option<NonNull<T>>
437        let atom = AtomicTaggedPtr::new(TaggedPtr::new(Some(non_null1), Tag::new(0)));
438        assert_eq!(atom.load(Ordering::Relaxed).ptr.option(), Some(non_null1));
439
440        // 传入 *const T
441        let atom = AtomicTaggedPtr::new(TaggedPtr::new(raw_ptr1, Tag::new(0)));
442        assert_eq!(atom.load(Ordering::Relaxed).ptr.option(), Some(non_null1));
443
444        // 传入 *mut T
445        let atom = AtomicTaggedPtr::new(TaggedPtr::new(mut_ptr1, Tag::new(0)));
446        assert_eq!(atom.load(Ordering::Relaxed).ptr.option(), Some(non_null1));
447
448        // 传入裸空指针 *const T
449        let atom = AtomicTaggedPtr::new(TaggedPtr::new(core::ptr::null::<i32>(), Tag::new(0)));
450        assert_eq!(atom.load(Ordering::Relaxed).ptr.option(), None);
451
452        // 传入裸空指针 *mut T
453        let atom = AtomicTaggedPtr::new(TaggedPtr::new(core::ptr::null_mut::<i32>(), Tag::new(0)));
454        assert_eq!(atom.load(Ordering::Relaxed).ptr.option(), None);
455
456        // 传入 None
457        let atom: AtomicTaggedPtr<i32> = AtomicTaggedPtr::new(TaggedPtr::new(None, Tag::new(0)));
458        assert_eq!(atom.load(Ordering::Relaxed).ptr.option(), None);
459
460        // 2. 测试 store
461        let atom = AtomicTaggedPtr::new(TaggedPtr::default());
462        atom.store(TaggedPtr::new(raw_ptr1, Tag::new(10)), Ordering::Relaxed);
463        let loaded = atom.load(Ordering::Relaxed);
464        assert_eq!(loaded.ptr.option(), Some(non_null1));
465        assert_eq!(loaded.tag, Tag::new(10));
466
467        atom.store(TaggedPtr::new(None, Tag::new(20)), Ordering::Relaxed);
468        let loaded = atom.load(Ordering::Relaxed);
469        assert_eq!(loaded.ptr.option(), None);
470        assert_eq!(loaded.tag, Tag::new(20));
471
472        // 3. 测试 compare_exchange / compare_exchange_weak (混合不同类型的指针参数)
473        let atom = AtomicTaggedPtr::new(TaggedPtr::new(raw_ptr1, Tag::new(0)));
474        let res = atom.compare_exchange(
475            TaggedPtr::new(raw_ptr1, Tag::new(0)),
476            TaggedPtr::new(mut_ptr1, Tag::new(1)),
477            Ordering::SeqCst,
478            Ordering::SeqCst,
479        );
480        assert!(res.is_ok());
481        let loaded = atom.load(Ordering::Relaxed);
482        assert_eq!(loaded.ptr.option(), Some(non_null1));
483        assert_eq!(loaded.tag, Tag::new(1));
484
485        let res = atom.compare_exchange_weak(
486            TaggedPtr::new(mut_ptr1, Tag::new(1)),
487            TaggedPtr::new(None, Tag::new(2)),
488            Ordering::SeqCst,
489            Ordering::SeqCst,
490        );
491        let mut res = res;
492        while res.is_err() {
493            res = atom.compare_exchange_weak(
494                TaggedPtr::new(mut_ptr1, Tag::new(1)),
495                TaggedPtr::new(None, Tag::new(2)),
496                Ordering::SeqCst,
497                Ordering::SeqCst,
498            );
499        }
500        assert!(res.is_ok());
501        let loaded = atom.load(Ordering::Relaxed);
502        assert_eq!(loaded.ptr.option(), None);
503        assert_eq!(loaded.tag, Tag::new(2));
504
505        // 4. 测试 From/Into conversions 直接调用
506        let ptr_from_nn = Ptr::from(non_null1);
507        assert_eq!(ptr_from_nn.option(), Some(non_null1));
508        let ptr_from_opt: Ptr<i32> = Ptr::from(Some(non_null1));
509        assert_eq!(ptr_from_opt.option(), Some(non_null1));
510        let ptr_from_const = Ptr::from(raw_ptr1);
511        assert_eq!(ptr_from_const.option(), Some(non_null1));
512        let ptr_from_mut = Ptr::from(mut_ptr1);
513        assert_eq!(ptr_from_mut.option(), Some(non_null1));
514
515        let tagged = TaggedPtr::new(non_null1, Tag::new(123));
516        let ptr_from_tagged = Ptr::from(tagged);
517        assert_eq!(ptr_from_tagged.option(), Some(non_null1));
518
519        let opt_from_ptr = Option::<NonNull<i32>>::from(ptr_from_nn);
520        assert_eq!(opt_from_ptr, Some(non_null1));
521        let opt_from_tagged = Option::<NonNull<i32>>::from(tagged);
522        assert_eq!(opt_from_tagged, Some(non_null1));
523
524        // 5. 测试 Tuple -> TaggedPtr 转换以及 AtomicTaggedPtr 接收 Into<TaggedPtr>
525        let tag = Tag::new(456);
526        let tagged_from_nn = TaggedPtr::from((non_null1, tag));
527        assert_eq!(tagged_from_nn.ptr.option(), Some(non_null1));
528        assert_eq!(tagged_from_nn.tag, tag);
529
530        let tagged_from_opt = TaggedPtr::from((Some(non_null1), tag));
531        assert_eq!(tagged_from_opt.ptr.option(), Some(non_null1));
532        assert_eq!(tagged_from_opt.tag, tag);
533
534        let tagged_from_const = TaggedPtr::from((raw_ptr1, tag));
535        assert_eq!(tagged_from_const.ptr.option(), Some(non_null1));
536        assert_eq!(tagged_from_const.tag, tag);
537
538        let tagged_from_mut = TaggedPtr::from((mut_ptr1, tag));
539        assert_eq!(tagged_from_mut.ptr.option(), Some(non_null1));
540        assert_eq!(tagged_from_mut.tag, tag);
541
542        // 测试 AtomicTaggedPtr 操作接收 tuple
543        let atom = AtomicTaggedPtr::new((non_null1, tag));
544        assert_eq!(atom.load(Ordering::Relaxed).ptr.option(), Some(non_null1));
545
546        atom.store((None, Tag::new(789)), Ordering::Relaxed);
547        assert_eq!(atom.load(Ordering::Relaxed).ptr.option(), None);
548        assert_eq!(atom.load(Ordering::Relaxed).tag, Tag::new(789));
549
550        let res = atom.compare_exchange(
551            (None, Tag::new(789)),
552            (mut_ptr1, Tag::new(999)),
553            Ordering::Relaxed,
554            Ordering::Relaxed,
555        );
556        assert!(res.is_ok());
557        assert_eq!(atom.load(Ordering::Relaxed).ptr.option(), Some(non_null1));
558        assert_eq!(atom.load(Ordering::Relaxed).tag, Tag::new(999));
559    }
560
561    #[test]
562    fn test_ptr_conversions() {
563        let val = 42;
564        let raw = &val as *const i32;
565        let mut_ptr = &val as *const i32 as *mut i32;
566        let non_null = NonNull::new(mut_ptr).unwrap();
567
568        let ptr_some = Ptr::new(Some(non_null));
569        let ptr_none: Ptr<i32> = Ptr::new(None);
570
571        // 测试 option() / as_option()
572        assert_eq!(ptr_some.option(), Some(non_null));
573        assert_eq!(ptr_none.option(), None);
574        assert_eq!(ptr_some.as_option(), Some(non_null));
575
576        // 测试 as_ptr()
577        assert_eq!(ptr_some.as_ptr(), raw);
578        assert_eq!(ptr_none.as_ptr(), core::ptr::null());
579
580        // 测试 as_mut_ptr()
581        assert_eq!(ptr_some.as_mut_ptr(), mut_ptr);
582        assert_eq!(ptr_none.as_mut_ptr(), core::ptr::null_mut());
583
584        // 测试 is_null() / is_some() / is_none()
585        assert!(ptr_some.is_some());
586        assert!(!ptr_some.is_null());
587        assert!(!ptr_some.is_none());
588
589        assert!(ptr_none.is_null());
590        assert!(ptr_none.is_none());
591        assert!(!ptr_none.is_some());
592
593        // 测试 PartialEq
594        assert!(ptr_some == Some(non_null));
595        assert!(ptr_some == non_null);
596        assert!(ptr_some == raw);
597        assert!(ptr_some == mut_ptr);
598
599        assert!(ptr_none == None);
600        assert!(ptr_none == core::ptr::null::<i32>());
601        assert!(ptr_none == core::ptr::null_mut::<i32>());
602    }
603
604    #[test]
605    fn test_new_traits_and_methods() {
606        let mut val = 42;
607        let non_null = NonNull::new(&mut val as *mut i32).unwrap();
608        let ptr_some = Ptr::new(Some(non_null));
609        let ptr_none = Ptr::<i32>::new(None);
610
611        // 1. Ptr::as_ref / as_mut
612        unsafe {
613            assert_eq!(ptr_some.as_ref(), Some(&42));
614            assert_eq!(ptr_none.as_ref(), None);
615            *ptr_some.as_mut().unwrap() = 100;
616            assert_eq!(ptr_some.as_ref(), Some(&100));
617            assert_eq!(ptr_none.as_mut(), None);
618        }
619
620        // 2. Ptr::expect / unwrap / unwrap_or
621        assert_eq!(ptr_some.expect("should be valid"), non_null);
622        assert_eq!(ptr_some.unwrap(), non_null);
623        let other_val = 99;
624        let other_nn = NonNull::new(&other_val as *const i32 as *mut i32).unwrap();
625        assert_eq!(ptr_none.unwrap_or(other_nn), other_nn);
626
627        // 3. Ptr::map / map_or / map_or_else
628        let mapped = ptr_some.map(|p| p);
629        assert_eq!(mapped, ptr_some);
630        assert_eq!(ptr_some.map_or(0, |p| unsafe { *p.as_ptr() }), 100);
631        assert_eq!(ptr_none.map_or(0, |p| unsafe { *p.as_ptr() }), 0);
632        assert_eq!(ptr_some.map_or_else(|| 0, |p| unsafe { *p.as_ptr() }), 100);
633        assert_eq!(ptr_none.map_or_else(|| 0, |p| unsafe { *p.as_ptr() }), 0);
634
635        // 4. Ptr Pointer formatting / Ord
636        let format_str = format!("{:p}", ptr_some);
637        assert!(!format_str.is_empty());
638        assert!(ptr_some > ptr_none || ptr_some < ptr_none || ptr_some == ptr_none);
639        assert_eq!(ptr_some.cmp(&ptr_some), core::cmp::Ordering::Equal);
640
641        // 5. Ptr conversions
642        let raw_const: *const i32 = ptr_some.into();
643        assert_eq!(raw_const, non_null.as_ptr() as *const i32);
644        let raw_mut: *mut i32 = ptr_some.into();
645        assert_eq!(raw_mut, non_null.as_ptr());
646        let opt_const: Option<*const i32> = ptr_some.into();
647        assert_eq!(opt_const, Some(non_null.as_ptr() as *const i32));
648        let opt_mut: Option<*mut i32> = ptr_none.into();
649        assert_eq!(opt_mut, None);
650
651        // 6. TaggedPtr methods & traits
652        let tag = Tag::new(10);
653        let tagged = TaggedPtr::new(ptr_some, tag);
654        assert_eq!(tagged.as_ptr(), raw_const);
655        assert_eq!(tagged.as_mut_ptr(), raw_mut);
656        assert!(tagged.is_some());
657        assert!(!tagged.is_null());
658        assert!(!tagged.is_none());
659        unsafe {
660            assert_eq!(tagged.as_ref(), Some(&100));
661            *tagged.as_mut().unwrap() = 200;
662            assert_eq!(tagged.as_ref(), Some(&200));
663        }
664
665        let tagged_with_ptr = tagged.with_ptr(ptr_none);
666        assert!(tagged_with_ptr.is_none());
667        assert_eq!(tagged_with_ptr.tag, tag);
668
669        let tagged_with_tag = tagged.with_tag(Tag::new(20));
670        assert_eq!(tagged_with_tag.tag.value(), 20);
671
672        let mapped_tagged = tagged.map_ptr(|p| p);
673        assert_eq!(mapped_tagged, tagged);
674
675        // TaggedPtr Pointer / Ord / Conversions
676        let format_tagged = format!("{:p}", tagged);
677        assert!(!format_tagged.is_empty());
678        assert_eq!(tagged.cmp(&tagged), core::cmp::Ordering::Equal);
679        let raw_const_tagged: *const i32 = tagged.into();
680        assert_eq!(raw_const_tagged, raw_const);
681        let raw_mut_tagged: *mut i32 = tagged.into();
682        assert_eq!(raw_mut_tagged, raw_mut);
683
684        // TaggedPtr manual PartialEq/Eq/Hash
685        assert_eq!(tagged, TaggedPtr::new(ptr_some, tag));
686        let mut hasher = std::collections::hash_map::DefaultHasher::new();
687        use core::hash::Hash;
688        use core::hash::Hasher;
689        tagged.hash(&mut hasher);
690        assert!(hasher.finish() > 0);
691
692        // 7. Tag arithmetic & methods
693        let tag1 = Tag::new(5);
694        assert_eq!(tag1.wrapping_sub(2).value(), 3);
695        assert_eq!(tag1.next().value(), 6);
696        assert_eq!((tag1 + 2).value(), 7);
697        assert_eq!((tag1 - 2).value(), 3);
698        let mut mut_tag = tag1;
699        mut_tag += 2;
700        assert_eq!(mut_tag.value(), 7);
701        mut_tag -= 2;
702        assert_eq!(mut_tag.value(), 5);
703
704        // 8. AtomicTaggedPtr swap / into_inner / fetch_update / From
705        let atom = AtomicTaggedPtr::new(tagged);
706        let old = atom.swap(TaggedPtr::new(ptr_none, Tag::new(99)), Ordering::SeqCst);
707        assert_eq!(old, tagged);
708        assert_eq!(atom.load(Ordering::SeqCst).tag.value(), 99);
709
710        let inner_val = atom.into_inner();
711        assert!(inner_val.ptr.is_none());
712        assert_eq!(inner_val.tag.value(), 99);
713
714        let atom2 = AtomicTaggedPtr::from(tagged);
715        let res = atom2.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |t| {
716            Some(t.with_tag(t.tag + 1))
717        });
718        assert!(res.is_ok());
719        assert_eq!(atom2.load(Ordering::SeqCst).tag.value(), tag.value() + 1);
720
721        let atom3 = AtomicTaggedPtr::from((ptr_some, tag));
722        assert_eq!(atom3.load(Ordering::SeqCst).tag.value(), tag.value());
723    }
724}