1#![no_std]
7
8use core::cmp::Ordering;
9use core::fmt;
10use core::hash::{Hash, Hasher};
11use core::marker::PhantomData as marker;
12use core::mem::MaybeUninit;
13use core::ops::Add;
14
15#[repr(transparent)]
24pub struct Offset<Base, Field> {
25 value: u32,
26 marker: marker<*const (Base, Field)>,
27}
28unsafe impl<Base, Field> Send for Offset<Base, Field> {}
29unsafe impl<Base, Field> Sync for Offset<Base, Field> {}
30
31#[macro_export]
36macro_rules! field_ptr {
37 ($base_ptr:ident.$field:ident) => {
38 &(*$base_ptr).$field as *const _
41 };
42}
43
44#[macro_export]
63macro_rules! offset_of {
64 ($ty:ident::$field:ident) => {
65 $crate::offset_of!(<$ty>::$field)
66 };
67 (<$ty:path>::$field:ident) => {{
68 #[inline(always)]
70 const unsafe fn offset<Base, Field>(
71 value: u32,
72 _ptr: *const Field,
73 ) -> $crate::Offset<Base, Field> {
74 $crate::Offset::new_unchecked(value)
75 }
76
77 #[allow(unsafe_code)]
78 #[allow(unused_unsafe)]
79 {
80 unsafe {
81 let _ = |value: &$ty| {
88 let $ty { $field: _, .. } = *value;
89 };
90
91 let uninit = <core::mem::MaybeUninit<$ty>>::uninit();
92 let base_ptr = uninit.as_ptr();
93 let field_ptr = $crate::field_ptr!(base_ptr.$field);
94 offset::<$ty, _>(
95 (field_ptr as *const u8).offset_from(base_ptr as *const u8) as u32,
96 field_ptr,
97 )
98 }
99 }
100 }};
101}
102
103impl<Base, Field> Offset<Base, Field> {
104 #[inline(always)]
111 pub const unsafe fn new_unchecked(value: u32) -> Self {
112 Self { value, marker }
113 }
114
115 #[inline(always)]
117 pub const fn uninit(self) -> Offset<MaybeUninit<Base>, MaybeUninit<Field>> {
118 Offset {
119 value: self.value,
120 marker,
121 }
122 }
123
124 pub const fn as_u32(self) -> u32 {
129 self.value
130 }
131
132 #[inline(always)]
134 pub fn index_in(self, base: &Base) -> &Field {
135 unsafe { &*((base as *const Base as *const u8).add(self.value as usize) as *const Field) }
136 }
137
138 #[inline(always)]
140 pub fn index_mut_in(self, base: &mut Base) -> &mut Field {
141 unsafe { &mut *((base as *mut Base as *mut u8).add(self.value as usize) as *mut Field) }
142 }
143}
144
145impl<A, B, C> Add<Offset<B, C>> for Offset<A, B> {
146 type Output = Offset<A, C>;
147
148 #[inline(always)]
149 fn add(self, other: Offset<B, C>) -> Self::Output {
150 Offset {
151 value: self.value + other.value,
152 marker,
153 }
154 }
155}
156
157impl<Base, Field> Copy for Offset<Base, Field> {}
158impl<Base, Field> Clone for Offset<Base, Field> {
159 #[inline(always)]
160 fn clone(&self) -> Self {
161 *self
162 }
163}
164
165impl<Base, Field> Eq for Offset<Base, Field> {}
166impl<Base, Field> PartialEq for Offset<Base, Field> {
167 #[inline(always)]
168 fn eq(&self, other: &Self) -> bool {
169 self.value == other.value
170 }
171}
172
173impl<Base, Field> PartialEq<&Self> for Offset<Base, Field> {
174 #[inline(always)]
175 fn eq(&self, other: &&Self) -> bool {
176 self == *other
177 }
178}
179
180impl<Base, Field> PartialEq<u32> for Offset<Base, Field> {
181 #[inline(always)]
182 fn eq(&self, other: &u32) -> bool {
183 self.value == *other
184 }
185}
186
187impl<Base, Field> PartialEq<&u32> for Offset<Base, Field> {
188 #[inline(always)]
189 fn eq(&self, other: &&u32) -> bool {
190 self.value == **other
191 }
192}
193
194impl<Base, Field> Ord for Offset<Base, Field> {
195 #[inline(always)]
196 fn cmp(&self, other: &Self) -> Ordering {
197 self.value.cmp(&other.value)
198 }
199}
200
201impl<Base, Field> PartialOrd for Offset<Base, Field> {
202 #[inline(always)]
203 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
204 Some(self.cmp(other))
205 }
206}
207
208impl<Base, Field> PartialOrd<&Self> for Offset<Base, Field> {
209 #[inline(always)]
210 fn partial_cmp(&self, other: &&Self) -> Option<Ordering> {
211 Some(self.cmp(&**other))
212 }
213}
214
215impl<Base, Field> PartialOrd<u32> for Offset<Base, Field> {
216 #[inline(always)]
217 fn partial_cmp(&self, other: &u32) -> Option<Ordering> {
218 self.value.partial_cmp(other)
219 }
220}
221
222impl<Base, Field> PartialOrd<&u32> for Offset<Base, Field> {
223 #[inline(always)]
224 fn partial_cmp(&self, other: &&u32) -> Option<Ordering> {
225 self.value.partial_cmp(other)
226 }
227}
228
229impl<Base, Field> Hash for Offset<Base, Field> {
230 #[inline(always)]
231 fn hash<H>(&self, state: &mut H)
232 where
233 H: Hasher,
234 {
235 self.value.hash(state);
236 }
237}
238
239impl<Base, Field> fmt::Debug for Offset<Base, Field>
240where
241 Base: DescribeOffset,
242{
243 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
244 Base::describe_offset(self.value, fmt)
245 }
246}
247
248pub trait DescribeOffset {
249 fn describe_offset(offset: u32, fmt: &mut fmt::Formatter) -> fmt::Result;
250}
251
252macro_rules! trivial_fmt_impl {
253 ($($t:ident),*) => {
254 $(impl<Base, Field> fmt::$t for Offset<Base, Field> {
255 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
256 self.value.fmt(fmt)
257 }
258 })*
259 }
260}
261trivial_fmt_impl!(Binary, Display, LowerHex, Octal, UpperHex);
262
263impl<Base, Field> From<Offset<Base, Field>> for u32 {
264 #[inline(always)]
265 fn from(offset: Offset<Base, Field>) -> Self {
266 offset.value
267 }
268}