1use std::cmp::*;
2use std::fmt;
3static mut PAGE_SIZE: usize = 0;
4static mut PAGE_SIZE_BITS: usize = 0;
5
6pub fn page_size() -> usize {
7 let result = unsafe { PAGE_SIZE };
8
9 if result != 0 {
10 return result;
11 }
12
13 init_page_size();
14
15 unsafe { PAGE_SIZE }
16}
17
18pub fn page_size_bits() -> usize {
19 let result = unsafe { PAGE_SIZE_BITS };
20
21 if result != 0 {
22 return result;
23 }
24
25 init_page_size();
26
27 unsafe { PAGE_SIZE_BITS }
28}
29
30fn init_page_size() {
31 unsafe {
32 PAGE_SIZE = determine_page_size();
33 assert!((PAGE_SIZE & (PAGE_SIZE - 1)) == 0);
34
35 PAGE_SIZE_BITS = log2(PAGE_SIZE);
36 }
37}
38
39pub fn map_gc_mem() -> Address {
40 commit(memory_limit(), false)
41}
42
43#[cfg(target_family = "unix")]
44pub fn memory_limit() -> usize {
45 unsafe {
46 use libc::*;
47 sysconf(_SC_PHYS_PAGES) as usize * sysconf(_SC_PAGESIZE) as usize
48 }
49}
50
51#[cfg(target_family = "windows")]
52pub(crate) fn memory_limit() -> usize {
53 unimplemented!()
54}
55
56#[cfg(target_family = "unix")]
57fn determine_page_size() -> usize {
58 let val = unsafe { libc::sysconf(libc::_SC_PAGESIZE) };
59
60 if val <= 0 {
61 panic!("could not determine page size.");
62 }
63
64 val as usize
65}
66
67#[cfg(target_family = "windows")]
68fn determine_page_size() -> usize {
69 use winapi::um::sysinfoapi::{GetSystemInfo, LPSYSTEM_INFO, SYSTEM_INFO};
70
71 unsafe {
72 let mut system_info: SYSTEM_INFO = std::mem::zeroed();
73 GetSystemInfo(&mut system_info as LPSYSTEM_INFO);
74
75 system_info.dwPageSize as usize
76 }
77}
78
79fn log2(mut val: usize) -> usize {
81 let mut log = 0;
82 assert!(val <= u32::max_value() as usize);
83
84 if (val & 0xFFFF0000) != 0 {
85 val >>= 16;
86 log += 16;
87 }
88 if val >= 256 {
89 val >>= 8;
90 log += 8;
91 }
92 if val >= 16 {
93 val >>= 4;
94 log += 4;
95 }
96 if val >= 4 {
97 val >>= 2;
98 log += 2;
99 }
100
101 log + (val >> 1)
102}
103
104#[test]
105fn test_log2() {
106 for i in 0..32 {
107 assert_eq!(i, log2(1 << i));
108 }
109}
110use std::i32;
111use std::mem::size_of;
112#[inline(always)]
115pub fn ptr_width() -> i32 {
116 size_of::<*const u8>() as i32
117}
118
119#[inline(always)]
120pub fn ptr_width_usize() -> usize {
121 size_of::<*const u8>() as usize
122}
123
124pub fn is_page_aligned(val: usize) -> bool {
126 let align = page_size_bits();
127
128 val == ((val >> align) << align)
131}
132
133#[test]
134fn test_is_page_aligned() {
135 let p = page_size();
136
137 assert_eq!(false, is_page_aligned(1));
138 assert_eq!(false, is_page_aligned(2));
139 assert_eq!(false, is_page_aligned(64));
140 assert_eq!(true, is_page_aligned(p));
141 assert_eq!(true, is_page_aligned(2 * p));
142 assert_eq!(true, is_page_aligned(3 * p));
143}
144
145pub fn page_align(val: usize) -> usize {
147 let align = page_size_bits();
148
149 ((val + (1 << align) - 1) >> align) << align
152}
153
154#[test]
155fn test_page_align() {
156 let p = page_size();
157
158 assert_eq!(p, page_align(1));
159 assert_eq!(p, page_align(p - 1));
160 assert_eq!(p, page_align(p));
161 assert_eq!(2 * p, page_align(p + 1));
162}
163
164pub fn align(value: u32, align: u32) -> u32 {
167 if align == 0 {
168 return value;
169 }
170
171 ((value + align - 1) / align) * align
172}
173
174pub fn align_i32(value: i32, align: i32) -> i32 {
177 if align == 0 {
178 return value;
179 }
180
181 ((value + align - 1) / align) * align
182}
183
184pub fn align_usize(value: usize, align: usize) -> usize {
187 if align == 0 {
188 return value;
189 }
190
191 ((value + align - 1) / align) * align
192}
193
194pub fn is_aligned(value: usize, align: usize) -> bool {
197 align_usize(value, align) == value
198}
199
200pub fn fits_u8(value: i64) -> bool {
202 0 <= value && value <= 255
203}
204
205pub fn fits_i32(value: i64) -> bool {
207 i32::MIN as i64 <= value && value <= i32::MAX as i64
208}
209use super::*;
210use std::ptr;
211#[cfg(test)]
212mod tests {
213 use super::*;
214
215 #[test]
216 fn test_fits_u8() {
217 assert_eq!(true, fits_u8(0));
218 assert_eq!(true, fits_u8(255));
219 assert_eq!(false, fits_u8(256));
220 assert_eq!(false, fits_u8(-1));
221 }
222
223 #[test]
224 fn test_fits_i32() {
225 assert_eq!(true, fits_i32(0));
226 assert_eq!(true, fits_i32(i32::MAX as i64));
227 assert_eq!(true, fits_i32(i32::MIN as i64));
228 assert_eq!(false, fits_i32(i32::MAX as i64 + 1));
229 assert_eq!(false, fits_i32(i32::MIN as i64 - 1));
230 }
231}
232
233#[cfg(target_family = "unix")]
234pub fn reserve(size: usize) -> Address {
235 debug_assert!(mem::is_page_aligned(size));
236
237 let ptr = unsafe {
238 libc::mmap(
239 ptr::null_mut(),
240 size,
241 libc::PROT_NONE,
242 libc::MAP_PRIVATE | libc::MAP_ANON | libc::MAP_NORESERVE,
243 -1,
244 0,
245 ) as *mut libc::c_void
246 };
247
248 if ptr == libc::MAP_FAILED {
249 panic!("reserving memory with mmap() failed");
250 }
251
252 Address::from_ptr(ptr)
253}
254
255#[cfg(target_family = "windows")]
256pub fn reserve(size: usize) -> Address {
257 debug_assert!(mem::is_page_aligned(size));
258
259 use kernel32::VirtualAlloc;
260 use winapi::um::winnt::{MEM_RESERVE, PAGE_NOACCESS};
261
262 let ptr = unsafe { VirtualAlloc(ptr::null_mut(), size as u64, MEM_RESERVE, PAGE_NOACCESS) };
263
264 if ptr.is_null() {
265 panic!("VirtualAlloc failed");
266 }
267
268 Address::from_ptr(ptr)
269}
270
271pub fn reserve_align(size: usize, align: usize) -> Address {
272 debug_assert!(mem::is_page_aligned(size));
273 debug_assert!(mem::is_page_aligned(align));
274
275 let align_minus_page = align - page_size();
276
277 let unaligned = reserve(size + align_minus_page);
278 let aligned: Address = mem::align_usize(unaligned.to_usize(), align).into();
279
280 let gap_start = aligned.offset_from(unaligned);
281 let gap_end = align_minus_page - gap_start;
282
283 if gap_start > 0 {
284 uncommit(unaligned, gap_start);
285 }
286
287 if gap_end > 0 {
288 uncommit(aligned.offset(size), gap_end);
289 }
290
291 aligned
292}
293
294#[cfg(target_family = "unix")]
295pub fn commit(size: usize, executable: bool) -> Address {
296 debug_assert!(mem::is_page_aligned(size));
297
298 let mut prot = libc::PROT_READ | libc::PROT_WRITE;
299
300 if executable {
301 prot |= libc::PROT_EXEC;
302 }
303
304 let ptr = unsafe {
305 libc::mmap(
306 ptr::null_mut(),
307 size,
308 prot,
309 libc::MAP_PRIVATE | libc::MAP_ANON,
310 -1,
311 0,
312 )
313 };
314
315 if ptr == libc::MAP_FAILED {
316 panic!("committing memory with mmap() failed");
317 }
318
319 Address::from_ptr(ptr)
320}
321
322#[cfg(target_family = "windows")]
323pub fn commit(size: usize, executable: bool) -> Address {
324 debug_assert!(mem::is_page_aligned(size));
325
326 use kernel32::VirtualAlloc;
327 use winapi::um::winnt::{MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READWRITE, PAGE_READWRITE};
328
329 let prot = if executable {
330 PAGE_EXECUTE_READWRITE
331 } else {
332 PAGE_READWRITE
333 };
334
335 let ptr = unsafe { VirtualAlloc(ptr::null_mut(), size as u64, MEM_COMMIT | MEM_RESERVE, prot) };
336
337 if ptr.is_null() {
338 panic!("VirtualAlloc failed");
339 }
340
341 Address::from_ptr(ptr)
342}
343
344#[cfg(target_family = "unix")]
345pub fn commit_at(ptr: Address, size: usize, executable: bool) {
346 debug_assert!(ptr.is_page_aligned());
347 debug_assert!(mem::is_page_aligned(size));
348
349 let mut prot = libc::PROT_READ | libc::PROT_WRITE;
350
351 if executable {
352 prot |= libc::PROT_EXEC;
353 }
354
355 let val = unsafe {
356 libc::mmap(
357 ptr.to_mut_ptr(),
358 size,
359 prot,
360 libc::MAP_PRIVATE | libc::MAP_ANON | libc::MAP_FIXED,
361 -1,
362 0,
363 )
364 };
365
366 if val == libc::MAP_FAILED {
367 panic!("committing memory with mmap() failed");
368 }
369}
370
371#[cfg(target_family = "windows")]
372pub fn commit_at(ptr: Address, size: usize, executable: bool) {
373 debug_assert!(ptr.is_page_aligned());
374 debug_assert!(mem::is_page_aligned(size));
375
376 use kernel32::VirtualAlloc;
377 use winapi::um::winnt::{MEM_COMMIT, PAGE_EXECUTE_READWRITE, PAGE_READWRITE};
378
379 let prot = if executable {
380 PAGE_EXECUTE_READWRITE
381 } else {
382 PAGE_READWRITE
383 };
384
385 let result = unsafe { VirtualAlloc(ptr.to_mut_ptr(), size as u64, MEM_COMMIT, prot) };
386
387 if result != ptr.to_mut_ptr() {
388 panic!("VirtualAlloc failed");
389 }
390}
391
392#[cfg(target_family = "unix")]
393pub fn uncommit(ptr: Address, size: usize) {
394 debug_assert!(ptr.is_page_aligned());
395 debug_assert!(mem::is_page_aligned(size));
396
397 let val = unsafe {
398 libc::mmap(
399 ptr.to_mut_ptr(),
400 size,
401 libc::PROT_NONE,
402 libc::MAP_PRIVATE | libc::MAP_ANON | libc::MAP_NORESERVE,
403 -1,
404 0,
405 )
406 };
407
408 if val == libc::MAP_FAILED {
409 panic!("uncommitting memory with mmap() failed");
410 }
411}
412
413#[cfg(target_family = "windows")]
414pub fn uncommit(ptr: Address, size: usize) {
415 debug_assert!(ptr.is_page_aligned());
416 debug_assert!(mem::is_page_aligned(size));
417
418 use kernel32::VirtualFree;
419 use winapi::um::winnt::MEM_RELEASE;
420
421 let _ = unsafe { VirtualFree(ptr.to_mut_ptr(), size as _, MEM_RELEASE) };
422}
423
424#[cfg(target_family = "unix")]
425pub fn discard(ptr: Address, size: usize) {
426 debug_assert!(ptr.is_page_aligned());
427 debug_assert!(mem::is_page_aligned(size));
428
429 let res = unsafe { libc::madvise(ptr.to_mut_ptr(), size, libc::MADV_DONTNEED) };
430
431 if res != 0 {
432 panic!("discarding memory with madvise() failed");
433 }
434
435 let res = unsafe { libc::mprotect(ptr.to_mut_ptr(), size, libc::PROT_NONE) };
436
437 if res != 0 {
438 panic!("discarding memory with mprotect() failed");
439 }
440}
441
442#[cfg(target_family = "windows")]
443pub fn discard(ptr: Address, size: usize) {
444 debug_assert!(ptr.is_page_aligned());
445 debug_assert!(mem::is_page_aligned(size));
446
447 use kernel32::VirtualFree;
448 use winapi::um::winnt::MEM_DECOMMIT;
449
450 let _ = unsafe { VirtualFree(ptr.to_mut_ptr(), size as u64, MEM_DECOMMIT) };
451}
452
453#[cfg(target_family = "unix")]
454pub fn protect(start: Address, size: usize, access: Access) {
455 debug_assert!(start.is_page_aligned());
456 debug_assert!(mem::is_page_aligned(size));
457
458 if access.is_none() {
459 discard(start, size);
460 return;
461 }
462
463 let protection = match access {
464 Access::None => unreachable!(),
465 Access::Read => libc::PROT_READ,
466 Access::ReadWrite => libc::PROT_READ | libc::PROT_WRITE,
467 Access::ReadExecutable => libc::PROT_READ | libc::PROT_EXEC,
468 Access::ReadWriteExecutable => libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC,
469 };
470
471 let res = unsafe { libc::mprotect(start.to_mut_ptr(), size, protection) };
472
473 if res != 0 {
474 panic!("mprotect() failed");
475 }
476}
477
478#[cfg(target_family = "windows")]
479pub fn protect(start: Address, size: usize, access: Access) {
480 debug_assert!(start.is_page_aligned());
481 debug_assert!(mem::is_page_aligned(size));
482
483 use kernel32::VirtualAlloc;
484 use winapi::um::winnt::{
485 MEM_COMMIT, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_READONLY, PAGE_READWRITE,
486 };
487
488 if access.is_none() {
489 discard(start, size);
490 return;
491 }
492
493 let protection = match access {
494 Access::None => unreachable!(),
495 Access::Read => PAGE_READONLY,
496 Access::ReadWrite => PAGE_READWRITE,
497 Access::ReadExecutable => PAGE_EXECUTE_READ,
498 Access::ReadWriteExecutable => PAGE_EXECUTE_READWRITE,
499 };
500
501 let ptr = unsafe { VirtualAlloc(start.to_mut_ptr(), size as u64, MEM_COMMIT, protection) };
502
503 if ptr.is_null() {
504 panic!("VirtualAlloc failed");
505 }
506}
507
508pub enum Access {
509 None,
510 Read,
511 ReadWrite,
512 ReadExecutable,
513 ReadWriteExecutable,
514}
515
516impl Access {
517 fn is_none(&self) -> bool {
518 match self {
519 Access::None => true,
520 _ => false,
521 }
522 }
523}
524
525#[derive(Copy, Clone, PartialEq, Eq, Hash)]
526pub struct Address(usize);
527
528impl Address {
529 pub fn deref(self) -> Self {
530 unsafe { *(self.offset(0).to_mut_ptr::<Self>()) }
531 }
532
533 #[inline(always)]
534 pub fn from(val: usize) -> Address {
535 Address(val)
536 }
537
538 #[inline(always)]
539 pub fn region_start(self, size: usize) -> Region {
540 Region::new(self, self.offset(size))
541 }
542
543 #[inline(always)]
544 pub fn offset_from(self, base: Address) -> usize {
545 debug_assert!(self >= base);
546
547 self.to_usize() - base.to_usize()
548 }
549
550 #[inline(always)]
551 pub fn offset(self, offset: usize) -> Address {
552 Address(self.0 + offset)
553 }
554
555 #[inline(always)]
556 pub fn sub(self, offset: usize) -> Address {
557 Address(self.0 - offset)
558 }
559
560 #[inline(always)]
561 pub fn add_ptr(self, words: usize) -> Address {
562 Address(self.0 + words * mem::ptr_width_usize())
563 }
564
565 #[inline(always)]
566 pub fn sub_ptr(self, words: usize) -> Address {
567 Address(self.0 - words * mem::ptr_width_usize())
568 }
569
570 #[inline(always)]
571 pub fn to_usize(self) -> usize {
572 self.0
573 }
574
575 #[inline(always)]
576 pub fn from_ptr<T>(ptr: *const T) -> Address {
577 Address(ptr as usize)
578 }
579
580 #[inline(always)]
581 pub fn to_ptr<T>(&self) -> *const T {
582 self.0 as *const T
583 }
584
585 #[inline(always)]
586 pub fn to_mut_ptr<T>(&self) -> *mut T {
587 self.0 as *const T as *mut T
588 }
589
590 #[inline(always)]
591 pub fn null() -> Address {
592 Address(0)
593 }
594
595 #[inline(always)]
596 pub fn is_null(self) -> bool {
597 self.0 == 0
598 }
599
600 #[inline(always)]
601 pub fn is_non_null(self) -> bool {
602 self.0 != 0
603 }
604
605 #[inline(always)]
606 pub fn align_page(self) -> Address {
607 mem::page_align(self.to_usize()).into()
608 }
609
610 #[inline(always)]
611 pub fn align_page_down(self) -> Address {
612 Address(self.0 & !(mem::page_size() - 1))
613 }
614
615 #[inline(always)]
616 pub fn is_page_aligned(self) -> bool {
617 mem::is_page_aligned(self.to_usize())
618 }
619
620 #[inline(always)]
621 pub const fn and(self, x: Address) -> Self {
622 Self(self.0 & x.0)
623 }
624
625 #[inline(always)]
626 pub const fn or(self, x: Address) -> Self {
627 Self(self.0 | x.0)
628 }
629}
630
631impl fmt::Display for Address {
632 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
633 write!(f, "0x{:x}", self.to_usize())
634 }
635}
636
637impl fmt::Debug for Address {
638 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
639 write!(f, "0x{:x}", self.to_usize())
640 }
641}
642
643impl PartialOrd for Address {
644 fn partial_cmp(&self, other: &Address) -> Option<std::cmp::Ordering> {
645 Some(self.cmp(other))
646 }
647}
648
649impl Ord for Address {
650 fn cmp(&self, other: &Address) -> std::cmp::Ordering {
651 self.to_usize().cmp(&other.to_usize())
652 }
653}
654
655impl From<usize> for Address {
656 fn from(val: usize) -> Address {
657 Address(val)
658 }
659}
660
661#[derive(Copy, Clone)]
662pub struct Region {
663 pub start: Address,
664 pub end: Address,
665}
666
667impl Region {
668 pub fn new(start: Address, end: Address) -> Region {
669 debug_assert!(start <= end);
670
671 Region { start, end }
672 }
673
674 #[inline(always)]
675 pub fn contains(&self, addr: Address) -> bool {
676 self.start <= addr && addr < self.end
677 }
678
679 #[inline(always)]
680 pub fn valid_top(&self, addr: Address) -> bool {
681 self.start <= addr && addr <= self.end
682 }
683
684 #[inline(always)]
685 pub fn size(&self) -> usize {
686 self.end.to_usize() - self.start.to_usize()
687 }
688
689 #[inline(always)]
690 pub fn empty(&self) -> bool {
691 self.start == self.end
692 }
693
694 #[inline(always)]
695 pub fn disjunct(&self, other: &Region) -> bool {
696 self.end <= other.start || self.start >= other.end
697 }
698
699 #[inline(always)]
700 pub fn overlaps(&self, other: &Region) -> bool {
701 !self.disjunct(other)
702 }
703
704 #[inline(always)]
705 pub fn fully_contains(&self, other: &Region) -> bool {
706 self.contains(other.start) && self.valid_top(other.end)
707 }
708}
709
710impl Default for Region {
711 fn default() -> Region {
712 Region {
713 start: Address::null(),
714 end: Address::null(),
715 }
716 }
717}
718
719impl fmt::Display for Region {
720 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
721 write!(f, "{}-{}", self.start, self.end)
722 }
723}
724
725pub struct FormattedSize {
726 size: usize,
727}
728
729impl fmt::Display for FormattedSize {
730 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
731 let ksize = (self.size as f64) / 1024f64;
732
733 if ksize < 1f64 {
734 return write!(f, "{}B", self.size);
735 }
736
737 let msize = ksize / 1024f64;
738
739 if msize < 1f64 {
740 return write!(f, "{:.1}K", ksize);
741 }
742
743 let gsize = msize / 1024f64;
744
745 if gsize < 1f64 {
746 write!(f, "{:.1}M", msize)
747 } else {
748 write!(f, "{:.1}G", gsize)
749 }
750 }
751}
752
753pub fn formatted_size(size: usize) -> FormattedSize {
754 FormattedSize { size }
755}
756
757#[repr(transparent)]
758pub struct Ptr<T: ?Sized>(pub(crate) *mut T);
759
760impl<T: ?Sized> Ptr<T> {
761 pub fn get(&self) -> &mut T {
762 unsafe { &mut *self.0 }
763 }
764}
765
766impl<T> Ptr<T> {
767 pub fn new(x: T) -> Self {
768 Self(Box::into_raw(Box::new(x)))
769 }
770
771 pub fn from_box(b: Box<T>) -> Self {
772 Self(Box::into_raw(b))
773 }
774
775 pub fn set(&self, val: T) {
776 unsafe { self.0.write(val) };
777 }
778
779 pub fn replace(&self, val: T) -> T {
780 std::mem::replace(self.get(), val)
781 }
782
783 pub fn take(&self) -> T
784 where
785 T: Default,
786 {
787 self.replace(T::default())
788 }
789
790 pub fn is_null(&self) -> bool {
791 self.0.is_null()
792 }
793
794 pub fn null() -> Self {
795 Self(std::ptr::null_mut())
796 }
797}
798
799use std::hash::*;
800
801impl<T> Hash for Ptr<T> {
802 fn hash<H: Hasher>(&self, state: &mut H) {
803 self.0.hash(state);
804 }
805}
806
807impl<T> PartialEq for Ptr<T> {
808 fn eq(&self, other: &Self) -> bool {
809 self.0 == other.0
810 }
811}
812
813impl<T> Eq for Ptr<T> {}
814
815impl<T> Copy for Ptr<T> {}
816impl<T> Clone for Ptr<T> {
817 fn clone(&self) -> Self {
818 *self
819 }
820}
821
822impl<T> std::ops::Deref for Ptr<T> {
823 type Target = T;
824 fn deref(&self) -> &T {
825 self.get()
826 }
827}
828
829unsafe impl<T> Send for Ptr<T> {}
830unsafe impl<T> Sync for Ptr<T> {}
831
832use std::hash::{Hash, Hasher};
833use std::sync::atomic::{AtomicPtr, Ordering};
834
835const UNTAG_MASK: usize = (!0x7) as usize;
837
838pub fn bit_is_set<T>(pointer: *mut T, bit: usize) -> bool {
840 let shifted = 1 << bit;
841
842 (pointer as usize & shifted) == shifted
843}
844
845pub fn with_bit<T>(pointer: *mut T, bit: usize) -> *mut T {
847 (pointer as usize | 1 << bit) as _
848}
849
850pub fn without_bit<T>(pointer: *mut T, bit: usize) -> *mut T {
851 (pointer as usize ^ 1 << bit) as _
852}
853
854pub fn untagged<T>(pointer: *mut T) -> *mut T {
856 (pointer as usize & UNTAG_MASK) as _
857}
858
859#[derive(Debug)]
861#[repr(transparent)]
862pub struct TaggedPointer<T: ?Sized> {
863 pub raw: *mut T,
864}
865
866impl<T> TaggedPointer<T> {
867 pub fn new(raw: *mut T) -> TaggedPointer<T> {
869 TaggedPointer { raw }
870 }
871
872 pub fn with_bit(raw: *mut T, bit: usize) -> TaggedPointer<T> {
874 let mut pointer = Self::new(raw);
875
876 pointer.set_bit(bit);
877
878 pointer
879 }
880
881 pub fn unset_bit(&mut self, bit: usize) {
882 if self.bit_is_set(bit) {
883 self.raw = without_bit(self.raw, bit);
884 }
885 }
886
887 pub const fn null() -> TaggedPointer<T> {
889 TaggedPointer {
890 raw: ptr::null::<T>() as *mut T,
891 }
892 }
893
894 pub fn untagged(self) -> *mut T {
896 self::untagged(self.raw)
897 }
898
899 pub fn without_tags(self) -> Self {
902 Self::new(self.untagged())
903 }
904
905 pub fn bit_is_set(self, bit: usize) -> bool {
907 self::bit_is_set(self.raw, bit)
908 }
909
910 pub fn set_bit(&mut self, bit: usize) {
912 self.raw = with_bit(self.raw, bit);
913 }
914
915 pub fn is_null(self) -> bool {
917 self.untagged().is_null()
918 }
919
920 pub fn as_ref<'a>(self) -> Option<&'a T> {
922 unsafe { self.untagged().as_ref() }
923 }
924
925 pub fn as_mut<'a>(self) -> Option<&'a mut T> {
927 unsafe { self.untagged().as_mut() }
928 }
929
930 #[cfg_attr(feature = "cargo-clippy", allow(clippy::trivially_copy_pass_by_ref))]
934 pub fn compare_and_swap(&self, current: *mut T, other: *mut T) -> bool {
935 self.as_atomic()
936 .compare_and_swap(current, other, Ordering::AcqRel)
937 == current
938 }
939
940 #[cfg_attr(feature = "cargo-clippy", allow(clippy::trivially_copy_pass_by_ref))]
942 pub fn atomic_store(&self, other: *mut T) {
943 self.as_atomic().store(other, Ordering::Release);
944 }
945
946 #[cfg_attr(feature = "cargo-clippy", allow(clippy::trivially_copy_pass_by_ref))]
948 pub fn atomic_load(&self) -> *mut T {
949 self.as_atomic().load(Ordering::Acquire)
950 }
951
952 #[cfg_attr(feature = "cargo-clippy", allow(clippy::trivially_copy_pass_by_ref))]
954 pub fn atomic_bit_is_set(&self, bit: usize) -> bool {
955 Self::new(self.atomic_load()).bit_is_set(bit)
956 }
957
958 fn as_atomic(&self) -> &AtomicPtr<T> {
959 unsafe { &*(self as *const TaggedPointer<T> as *const AtomicPtr<T>) }
960 }
961}
962
963impl<T> PartialEq for TaggedPointer<T> {
964 fn eq(&self, other: &TaggedPointer<T>) -> bool {
965 self.raw == other.raw
966 }
967}
968
969impl<T> Eq for TaggedPointer<T> {}
970
971impl<T> Clone for TaggedPointer<T> {
974 fn clone(&self) -> TaggedPointer<T> {
975 TaggedPointer::new(self.raw)
976 }
977}
978
979impl<T> Copy for TaggedPointer<T> {}
980
981impl<T> Hash for TaggedPointer<T> {
982 fn hash<H: Hasher>(&self, state: &mut H) {
983 self.raw.hash(state);
984 }
985}