pointer_value_pair/
pair.rs1use std::{marker::PhantomData, mem};
2
3#[repr(transparent)]
14#[derive(Debug)]
15pub struct PointerValuePair<T> {
16 repr: usize,
17 _phantom: PhantomData<T>,
18}
19
20impl<T> Copy for PointerValuePair<T> {}
21
22impl<T> Clone for PointerValuePair<T> {
23 fn clone(&self) -> Self {
24 PointerValuePair {
25 repr: self.repr,
26 _phantom: PhantomData,
27 }
28 }
29}
30
31const fn align_bits_mask<T>() -> usize {
32 mem::align_of::<T>() - 1
33}
34
35impl<T> PointerValuePair<T> {
36 pub fn new(ptr: *const T, value: usize) -> PointerValuePair<T> {
43
44 let m = align_bits_mask::<T>();
45 assert!(
46 value <= m,
47 "not enough alignment bits ({}) to store the value ({})",
48 Self::available_bits(),
49 value
50 );
51
52 let mut repr = ptr as usize;
53 repr |= value;
54
55 PointerValuePair {
56 repr,
57 _phantom: PhantomData,
58 }
59 }
60
61 pub const fn available_bits() -> u32 {
63 align_bits_mask::<T>().count_ones()
64 }
65
66 pub const fn max_value() -> usize {
68 align_bits_mask::<T>()
69 }
70
71 pub const fn ptr(self) -> *const T {
73 (self.repr & !align_bits_mask::<T>()) as *const T
74 }
75
76 pub const fn value(self) -> usize {
78 self.repr & align_bits_mask::<T>()
79 }
80}
81
82
83#[cfg(test)]
84mod tests {
85 use std::mem;
86 use super::PointerValuePair;
87
88 #[test]
89 fn pointer_sized() {
90 assert_eq!(mem::size_of::<*const i32>(), mem::size_of::<PointerValuePair<i32>>());
91 }
92
93 #[test]
94 fn basic_get_set() {
95 let pointee = 42usize;
96 let pv = PointerValuePair::new(&pointee, 3);
97 assert_eq!(pv.ptr(), &pointee as *const _);
98 let p_val = unsafe { *pv.ptr() };
99 assert_eq!(p_val, 42usize);
100 assert_eq!(pv.value(), 3);
101 }
102
103 #[test]
104 fn custom_alignments() {
105
106 #[repr(C, align(8))]
107 struct Align8(i32);
108 assert!(PointerValuePair::<Align8>::max_value() >= 0x7);
109 assert!(PointerValuePair::<Align8>::available_bits() >= 3);
110
111 #[repr(C, align(16))]
112 struct Align16(i32);
113 assert!(PointerValuePair::<Align16>::max_value() >= 0xF);
114 assert!(PointerValuePair::<Align16>::available_bits() >= 4);
115
116 #[repr(C, align(32))]
117 struct Align32(i32);
118 assert!(PointerValuePair::<Align32>::max_value() >= 0x1F);
119 assert!(PointerValuePair::<Align32>::available_bits() >= 5);
120 }
121}