1use core::fmt;
26use core::ptr::NonNull;
27use core::sync::atomic::Ordering;
28
29use crate::ptr::{Ptr, TaggedPtr};
30
31#[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#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
65pub struct Tag(pub(crate) usize);
66
67impl Tag {
68 #[inline]
70 pub const fn new(value: usize) -> Self {
71 Self(value & TAG_MASK)
72 }
73
74 #[inline]
76 pub const fn value(self) -> usize {
77 self.0
78 }
79
80 #[inline]
82 pub const fn wrapping_add(self, rhs: usize) -> Self {
83 Self::new(self.0.wrapping_add(rhs))
84 }
85
86 #[inline]
88 pub const fn wrapping_sub(self, rhs: usize) -> Self {
89 Self::new(self.0.wrapping_sub(rhs))
90 }
91
92 #[inline]
94 pub const fn next(self) -> Self {
95 self.wrapping_add(1)
96 }
97
98 #[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
163pub type TaggedPtrResult<T> = Result<TaggedPtr<T>, TaggedPtr<T>>;
165
166pub(crate) type RawTaggedPtrResult<T> =
168 Result<(Option<NonNull<T>>, Tag), (Option<NonNull<T>>, Tag)>;
169
170pub struct AtomicTaggedPtr<T> {
172 inner: AtomicTaggedPtrImpl<T>,
173}
174
175unsafe impl<T> Send for AtomicTaggedPtr<T> {}
177unsafe impl<T> Sync for AtomicTaggedPtr<T> {}
178
179impl<T> AtomicTaggedPtr<T> {
180 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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
332impl<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 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#[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!(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 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 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 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 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 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 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 let atom: AtomicTaggedPtr<i32> = AtomicTaggedPtr::new(TaggedPtr::new(None, Tag::new(0)));
458 assert_eq!(atom.load(Ordering::Relaxed).ptr.option(), None);
459
460 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 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 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 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 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 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 assert_eq!(ptr_some.as_ptr(), raw);
578 assert_eq!(ptr_none.as_ptr(), core::ptr::null());
579
580 assert_eq!(ptr_some.as_mut_ptr(), mut_ptr);
582 assert_eq!(ptr_none.as_mut_ptr(), core::ptr::null_mut());
583
584 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 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 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 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 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 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 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 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 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 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 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 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}