1pub const CONTAINER_SENTINEL_BIT: usize = 1;
6
7#[inline]
9pub fn make_sentinel<T, U>(ptr: *mut U) -> *mut T {
10 const {
11 assert!(
12 core::mem::align_of::<T>() > 1,
13 "Type T must have alignment > 1 to be used with sentinel pointers"
14 )
15 };
16 ptr.map_addr(|addr| addr | CONTAINER_SENTINEL_BIT).cast()
17}
18
19#[inline]
21pub const fn make_sentinel_null<T>() -> *mut T {
22 assert!(
24 core::mem::align_of::<T>() > 1,
25 "Type T must have alignment > 1 to be used with sentinel pointers"
26 );
27 core::ptr::without_provenance_mut(CONTAINER_SENTINEL_BIT)
28}
29
30#[inline]
32pub fn unmake_sentinel<T, U>(sentinel: *mut U) -> *mut T {
33 const {
34 assert!(
35 core::mem::align_of::<T>() > 1,
36 "Type T must have alignment > 1 to be used with sentinel pointers"
37 )
38 };
39 sentinel.map_addr(|addr| addr & !CONTAINER_SENTINEL_BIT).cast()
40}
41
42#[inline]
44pub fn is_sentinel_ptr<T>(ptr: *const T) -> bool {
45 const {
46 assert!(
47 core::mem::align_of::<T>() > 1,
48 "Type T must have alignment > 1 to be used with sentinel pointers"
49 )
50 };
51 (ptr.addr() & CONTAINER_SENTINEL_BIT) != 0
52}
53
54#[inline]
57pub fn valid_sentinel_ptr<T>(ptr: *const T) -> bool {
58 const {
59 assert!(
60 core::mem::align_of::<T>() > 1,
61 "Type T must have alignment > 1 to be used with sentinel pointers"
62 )
63 };
64 !ptr.is_null() && !is_sentinel_ptr(ptr)
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn test_sentinel_machinery() {
73 let mut value = 42;
74 let ptr = &mut value as *mut i32;
75
76 assert!(!is_sentinel_ptr(ptr));
77 assert!(valid_sentinel_ptr(ptr));
78
79 let sent = make_sentinel::<i32, i32>(ptr);
80 assert!(is_sentinel_ptr(sent));
81 assert!(!valid_sentinel_ptr(sent));
82
83 let unmasked = unmake_sentinel::<i32, i32>(sent);
84 assert_eq!(unmasked, ptr);
85 assert!(!is_sentinel_ptr(unmasked));
86 assert!(valid_sentinel_ptr(unmasked));
87
88 let null_sent = make_sentinel_null::<i32>();
89 assert!(is_sentinel_ptr(null_sent));
90 assert!(!valid_sentinel_ptr(null_sent));
91 assert_eq!(null_sent as usize, 1);
92
93 let unmasked_null = unmake_sentinel::<i32, i32>(null_sent);
94 assert!(unmasked_null.is_null());
95 }
96}