1use core::{
2 fmt::{Debug, Formatter, Pointer},
3 marker::PhantomData,
4 ops::Deref,
5};
6
7use crate::{config::PtrCfg, error::PackedPtrError, Packable, TypedPackedPtr};
8
9#[repr(transparent)]
13pub struct PackedRef<'a, T, C: PtrCfg, D: Packable>(TypedPackedPtr<T, C, D>, PhantomData<&'a T>);
14
15impl<'a, T, C: PtrCfg, D: Packable> PackedRef<'a, T, C, D> {
16 pub fn new(ptr: &'a T, data: D, cfg: C) -> Result<Self, PackedPtrError> {
23 Ok(Self(TypedPackedPtr::new(ptr, data, cfg)?, PhantomData))
24 }
25
26 pub unsafe fn new_unchecked(ptr: &'a T, data: D) -> Self {
49 Self(TypedPackedPtr::new_unchecked(ptr, data), PhantomData)
50 }
51
52 fn r#ref(self) -> &'a T {
54 unsafe { &*self.0.ptr() }
56 }
57
58 #[must_use]
60 pub fn data(self) -> D {
61 self.0.data()
62 }
63
64 #[must_use]
66 pub fn get(self) -> (&'a T, D) {
67 (self.r#ref(), self.0.data())
68 }
69
70 pub fn set_data(&mut self, data: D) {
76 self.0.set_data(data);
77 }
78}
79
80impl<T, C: PtrCfg, D: Packable> Deref for PackedRef<'_, T, C, D> {
81 type Target = T;
82
83 fn deref(&self) -> &Self::Target {
84 self.r#ref()
85 }
86}
87
88impl<T, C: PtrCfg, D: Packable> Clone for PackedRef<'_, T, C, D> {
89 fn clone(&self) -> Self {
90 *self
91 }
92}
93
94impl<T, C: PtrCfg, D: Packable> Copy for PackedRef<'_, T, C, D> {}
95
96impl<T: Debug, C: PtrCfg, D: Packable + Debug> Debug for PackedRef<'_, T, C, D> {
97 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
98 f.debug_tuple("PackedRef")
99 .field(&self.r#ref())
100 .field(&self.data())
101 .finish()
102 }
103}
104
105impl<T, C: PtrCfg, D: Packable> Pointer for PackedRef<'_, T, C, D> {
106 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
107 Pointer::fmt(&self.r#ref(), f)
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use crate::config::AlignOnly;
115
116 #[test]
117 fn new() {
118 let data = 0xdead_beef_u32;
119 let packed = (true, false);
120
121 let ok = PackedRef::new(&data, packed, AlignOnly).unwrap();
122
123 assert_eq!(*ok, data);
124 assert_eq!(ok.data(), packed);
125 assert_eq!(ok.get(), (&data, packed));
126
127 let packed = 255u32;
128 let overflow = PackedRef::new(&data, packed, AlignOnly);
129
130 assert!(overflow.is_err());
131 assert!(matches!(
132 overflow.unwrap_err(),
133 PackedPtrError::DataOverflow
134 ));
135 }
136
137 #[test]
138 fn set_data() {
139 let data = 0xdead_beef_u32;
140 let packed = (true, false);
141
142 let mut ref1 = PackedRef::new(&data, packed, AlignOnly).unwrap();
143
144 assert_eq!(*ref1, data);
145 assert_eq!(ref1.data(), packed);
146 assert_eq!(ref1.get(), (&data, packed));
147
148 let new_packed = (false, true);
149 ref1.set_data(new_packed);
150
151 assert_eq!(*ref1, data);
152 assert_eq!(ref1.data(), new_packed);
153 assert_eq!(ref1.get(), (&data, new_packed));
154 }
155}