atomic_tagged_ptr/ptr/tagged.rs
1mod atomic;
2
3pub use atomic::{AtomicTaggedPtr, TAG_MASK};
4
5use core::fmt;
6use core::ptr::NonNull;
7
8use super::Ptr;
9
10/// A packaged representation of a pointer and a generation tag.
11/// Used for atomic operations with `AtomicTaggedPtr`.
12pub struct TaggedPtr<T> {
13 /// The physical pointer wrapper.
14 pub ptr: Ptr<T>,
15 /// The generation tag for ABA protection.
16 pub tag: crate::Tag,
17}
18
19impl<T> Copy for TaggedPtr<T> {}
20
21impl<T> Clone for TaggedPtr<T> {
22 #[inline]
23 fn clone(&self) -> Self {
24 *self
25 }
26}
27
28impl<T> PartialEq for TaggedPtr<T> {
29 #[inline]
30 fn eq(&self, other: &Self) -> bool {
31 self.ptr == other.ptr && self.tag == other.tag
32 }
33}
34
35impl<T> Eq for TaggedPtr<T> {}
36
37impl<T> core::hash::Hash for TaggedPtr<T> {
38 #[inline]
39 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
40 self.ptr.hash(state);
41 self.tag.hash(state);
42 }
43}
44
45impl<T> Default for TaggedPtr<T> {
46 #[inline]
47 fn default() -> Self {
48 Self {
49 ptr: Ptr::default(),
50 tag: crate::Tag::default(),
51 }
52 }
53}
54
55impl<T> TaggedPtr<T> {
56 /// Creates a new `TaggedPtr` from a pointer and a tag.
57 ///
58 /// # Examples
59 ///
60 /// ```rust
61 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
62 /// use std::ptr::NonNull;
63 ///
64 /// let val = 42;
65 /// let ptr = NonNull::new(&val as *const i32 as *mut i32);
66 /// let tagged = TaggedPtr::new(ptr, Tag::new(123));
67 /// assert_eq!(tagged.ptr.option(), ptr);
68 /// assert_eq!(tagged.tag.value(), 123);
69 /// ```
70 #[inline]
71 pub fn new<P>(ptr: P, tag: crate::Tag) -> Self
72 where
73 P: Into<Ptr<T>>,
74 {
75 Self {
76 ptr: ptr.into(),
77 tag,
78 }
79 }
80
81 /// Creates a new `TaggedPtr` with a null pointer and the default tag.
82 ///
83 /// # Examples
84 ///
85 /// ```rust
86 /// use atomic_tagged_ptr::TaggedPtr;
87 ///
88 /// let p: TaggedPtr<i32> = TaggedPtr::null();
89 /// assert!(p.is_null());
90 /// assert_eq!(p.tag.value(), 0);
91 /// ```
92 #[inline]
93 pub const fn null() -> Self {
94 Self {
95 ptr: Ptr::null(),
96 tag: crate::Tag::new(0),
97 }
98 }
99
100 /// Casts the pointer part to a pointer of another type, keeping the tag unchanged.
101 ///
102 /// # Examples
103 ///
104 /// ```rust
105 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
106 /// use std::ptr::NonNull;
107 ///
108 /// let val = 42u8;
109 /// let tagged = TaggedPtr::new(NonNull::new(&val as *const u8 as *mut u8), Tag::new(123));
110 /// let casted: TaggedPtr<i8> = tagged.cast();
111 /// assert_eq!(casted.tag.value(), 123);
112 /// ```
113 #[inline]
114 pub fn cast<U>(self) -> TaggedPtr<U> {
115 TaggedPtr {
116 ptr: self.ptr.cast(),
117 tag: self.tag,
118 }
119 }
120
121 /// Deconstructs the `TaggedPtr` into a tuple of `(Ptr<T>, Tag)`.
122 ///
123 /// # Examples
124 ///
125 /// ```rust
126 /// use atomic_tagged_ptr::{TaggedPtr, Tag, Ptr};
127 /// use std::ptr::NonNull;
128 ///
129 /// let val = 42;
130 /// let ptr = NonNull::new(&val as *const i32 as *mut i32);
131 /// let tagged = TaggedPtr::new(ptr, Tag::new(123));
132 /// let (p, t) = tagged.decompose();
133 /// assert_eq!(p.option(), ptr);
134 /// assert_eq!(t.value(), 123);
135 /// ```
136 #[inline]
137 pub fn decompose(self) -> (Ptr<T>, crate::Tag) {
138 (self.ptr, self.tag)
139 }
140
141 /// Converts the pointer part into a raw const pointer `*const T`.
142 /// Returns a null pointer if the underlying pointer is null.
143 ///
144 /// # Examples
145 ///
146 /// ```rust
147 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
148 /// use std::ptr::NonNull;
149 ///
150 /// let val = 42;
151 /// let ptr = NonNull::new(&val as *const i32 as *mut i32);
152 /// let tagged = TaggedPtr::new(ptr, Tag::new(123));
153 /// assert_eq!(unsafe { *tagged.as_ptr() }, 42);
154 ///
155 /// let null_tagged: TaggedPtr<i32> = TaggedPtr::null();
156 /// assert!(null_tagged.as_ptr().is_null());
157 /// ```
158 #[inline]
159 pub fn as_ptr(self) -> *const T {
160 self.ptr.as_ptr()
161 }
162
163 /// Converts the pointer part into a raw mutable pointer `*mut T`.
164 /// Returns a null pointer if the underlying pointer is null.
165 ///
166 /// # Examples
167 ///
168 /// ```rust
169 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
170 /// use std::ptr::NonNull;
171 ///
172 /// let mut val = 42;
173 /// let ptr = NonNull::new(&mut val as *mut i32);
174 /// let tagged = TaggedPtr::new(ptr, Tag::new(123));
175 /// assert_eq!(unsafe { *tagged.as_mut_ptr() }, 42);
176 ///
177 /// let null_tagged: TaggedPtr<i32> = TaggedPtr::null();
178 /// assert!(null_tagged.as_mut_ptr().is_null());
179 /// ```
180 #[inline]
181 pub fn as_mut_ptr(self) -> *mut T {
182 self.ptr.as_mut_ptr()
183 }
184
185 /// Returns `true` if the pointer part is null.
186 ///
187 /// # Examples
188 ///
189 /// ```rust
190 /// use atomic_tagged_ptr::TaggedPtr;
191 ///
192 /// let p: TaggedPtr<i32> = TaggedPtr::null();
193 /// assert!(p.is_null());
194 /// ```
195 #[inline]
196 pub fn is_null(self) -> bool {
197 self.ptr.is_null()
198 }
199
200 /// Returns `true` if the pointer part is not null (is some).
201 ///
202 /// # Examples
203 ///
204 /// ```rust
205 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
206 /// use std::ptr::NonNull;
207 ///
208 /// let val = 42;
209 /// let p = TaggedPtr::new(NonNull::new(&val as *const i32 as *mut i32), Tag::new(10));
210 /// assert!(p.is_some());
211 /// ```
212 #[inline]
213 pub fn is_some(self) -> bool {
214 self.ptr.is_some()
215 }
216
217 /// Returns `true` if the pointer part is null (is none).
218 ///
219 /// # Examples
220 ///
221 /// ```rust
222 /// use atomic_tagged_ptr::TaggedPtr;
223 ///
224 /// let p: TaggedPtr<i32> = TaggedPtr::null();
225 /// assert!(p.is_none());
226 /// ```
227 #[inline]
228 pub fn is_none(self) -> bool {
229 self.ptr.is_none()
230 }
231
232 /// Returns a shared reference to the value if the pointer part is not null.
233 ///
234 /// # Safety
235 ///
236 /// The caller must ensure that:
237 /// * The pointer is valid (aligned, points to a valid initialized value of type `T`).
238 /// * The memory is not mutated while the reference is active.
239 /// * The reference lifetime `'a` is correctly bounded.
240 ///
241 /// # Examples
242 ///
243 /// ```rust
244 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
245 /// use std::ptr::NonNull;
246 ///
247 /// let val = 42;
248 /// let ptr = NonNull::new(&val as *const i32 as *mut i32);
249 /// let tagged = TaggedPtr::new(ptr, Tag::new(1));
250 /// unsafe {
251 /// assert_eq!(tagged.as_ref(), Some(&42));
252 /// }
253 /// ```
254 #[inline]
255 pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
256 unsafe { self.ptr.as_ref() }
257 }
258
259 /// Returns a mutable reference to the value if the pointer part is not null.
260 ///
261 /// # Safety
262 ///
263 /// The caller must ensure that:
264 /// * The pointer is valid (aligned, points to a valid initialized value of type `T`).
265 /// * No other references (shared or mutable) to the same memory are active.
266 /// * The reference lifetime `'a` is correctly bounded.
267 ///
268 /// # Examples
269 ///
270 /// ```rust
271 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
272 /// use std::ptr::NonNull;
273 ///
274 /// let mut val = 42;
275 /// let ptr = NonNull::new(&mut val as *mut i32);
276 /// let tagged = TaggedPtr::new(ptr, Tag::new(1));
277 /// unsafe {
278 /// let r = tagged.as_mut();
279 /// assert_eq!(r, Some(&mut 42));
280 /// *r.unwrap() = 100;
281 /// }
282 /// assert_eq!(val, 100);
283 /// ```
284 #[inline]
285 pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
286 unsafe { self.ptr.as_mut() }
287 }
288
289 /// Returns a new `TaggedPtr` with a different pointer but the same tag.
290 ///
291 /// # Examples
292 ///
293 /// ```rust
294 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
295 /// use std::ptr::NonNull;
296 ///
297 /// let val1 = 10;
298 /// let val2 = 20;
299 /// let ptr1 = NonNull::new(&val1 as *const i32 as *mut i32);
300 /// let ptr2 = NonNull::new(&val2 as *const i32 as *mut i32);
301 ///
302 /// let tagged = TaggedPtr::new(ptr1, Tag::new(100));
303 /// let new_tagged = tagged.with_ptr(ptr2);
304 /// assert_eq!(new_tagged.ptr.option(), ptr2);
305 /// assert_eq!(new_tagged.tag.value(), 100);
306 /// ```
307 #[inline]
308 pub fn with_ptr<U>(self, ptr: impl Into<Ptr<U>>) -> TaggedPtr<U> {
309 TaggedPtr {
310 ptr: ptr.into(),
311 tag: self.tag,
312 }
313 }
314
315 /// Returns a new `TaggedPtr` with a different tag but the same pointer.
316 ///
317 /// # Examples
318 ///
319 /// ```rust
320 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
321 /// use std::ptr::NonNull;
322 ///
323 /// let val = 42;
324 /// let ptr = NonNull::new(&val as *const i32 as *mut i32);
325 ///
326 /// let tagged = TaggedPtr::new(ptr, Tag::new(100));
327 /// let new_tagged = tagged.with_tag(Tag::new(200));
328 /// assert_eq!(new_tagged.ptr.option(), ptr);
329 /// assert_eq!(new_tagged.tag.value(), 200);
330 /// ```
331 #[inline]
332 pub fn with_tag(self, tag: crate::Tag) -> Self {
333 Self { ptr: self.ptr, tag }
334 }
335
336 /// Maps the pointer part of the `TaggedPtr` using the given closure.
337 ///
338 /// # Examples
339 ///
340 /// ```rust
341 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
342 /// use std::ptr::NonNull;
343 ///
344 /// let val = 42u8;
345 /// let ptr = NonNull::new(&val as *const u8 as *mut u8);
346 /// let tagged = TaggedPtr::new(ptr, Tag::new(100));
347 /// let mapped = tagged.map_ptr(|p| p.cast::<i8>());
348 /// assert_eq!(unsafe { *mapped.as_ptr() }, 42);
349 /// assert_eq!(mapped.tag.value(), 100);
350 /// ```
351 #[inline]
352 pub fn map_ptr<U, F>(self, f: F) -> TaggedPtr<U>
353 where
354 F: FnOnce(Ptr<T>) -> Ptr<U>,
355 {
356 TaggedPtr {
357 ptr: f(self.ptr),
358 tag: self.tag,
359 }
360 }
361
362 /// Reads the value from the pointer part without moving it. This leaves the memory unchanged.
363 ///
364 /// # Safety
365 ///
366 /// * The pointer must be non-null.
367 /// * The pointer must be valid for reads (correctly aligned, points to an initialized instance of `T`, etc.).
368 /// * The memory must not be mutated by another thread while being read.
369 ///
370 /// # Examples
371 ///
372 /// ```rust
373 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
374 /// use std::ptr::NonNull;
375 ///
376 /// let val = 42;
377 /// let ptr = NonNull::new(&val as *const i32 as *mut i32);
378 /// let tagged = TaggedPtr::new(ptr, Tag::new(1));
379 /// unsafe {
380 /// assert_eq!(tagged.read(), 42);
381 /// }
382 /// ```
383 #[inline]
384 pub unsafe fn read(self) -> T {
385 // Safety: The caller guarantees the pointer is valid.
386 unsafe { self.ptr.read() }
387 }
388
389 /// Performs a volatile read of the value from the pointer part without moving it.
390 ///
391 /// # Safety
392 ///
393 /// * The pointer must be non-null.
394 /// * The pointer must be valid for reads.
395 /// * The memory must not be mutated by another thread while being read.
396 ///
397 /// # Examples
398 ///
399 /// ```rust
400 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
401 /// use std::ptr::NonNull;
402 ///
403 /// let val = 42;
404 /// let ptr = NonNull::new(&val as *const i32 as *mut i32);
405 /// let tagged = TaggedPtr::new(ptr, Tag::new(1));
406 /// unsafe {
407 /// assert_eq!(tagged.read_volatile(), 42);
408 /// }
409 /// ```
410 #[inline]
411 pub unsafe fn read_volatile(self) -> T {
412 // Safety: The caller guarantees the pointer is valid.
413 unsafe { self.ptr.read_volatile() }
414 }
415
416 /// Reads the value from the pointer part without moving it, without requiring alignment.
417 ///
418 /// # Safety
419 ///
420 /// * The pointer must be non-null.
421 /// * The pointer must be valid for reads.
422 /// * The memory must not be mutated by another thread while being read.
423 ///
424 /// # Examples
425 ///
426 /// ```rust
427 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
428 /// use std::ptr::NonNull;
429 ///
430 /// let val = 42;
431 /// let ptr = NonNull::new(&val as *const i32 as *mut i32);
432 /// let tagged = TaggedPtr::new(ptr, Tag::new(1));
433 /// unsafe {
434 /// assert_eq!(tagged.read_unaligned(), 42);
435 /// }
436 /// ```
437 #[inline]
438 pub unsafe fn read_unaligned(self) -> T {
439 // Safety: The caller guarantees the pointer is valid.
440 unsafe { self.ptr.read_unaligned() }
441 }
442
443 /// Overwrites the memory location at the pointer part with the given value.
444 ///
445 /// # Safety
446 ///
447 /// * The pointer must be non-null.
448 /// * The pointer must be valid for writes (correctly aligned, etc.).
449 ///
450 /// # Examples
451 ///
452 /// ```rust
453 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
454 /// use std::ptr::NonNull;
455 ///
456 /// let mut val = 0;
457 /// let ptr = NonNull::new(&mut val as *mut i32);
458 /// let tagged = TaggedPtr::new(ptr, Tag::new(1));
459 /// unsafe {
460 /// tagged.write(42);
461 /// }
462 /// assert_eq!(val, 42);
463 /// ```
464 #[inline]
465 pub unsafe fn write(self, val: T) {
466 // Safety: The caller guarantees the pointer is valid.
467 unsafe { self.ptr.write(val) }
468 }
469
470 /// Performs a volatile write to the memory location at the pointer part.
471 ///
472 /// # Safety
473 ///
474 /// * The pointer must be non-null.
475 /// * The pointer must be valid for writes.
476 ///
477 /// # Examples
478 ///
479 /// ```rust
480 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
481 /// use std::ptr::NonNull;
482 ///
483 /// let mut val = 0;
484 /// let ptr = NonNull::new(&mut val as *mut i32);
485 /// let tagged = TaggedPtr::new(ptr, Tag::new(1));
486 /// unsafe {
487 /// tagged.write_volatile(42);
488 /// }
489 /// assert_eq!(val, 42);
490 /// ```
491 #[inline]
492 pub unsafe fn write_volatile(self, val: T) {
493 // Safety: The caller guarantees the pointer is valid.
494 unsafe { self.ptr.write_volatile(val) }
495 }
496
497 /// Overwrites the memory location at the pointer part without requiring alignment.
498 ///
499 /// # Safety
500 ///
501 /// * The pointer must be non-null.
502 /// * The pointer must be valid for writes.
503 ///
504 /// # Examples
505 ///
506 /// ```rust
507 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
508 /// use std::ptr::NonNull;
509 ///
510 /// let mut val = 0;
511 /// let ptr = NonNull::new(&mut val as *mut i32);
512 /// let tagged = TaggedPtr::new(ptr, Tag::new(1));
513 /// unsafe {
514 /// tagged.write_unaligned(42);
515 /// }
516 /// assert_eq!(val, 42);
517 /// ```
518 #[inline]
519 pub unsafe fn write_unaligned(self, val: T) {
520 // Safety: The caller guarantees the pointer is valid.
521 unsafe { self.ptr.write_unaligned(val) }
522 }
523
524 /// Replaces the value at the pointer part with `val`, returning the old value.
525 ///
526 /// # Safety
527 ///
528 /// * The pointer must be non-null.
529 /// * The pointer must be valid for reads and writes.
530 ///
531 /// # Examples
532 ///
533 /// ```rust
534 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
535 /// use std::ptr::NonNull;
536 ///
537 /// let mut val = 10;
538 /// let ptr = NonNull::new(&mut val as *mut i32);
539 /// let tagged = TaggedPtr::new(ptr, Tag::new(1));
540 /// unsafe {
541 /// let old = tagged.replace(20);
542 /// assert_eq!(old, 10);
543 /// }
544 /// assert_eq!(val, 20);
545 /// ```
546 #[inline]
547 pub unsafe fn replace(self, val: T) -> T {
548 // Safety: The caller guarantees the pointer is valid.
549 unsafe { self.ptr.replace(val) }
550 }
551
552 /// Swaps the values at the pointer part of `self` and `with`.
553 ///
554 /// # Safety
555 ///
556 /// * Both pointers must be non-null.
557 /// * Both pointers must be valid for reads and writes.
558 /// * Both pointers must be properly aligned.
559 ///
560 /// # Examples
561 ///
562 /// ```rust
563 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
564 /// use std::ptr::NonNull;
565 ///
566 /// let mut val1 = 10;
567 /// let mut val2 = 20;
568 /// let ptr1 = NonNull::new(&mut val1 as *mut i32);
569 /// let ptr2 = NonNull::new(&mut val2 as *mut i32);
570 /// let tagged1 = TaggedPtr::new(ptr1, Tag::new(1));
571 /// let tagged2 = TaggedPtr::new(ptr2, Tag::new(2));
572 /// unsafe {
573 /// tagged1.swap(tagged2);
574 /// }
575 /// assert_eq!(val1, 20);
576 /// assert_eq!(val2, 10);
577 /// ```
578 #[inline]
579 pub unsafe fn swap(self, with: TaggedPtr<T>) {
580 // Safety: The caller guarantees both pointers are valid.
581 unsafe { self.ptr.swap(with.ptr) }
582 }
583
584 /// Copies `count` items from the pointer part of `self` to `dest`. The regions may overlap.
585 ///
586 /// # Safety
587 ///
588 /// * Both pointers must be non-null.
589 /// * Both pointers must be valid for reads and writes.
590 /// * Both pointers must be properly aligned.
591 ///
592 /// # Examples
593 ///
594 /// ```rust
595 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
596 /// use std::ptr::NonNull;
597 ///
598 /// let mut arr = [1, 2, 3];
599 /// let ptr1 = NonNull::new(&mut arr[0] as *mut i32);
600 /// let ptr2 = NonNull::new(&mut arr[1] as *mut i32);
601 /// let tagged1 = TaggedPtr::new(ptr1, Tag::new(1));
602 /// let tagged2 = TaggedPtr::new(ptr2, Tag::new(2));
603 /// unsafe {
604 /// tagged1.copy_to(tagged2, 2);
605 /// }
606 /// assert_eq!(arr, [1, 1, 2]);
607 /// ```
608 #[inline]
609 pub unsafe fn copy_to(self, dest: TaggedPtr<T>, count: usize) {
610 // Safety: The caller guarantees the pointers are valid.
611 unsafe { self.ptr.copy_to(dest.ptr, count) }
612 }
613
614 /// Copies `count` items from the pointer part of `self` to `dest`. The regions must not overlap.
615 ///
616 /// # Safety
617 ///
618 /// * Both pointers must be non-null.
619 /// * Both pointers must be valid for reads and writes.
620 /// * Both pointers must be properly aligned.
621 /// * The memory regions must not overlap.
622 ///
623 /// # Examples
624 ///
625 /// ```rust
626 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
627 /// use std::ptr::NonNull;
628 ///
629 /// let mut arr1 = [1, 2, 3];
630 /// let mut arr2 = [0, 0, 0];
631 /// let ptr1 = NonNull::new(&mut arr1[0] as *mut i32);
632 /// let ptr2 = NonNull::new(&mut arr2[0] as *mut i32);
633 /// let tagged1 = TaggedPtr::new(ptr1, Tag::new(1));
634 /// let tagged2 = TaggedPtr::new(ptr2, Tag::new(2));
635 /// unsafe {
636 /// tagged1.copy_to_nonoverlapping(tagged2, 3);
637 /// }
638 /// assert_eq!(arr2, [1, 2, 3]);
639 /// ```
640 #[inline]
641 pub unsafe fn copy_to_nonoverlapping(self, dest: TaggedPtr<T>, count: usize) {
642 // Safety: The caller guarantees the pointers are valid.
643 unsafe { self.ptr.copy_to_nonoverlapping(dest.ptr, count) }
644 }
645
646 /// Copies `count` items from `src` to the pointer part of `self`. The regions may overlap.
647 ///
648 /// # Safety
649 ///
650 /// * Both pointers must be non-null.
651 /// * Both pointers must be valid for reads and writes.
652 /// * Both pointers must be properly aligned.
653 ///
654 /// # Examples
655 ///
656 /// ```rust
657 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
658 /// use std::ptr::NonNull;
659 ///
660 /// let mut arr = [1, 2, 3];
661 /// let ptr1 = NonNull::new(&mut arr[1] as *mut i32);
662 /// let ptr2 = NonNull::new(&mut arr[0] as *mut i32);
663 /// let tagged1 = TaggedPtr::new(ptr1, Tag::new(1));
664 /// let tagged2 = TaggedPtr::new(ptr2, Tag::new(2));
665 /// unsafe {
666 /// tagged1.copy_from(tagged2, 2);
667 /// }
668 /// assert_eq!(arr, [1, 1, 2]);
669 /// ```
670 #[inline]
671 pub unsafe fn copy_from(self, src: TaggedPtr<T>, count: usize) {
672 // Safety: The caller guarantees the pointers are valid.
673 unsafe { self.ptr.copy_from(src.ptr, count) }
674 }
675
676 /// Copies `count` items from `src` to the pointer part of `self`. The regions must not overlap.
677 ///
678 /// # Safety
679 ///
680 /// * Both pointers must be non-null.
681 /// * Both pointers must be valid for reads and writes.
682 /// * Both pointers must be properly aligned.
683 /// * The memory regions must not overlap.
684 ///
685 /// # Examples
686 ///
687 /// ```rust
688 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
689 /// use std::ptr::NonNull;
690 ///
691 /// let mut arr1 = [1, 2, 3];
692 /// let mut arr2 = [0, 0, 0];
693 /// let ptr1 = NonNull::new(&mut arr2[0] as *mut i32);
694 /// let ptr2 = NonNull::new(&mut arr1[0] as *mut i32);
695 /// let tagged1 = TaggedPtr::new(ptr1, Tag::new(1));
696 /// let tagged2 = TaggedPtr::new(ptr2, Tag::new(2));
697 /// unsafe {
698 /// tagged1.copy_from_nonoverlapping(tagged2, 3);
699 /// }
700 /// assert_eq!(arr2, [1, 2, 3]);
701 /// ```
702 #[inline]
703 pub unsafe fn copy_from_nonoverlapping(self, src: TaggedPtr<T>, count: usize) {
704 // Safety: The caller guarantees the pointers are valid.
705 unsafe { self.ptr.copy_from_nonoverlapping(src.ptr, count) }
706 }
707
708 /// Calculates the offset from the pointer part, returning a new `TaggedPtr` with the same tag.
709 ///
710 /// # Safety
711 ///
712 /// Both the starting and resulting pointer must be either in bounds or one byte past the end of the same allocated object.
713 ///
714 /// # Examples
715 ///
716 /// ```rust
717 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
718 /// use std::ptr::NonNull;
719 ///
720 /// let mut arr = [10, 20, 30];
721 /// let ptr = NonNull::new(&mut arr[0] as *mut i32);
722 /// let tagged = TaggedPtr::new(ptr, Tag::new(123));
723 /// unsafe {
724 /// let offset_tagged = tagged.offset(1);
725 /// assert_eq!(offset_tagged.read(), 20);
726 /// assert_eq!(offset_tagged.tag.value(), 123);
727 /// }
728 /// ```
729 #[inline]
730 pub unsafe fn offset(self, count: isize) -> Self {
731 Self {
732 ptr: unsafe { self.ptr.offset(count) },
733 tag: self.tag,
734 }
735 }
736
737 /// Calculates the positive offset from the pointer part, returning a new `TaggedPtr` with the same tag.
738 ///
739 /// # Safety
740 ///
741 /// Both the starting and resulting pointer must be either in bounds or one byte past the end of the same allocated object.
742 ///
743 /// # Examples
744 ///
745 /// ```rust
746 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
747 /// use std::ptr::NonNull;
748 ///
749 /// let mut arr = [10, 20, 30];
750 /// let ptr = NonNull::new(&mut arr[0] as *mut i32);
751 /// let tagged = TaggedPtr::new(ptr, Tag::new(123));
752 /// unsafe {
753 /// let offset_tagged = tagged.add(2);
754 /// assert_eq!(offset_tagged.read(), 30);
755 /// assert_eq!(offset_tagged.tag.value(), 123);
756 /// }
757 /// ```
758 #[inline]
759 pub unsafe fn add(self, count: usize) -> Self {
760 Self {
761 ptr: unsafe { self.ptr.add(count) },
762 tag: self.tag,
763 }
764 }
765
766 /// Calculates the negative offset from the pointer part, returning a new `TaggedPtr` with the same tag.
767 ///
768 /// # Safety
769 ///
770 /// Both the starting and resulting pointer must be either in bounds or one byte past the end of the same allocated object.
771 ///
772 /// # Examples
773 ///
774 /// ```rust
775 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
776 /// use std::ptr::NonNull;
777 ///
778 /// let mut arr = [10, 20, 30];
779 /// let ptr = NonNull::new(&mut arr[2] as *mut i32);
780 /// let tagged = TaggedPtr::new(ptr, Tag::new(123));
781 /// unsafe {
782 /// let offset_tagged = tagged.sub(1);
783 /// assert_eq!(offset_tagged.read(), 20);
784 /// assert_eq!(offset_tagged.tag.value(), 123);
785 /// }
786 /// ```
787 #[inline]
788 pub unsafe fn sub(self, count: usize) -> Self {
789 Self {
790 ptr: unsafe { self.ptr.sub(count) },
791 tag: self.tag,
792 }
793 }
794
795 /// Calculates the wrapping offset from the pointer part, returning a new `TaggedPtr` with the same tag.
796 ///
797 /// # Examples
798 ///
799 /// ```rust
800 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
801 /// use std::ptr::NonNull;
802 ///
803 /// let mut arr = [10, 20, 30];
804 /// let ptr = NonNull::new(&mut arr[0] as *mut i32);
805 /// let tagged = TaggedPtr::new(ptr, Tag::new(123));
806 /// let offset_tagged = tagged.wrapping_offset(1);
807 /// assert_eq!(unsafe { offset_tagged.read() }, 20);
808 /// assert_eq!(offset_tagged.tag.value(), 123);
809 /// ```
810 #[inline]
811 pub fn wrapping_offset(self, count: isize) -> Self {
812 Self {
813 ptr: self.ptr.wrapping_offset(count),
814 tag: self.tag,
815 }
816 }
817
818 /// Calculates the positive wrapping offset from the pointer part, returning a new `TaggedPtr` with the same tag.
819 ///
820 /// # Examples
821 ///
822 /// ```rust
823 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
824 /// use std::ptr::NonNull;
825 ///
826 /// let mut arr = [10, 20, 30];
827 /// let ptr = NonNull::new(&mut arr[0] as *mut i32);
828 /// let tagged = TaggedPtr::new(ptr, Tag::new(123));
829 /// let offset_tagged = tagged.wrapping_add(2);
830 /// assert_eq!(unsafe { offset_tagged.read() }, 30);
831 /// assert_eq!(offset_tagged.tag.value(), 123);
832 /// ```
833 #[inline]
834 pub fn wrapping_add(self, count: usize) -> Self {
835 Self {
836 ptr: self.ptr.wrapping_add(count),
837 tag: self.tag,
838 }
839 }
840
841 /// Calculates the negative wrapping offset from the pointer part, returning a new `TaggedPtr` with the same tag.
842 ///
843 /// # Examples
844 ///
845 /// ```rust
846 /// use atomic_tagged_ptr::{TaggedPtr, Tag};
847 /// use std::ptr::NonNull;
848 ///
849 /// let mut arr = [10, 20, 30];
850 /// let ptr = NonNull::new(&mut arr[2] as *mut i32);
851 /// let tagged = TaggedPtr::new(ptr, Tag::new(123));
852 /// let offset_tagged = tagged.wrapping_sub(1);
853 /// assert_eq!(unsafe { offset_tagged.read() }, 20);
854 /// assert_eq!(offset_tagged.tag.value(), 123);
855 /// ```
856 #[inline]
857 pub fn wrapping_sub(self, count: usize) -> Self {
858 Self {
859 ptr: self.ptr.wrapping_sub(count),
860 tag: self.tag,
861 }
862 }
863}
864
865impl<T> fmt::Pointer for TaggedPtr<T> {
866 #[inline]
867 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
868 fmt::Pointer::fmt(&self.ptr, f)
869 }
870}
871
872impl<T> PartialOrd for TaggedPtr<T> {
873 #[inline]
874 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
875 Some(self.cmp(other))
876 }
877}
878
879impl<T> Ord for TaggedPtr<T> {
880 #[inline]
881 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
882 match self.ptr.cmp(&other.ptr) {
883 core::cmp::Ordering::Equal => self.tag.cmp(&other.tag),
884 ord => ord,
885 }
886 }
887}
888
889impl<T> From<TaggedPtr<T>> for *const T {
890 #[inline]
891 fn from(tagged: TaggedPtr<T>) -> Self {
892 tagged.as_ptr()
893 }
894}
895
896impl<T> From<TaggedPtr<T>> for *mut T {
897 #[inline]
898 fn from(tagged: TaggedPtr<T>) -> Self {
899 tagged.as_mut_ptr()
900 }
901}
902
903impl<T> fmt::Debug for TaggedPtr<T> {
904 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
905 f.debug_struct("TaggedPtr")
906 .field("ptr", &self.ptr)
907 .field("tag", &self.tag)
908 .finish()
909 }
910}
911
912impl<T> From<(Ptr<T>, crate::Tag)> for TaggedPtr<T> {
913 #[inline]
914 fn from(tuple: (Ptr<T>, crate::Tag)) -> Self {
915 Self {
916 ptr: tuple.0,
917 tag: tuple.1,
918 }
919 }
920}
921
922impl<T> From<(Option<NonNull<T>>, crate::Tag)> for TaggedPtr<T> {
923 #[inline]
924 fn from(tuple: (Option<NonNull<T>>, crate::Tag)) -> Self {
925 Self {
926 ptr: Ptr::new(tuple.0),
927 tag: tuple.1,
928 }
929 }
930}
931
932impl<T> From<(NonNull<T>, crate::Tag)> for TaggedPtr<T> {
933 #[inline]
934 fn from(tuple: (NonNull<T>, crate::Tag)) -> Self {
935 Self {
936 ptr: Ptr::from(tuple.0),
937 tag: tuple.1,
938 }
939 }
940}
941
942impl<T> From<(*const T, crate::Tag)> for TaggedPtr<T> {
943 #[inline]
944 fn from(tuple: (*const T, crate::Tag)) -> Self {
945 Self {
946 ptr: Ptr::from(tuple.0),
947 tag: tuple.1,
948 }
949 }
950}
951
952impl<T> From<(*mut T, crate::Tag)> for TaggedPtr<T> {
953 #[inline]
954 fn from(tuple: (*mut T, crate::Tag)) -> Self {
955 Self {
956 ptr: Ptr::from(tuple.0),
957 tag: tuple.1,
958 }
959 }
960}
961
962impl<T> From<TaggedPtr<T>> for (Ptr<T>, crate::Tag) {
963 #[inline]
964 fn from(tagged: TaggedPtr<T>) -> Self {
965 (tagged.ptr, tagged.tag)
966 }
967}
968
969impl<T> From<TaggedPtr<T>> for Option<NonNull<T>> {
970 #[inline]
971 fn from(tagged: TaggedPtr<T>) -> Self {
972 tagged.ptr.inner
973 }
974}
975
976impl<T> AsRef<Option<NonNull<T>>> for Ptr<T> {
977 #[inline]
978 fn as_ref(&self) -> &Option<NonNull<T>> {
979 &self.inner
980 }
981}
982
983impl<T> AsRef<Ptr<T>> for TaggedPtr<T> {
984 #[inline]
985 fn as_ref(&self) -> &Ptr<T> {
986 &self.ptr
987 }
988}
989
990impl<T> AsRef<crate::Tag> for TaggedPtr<T> {
991 #[inline]
992 fn as_ref(&self) -> &crate::Tag {
993 &self.tag
994 }
995}