const_field_offset/
lib.rs1#![no_std]
12
13#[cfg(test)]
14extern crate alloc;
15
16use core::pin::Pin;
17
18#[doc(inline)]
19pub use const_field_offset_macro::FieldOffsets;
20
21pub use field_offset::{AllowPin, FieldOffset, NotPinned};
22
23pub trait PinnedDrop {
26 fn drop(self: Pin<&mut Self>);
29
30 #[doc(hidden)]
31 fn do_safe_pinned_drop(&mut self) {
32 let p = unsafe { Pin::new_unchecked(self) };
33 p.drop()
34 }
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40 use crate as const_field_offset;
41 #[derive(Debug, FieldOffsets)]
45 #[repr(C)]
46 struct Foo {
47 a: u32,
48 b: f64,
49 c: bool,
50 }
51
52 #[derive(Debug, FieldOffsets)]
53 #[repr(C)]
54 struct Bar {
55 x: u32,
56 y: Foo,
57 }
58
59 #[test]
60 #[allow(clippy::float_cmp)] fn test_simple() {
62 let foo_b = Foo::FIELD_OFFSETS.b;
64
65 let mut x = Foo { a: 1, b: 2.0, c: false };
67
68 {
70 let y = foo_b.apply(&x);
71 assert_eq!(*y, 2.0);
72 }
73
74 {
76 let y = foo_b.apply_mut(&mut x);
77 *y = 42.0;
78 }
79 assert_eq!(x.b, 42.0);
80 }
81
82 #[test]
83 #[allow(clippy::float_cmp)] fn test_nested() {
85 let mut x = Bar { x: 0, y: Foo { a: 1, b: 2.0, c: false } };
87
88 let bar_y_b = Bar::FIELD_OFFSETS.y + Foo::FIELD_OFFSETS.b;
90
91 {
93 let y = bar_y_b.apply_mut(&mut x);
94 *y = 42.0;
95 }
96 assert_eq!(x.y.b, 42.0);
97 }
98
99 #[test]
100 #[allow(clippy::float_cmp)] fn test_pin() {
102 use ::alloc::boxed::Box;
103 let foo_b = Foo::FIELD_OFFSETS.b;
105 let foo_b_pin = unsafe { foo_b.as_pinned_projection() };
106 let foo_object = Box::pin(Foo { a: 21, b: 22.0, c: true });
107 let pb: Pin<&f64> = foo_b_pin.apply_pin(foo_object.as_ref());
108 assert_eq!(*pb, 22.0);
109
110 let mut x = Box::pin(Bar { x: 0, y: Foo { a: 1, b: 52.0, c: false } });
111 let bar_y_b = Bar::FIELD_OFFSETS.y + foo_b_pin;
112 assert_eq!(*bar_y_b.apply(&*x), 52.0);
113
114 let bar_y_pin = unsafe { Bar::FIELD_OFFSETS.y.as_pinned_projection() };
115 *(bar_y_pin + foo_b_pin).apply_pin_mut(x.as_mut()) = 12.;
116 assert_eq!(x.y.b, 12.0);
117 }
118}
119
120#[cfg(doctest)]
144const NO_IMPL_UNPIN: u32 = 0;
145
146#[doc(hidden)]
147#[cfg(feature = "field-offset-trait")]
148mod internal {
149 use super::*;
150 pub trait CombineFlag {
151 type Output;
152 }
153 impl CombineFlag for (AllowPin, AllowPin) {
154 type Output = AllowPin;
155 }
156 impl CombineFlag for (NotPinned, AllowPin) {
157 type Output = NotPinned;
158 }
159 impl CombineFlag for (AllowPin, NotPinned) {
160 type Output = NotPinned;
161 }
162 impl CombineFlag for (NotPinned, NotPinned) {
163 type Output = NotPinned;
164 }
165}
166
167#[cfg(feature = "field-offset-trait")]
168pub trait ConstFieldOffset: Copy {
169 type Container;
171 type Field;
173
174 type PinFlag;
176
177 const OFFSET: FieldOffset<Self::Container, Self::Field, Self::PinFlag>;
178
179 fn as_field_offset(self) -> FieldOffset<Self::Container, Self::Field, Self::PinFlag> {
180 Self::OFFSET
181 }
182 fn get_byte_offset(self) -> usize {
183 Self::OFFSET.get_byte_offset()
184 }
185 fn apply(self, x: &Self::Container) -> &Self::Field {
186 Self::OFFSET.apply(x)
187 }
188 fn apply_mut(self, x: &mut Self::Container) -> &mut Self::Field {
189 Self::OFFSET.apply_mut(x)
190 }
191
192 fn apply_pin<'a>(self, x: Pin<&'a Self::Container>) -> Pin<&'a Self::Field>
193 where
194 Self: ConstFieldOffset<PinFlag = AllowPin>,
195 {
196 Self::OFFSET.apply_pin(x)
197 }
198 fn apply_pin_mut<'a>(self, x: Pin<&'a mut Self::Container>) -> Pin<&'a mut Self::Field>
199 where
200 Self: ConstFieldOffset<PinFlag = AllowPin>,
201 {
202 Self::OFFSET.apply_pin_mut(x)
203 }
204}
205
206#[cfg(feature = "field-offset-trait")]
209union TransmutePinFlag<Container, Field, PinFlag> {
210 x: FieldOffset<Container, Field, PinFlag>,
211 y: FieldOffset<Container, Field>,
212}
213
214#[derive(Copy, Clone)]
216#[cfg(feature = "field-offset-trait")]
217pub struct ConstFieldOffsetSum<A: ConstFieldOffset, B: ConstFieldOffset>(pub A, pub B);
218
219#[cfg(feature = "field-offset-trait")]
220impl<A: ConstFieldOffset, B: ConstFieldOffset> ConstFieldOffset for ConstFieldOffsetSum<A, B>
221where
222 A: ConstFieldOffset<Field = B::Container>,
223 (A::PinFlag, B::PinFlag): internal::CombineFlag,
224{
225 type Container = A::Container;
226 type Field = B::Field;
227 type PinFlag = <(A::PinFlag, B::PinFlag) as internal::CombineFlag>::Output;
228 const OFFSET: FieldOffset<Self::Container, Self::Field, Self::PinFlag> = unsafe {
229 TransmutePinFlag {
230 y: FieldOffset::new_from_offset(
231 A::OFFSET.get_byte_offset() + B::OFFSET.get_byte_offset(),
232 ),
233 }
234 .x
235 };
236}
237
238#[cfg(feature = "field-offset-trait")]
239impl<A: ConstFieldOffset, B: ConstFieldOffset, Other> ::core::ops::Add<Other>
240 for ConstFieldOffsetSum<A, B>
241where
242 Self: ConstFieldOffset,
243 Other: ConstFieldOffset<Container = <Self as ConstFieldOffset>::Field>,
244{
245 type Output = ConstFieldOffsetSum<Self, Other>;
246 fn add(self, other: Other) -> Self::Output {
247 ConstFieldOffsetSum(self, other)
248 }
249}