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