repr_offset/lib.rs
1//! `repr_offset` allows computing and safely using field offsets from types
2//! with a defined layout.
3//!
4//! Currently only `#[repr(C)]`/`#[repr(C,packed)]`/`#[repr(C,align)]` structs are supported.
5//!
6//! # Features
7//!
8//! These are some of the features this library provides:
9//!
10//! - The [`ReprOffset`] derive macro, which outputs associated constants with the
11//! offsets of fields, and implements the [`GetFieldOffset`] trait for each field.<br>
12//!
13//! - The [`FieldOffset`] type (how offsets are represented),
14//! with methods for operating on a field through a pointer to the struct,
15//! including getting a reference(or pointer) to the field.
16//!
17//! - The [`unsafe_struct_field_offsets`] macro as an alternative to the
18//! [`ReprOffset`] derive macro, most useful when the "derive" feature is disabled.
19//!
20//! - The [`GetFieldOffset`] trait, for getting the [`FieldOffset`] for a field,
21//! and the [`OFF!`], [`off`], [`PUB_OFF!`], and [`pub_off`] macros for
22//! getting the [`FieldOffset`] for a field with a convenient syntax.
23//!
24//! - The extension traits from the [`ext`] module,
25//! which define methods for operating on a field, given a [`FieldOffset`].
26//!
27//! <span id="root-mod-examples"></span>
28//! # Examples
29//!
30//! ### Derivation
31//!
32//! This example demonstrates:
33//!
34//! - Deriving the field offset constants and [`GetFieldOffset`] trait
35//! with the [`ReprOffset`] derive macro.
36//!
37//! - Moving out *unaligned* fields through a raw pointer.
38//!
39//! - The [`off`] macro, and an extension trait from the [`ext`] module.
40//!
41//! ```rust
42#![cfg_attr(feature = "derive", doc = "use repr_offset::ReprOffset;")]
43#![cfg_attr(not(feature = "derive"), doc = "use repr_offset_derive::ReprOffset;")]
44//!
45//! use repr_offset::{ROExtRawOps, off};
46//!
47//! use std::mem::ManuallyDrop;
48//!
49//! #[repr(C, packed)]
50//! #[derive(ReprOffset)]
51//! struct Packed{
52//! x: u8,
53//! y: u64,
54//! z: String,
55//! }
56//!
57//! let mut this = ManuallyDrop::new(Packed{
58//! x: 5,
59//! y: 8,
60//! z: "oh,hi".to_string(),
61//! });
62//!
63//! let ptr: *mut Packed = &mut *this;
64//!
65//! unsafe{
66//! assert_eq!( Packed::OFFSET_X.read(ptr), 5 );
67//! assert_eq!( Packed::OFFSET_Y.read(ptr), 8 );
68//! assert_eq!( Packed::OFFSET_Z.read(ptr), "oh,hi".to_string() );
69//!
70//! // Another way to do the same, using extension traits, and macros.
71//! assert_eq!( ptr.f_read(off!(x)), 5 );
72//! assert_eq!( ptr.f_read(off!(y)), 8 );
73//! }
74//!
75//! ```
76//!
77//! ### Initialization
78//!
79//! This example demonstrates how you can:
80//!
81//! - Use the [`unsafe_struct_field_offsets`] macro to declare associated constants with
82//! the field offsets, and implement the [`GetFieldOffset`] trait.
83//!
84//! - The [`off`] macro, and an extension trait from the [`ext`] module.
85//!
86//! - Initialize an uninitialized struct with a functino that takes a raw pointer.
87//!
88//! ```rust
89//!
90//! use std::mem::MaybeUninit;
91//!
92//! use repr_offset::{
93//! unsafe_struct_field_offsets,
94//! off,
95//! Aligned, ROExtRawMutOps,
96//! };
97//!
98//! fn main(){
99//! unsafe {
100//! let mut foo = MaybeUninit::<Foo>::uninit();
101//! initialize_foo(foo.as_mut_ptr());
102//! assert_eq!(
103//! foo.assume_init(),
104//! Foo{ name: "foo".to_string(), x: 13, y: 21 }
105//! );
106//! }
107//! }
108//!
109//! /// Initializes a `Foo` through a raw pointer.
110//! ///
111//! /// # Safety
112//! ///
113//! /// Callers must pass a pointer to uninitialized memory with the
114//! /// size and alignment of `Foo`
115//! unsafe fn initialize_foo(this: *mut Foo){
116//! // How it's done with the inherent associated constants declared in
117//! // the `unsafe_struct_field_offsets` macro
118//! //
119//! Foo::OFFSET_NAME.write(this, "foo".into());
120//! Foo::OFFSET_X.write(this, 13);
121//! Foo::OFFSET_Y.write(this, 21);
122//!
123//! // How it's done with the extension traits from the ext module,
124//! // the `off` macro, and the `GetFieldOffset` trait:
125//! //
126//! // this.f_write(off!(name), "foo".into());
127//! // this.f_write(off!(x), 13);
128//! // this.f_write(off!(y), 21);
129//! }
130//!
131//! #[repr(C)]
132//! #[derive(Debug, PartialEq)]
133//! pub struct Foo{
134//! pub name: String,
135//! pub x: u32,
136//! pub y: u32,
137//! }
138//!
139//! // This macro is unsafe to invoke because you have to ensure that:
140//! // - All field types are listed,in declaration order.
141//! // - The `alignment` parameter is `Unaligned` if the struct is `#[repr(C,packed)]`,
142//! // and `Aligned` if it's not.
143//! unsafe_struct_field_offsets!{
144//! alignment = Aligned,
145//!
146//! impl[] Foo {
147//! pub const OFFSET_NAME, name: String;
148//! pub const OFFSET_X, x: u32;
149//! pub const OFFSET_Y, y: u32;
150//! }
151//! }
152//!
153//!
154//!
155//! ```
156//!
157//! # Dependencies
158//!
159//! This library re-exports the [`ReprOffset`] derive macro from the
160//! `repr_offset_derive` crate when the "derive" feature is enabled,
161//! this is disabled by default.
162//!
163//! It also reexports the `tstr` crate unconditionally, to use its `TS` macro
164//! as the type parameter of the [`GetFieldOffset`] trait.
165//!
166//! # Cargo features
167//!
168//! These are the cargo features in `repr_offset`:
169//!
170//! - `derive` (disabled by default):
171//! Enables the [`ReprOffset`] derive macro.
172//! This requires the same Rust versions as `syn`, which is currently `>= 1.56.0`.
173//!
174//! - `"for_examples"` (disabled by default):
175//! Enables the `for_examples` module, with types used in documentation examples.
176//!
177//! Example of using the "derive" feature::
178//! ```toml
179//! repr_offset = { version = "0.2", features = ["derive"] }
180//! ```
181//!
182//! # no-std support
183//!
184//! This library is unconditionally `#![no_std]`, and that is unlikely to change in the future.
185//!
186//! # Minimum Rust version
187//!
188//! This crate support Rust back to 1.41.0.
189//!
190//!
191//!
192//! [`OFF!`]: ./macro.OFF.html
193//! [`off`]: ./macro.off.html
194//! [`PUB_OFF!`]: ./macro.PUB_OFF.html
195//! [`pub_off`]: ./macro.pub_off.html
196//!
197//! [`ReprOffset`]: ./derive.ReprOffset.html
198//! [`GetFieldOffset`]: ./get_field_offset/trait.GetFieldOffset.html
199//! [`unsafe_struct_field_offsets`]: ./macro.unsafe_struct_field_offsets.html
200//! [`FieldOffset`]: ./struct.FieldOffset.html
201//! [`ext`]: ./ext/index.html
202//!
203#![no_std]
204#![cfg_attr(feature = "priv_raw_ref", feature(raw_ref_op))]
205#![cfg_attr(feature = "docsrs", feature(doc_cfg))]
206#![allow(clippy::empty_loop)]
207#![deny(clippy::missing_safety_doc)]
208#![deny(clippy::shadow_unrelated)]
209#![deny(clippy::wildcard_imports)]
210#![deny(missing_docs)]
211
212#[doc(hidden)]
213pub extern crate self as repr_offset;
214
215#[macro_use]
216mod internal_macros;
217
218#[macro_use]
219mod macros;
220
221#[cfg(feature = "testing")]
222#[macro_use]
223mod test_macros;
224
225pub mod offset_calc;
226
227pub mod alignment;
228
229pub mod privacy;
230
231/// Types used for examples,
232///
233/// These are in the docs purely so that documentation examples only use
234/// types that are documented.
235///
236/// You can only use items from this module when the "for_examples" feature is enabled.
237#[cfg_attr(feature = "docsrs", doc(cfg(feature = "for_examples")))]
238pub mod for_examples {
239 #[doc(inline)]
240 #[cfg(any(feature = "for_examples", doc))]
241 pub use crate::for_examples_inner::*;
242}
243
244#[doc(hidden)]
245#[cfg(any(feature = "for_examples", doc))]
246pub mod for_examples_inner;
247
248mod struct_field_offset;
249
250pub mod ext;
251
252pub mod get_field_offset;
253
254pub mod utils;
255
256#[cfg(feature = "testing")]
257pub mod types_for_tests;
258
259pub use tstr;
260
261include! {"repr_offset_macro.rs"}
262
263pub use self::{
264 alignment::{Aligned, Unaligned},
265 ext::{ROExtAcc, ROExtOps, ROExtRawAcc, ROExtRawMutAcc, ROExtRawMutOps, ROExtRawOps},
266 get_field_offset::{FieldType, GetPubFieldOffset},
267 struct_field_offset::FieldOffset,
268};
269
270#[cfg(all(test, not(feature = "testing")))]
271compile_error! { "tests must be run with the \"testing\" feature" }
272
273// DO NOT USE THIS OUTSIDE MACROS OF THIS CRATE
274#[doc(hidden)]
275pub mod pmr {
276 pub use core::marker::PhantomData;
277
278 pub use crate::struct_field_offset::FOAssertStruct;
279
280 pub use crate::get_field_offset::{
281 loop_create_fo, loop_create_mutref, loop_create_val, FieldOffsetWithVis, GetFieldOffset,
282 GetPubFieldOffset, ImplsGetFieldOffset,
283 };
284}