1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
//! `repr_offset` allows computing and safely using field offsets from types with a stable layout.
//!
//! Currently only `#[repr(C)]`/`#[repr(C,packed)]`/`#[repr(C,align)]` structs are supported.
//!
//! # Features
//!
//! These are some of the features this library provides:
//!
//! - The [`ReprOffset`] derive macro, which outputs associated constants with the
//! offsets of fields.<br>
//!
//! - Using the [`FieldOffset`] type (how offsets are represented),
//! with methods for operating on a field through a pointer to the struct,
//! including getting a reference(or pointer) to the field.
//!
//! - Use the [`unsafe_struct_field_offsets`] macro as an alternative to the
//! [`ReprOffset`] derive macro, most useful when the "derive" feature is disabled.
//!
//! # Dependencies
//!
//! This library re-exports the [`ReprOffset`] derive macro from the
//! `repr_offset_derive` crate when the "derive" feature is enabled
//! (it's enabled is the default).
//!
//! If you don't need the derive macro,
//! you can disable the default feature in the Cargo.toml file with
//! `repr_offset = { version = "....", default_features = false }`,
//! making a clean compile of this crate take one to three seconds(depends on the machine).
//!
//! <span id="root-mod-examples"></span>
//! # Examples
//!
//! ### Derivation
//!
//! This example demonstrates:
//!
//! - Deriving the field offset constants with the [`ReprOffset`] derive macro.
//!
//! - Moving out *unaligned* fields through a raw pointer.
//!
//! ```rust
#![cfg_attr(feature = "derive", doc = "use repr_offset::ReprOffset;")]
#![cfg_attr(not(feature = "derive"), doc = "use repr_offset_derive::ReprOffset;")]
//!
//! use std::mem::ManuallyDrop;
//!
//! #[repr(C, packed)]
//! #[derive(ReprOffset)]
//! struct Packed{
//!     x: u8,
//!     y: u64,
//!     z: String,
//! }
//!
//! let mut this = ManuallyDrop::new(Packed{
//!     x: 5,
//!     y: 8,
//!     z: "oh,hi".to_string(),
//! });
//!
//! let ptr: *mut Packed = &mut *this;
//!
//! unsafe{
//!     assert_eq!( Packed::OFFSET_X.read(ptr), 5 );
//!     assert_eq!( Packed::OFFSET_Y.read(ptr), 8 );
//!     assert_eq!( Packed::OFFSET_Z.read(ptr), "oh,hi".to_string() );
//! }
//!
//! ```
//!
//! ### Initialization
//!
//! This example demonstrates how you can:
//!
//! - Use the [`unsafe_struct_field_offsets`] macro to declare associated constants with
//! the field offsets.
//!
//! - Initialize an uninitialized struct by passing a pointer to it.
//!
//! This example only compiles since Rust 1.36 because it uses `MaybeUninit`.
//!
#![cfg_attr(rust_1_36, doc = "```rust")]
#![cfg_attr(not(rust_1_36), doc = "```ignore")]
//!
//! use std::mem::MaybeUninit;
//!
//! use repr_offset::{unsafe_struct_field_offsets, Aligned};
//!
//! fn main(){
//!     unsafe {
//!         let mut foo = MaybeUninit::uninit();
//!         initialize_foo(foo.as_mut_ptr());
//!         assert_eq!(
//!             foo.assume_init(),
//!             Foo{ name: "foo".to_string(), x: 13, y: 21 }
//!         );
//!     }
//! }
//!
//! /// Initializes a `Foo` through a raw pointer.
//! ///
//! /// # Safety
//! ///
//! /// Callers must pass a pointer to uninitialized memory with the
//! /// size and alignment of `Foo`
//! unsafe fn initialize_foo(this: *mut Foo){
//!     Foo::OFFSET_NAME.raw_get_mut(this).write("foo".into());
//!     Foo::OFFSET_X.raw_get_mut(this).write(13);
//!     Foo::OFFSET_Y.raw_get_mut(this).write(21);
//! }
//!
//! #[repr(C)]
//! #[derive(Debug, PartialEq)]
//! pub struct Foo{
//!     pub name: String,
//!     pub x: u32,
//!     pub y: u32,
//! }
//!
//! // This macro is unsafe to invoke because you have to ensure that:
//! // - All field types are listed,in declaration order.
//! // - The `alignment` parameter is `Unaligned` if the struct is `#[repr(C,packed)]`,
//! //   and `Aligned` if it's not.
//! unsafe_struct_field_offsets!{
//!     alignment =  Aligned,
//!
//!     impl[] Foo {
//!         pub const OFFSET_NAME:String;
//!         pub const OFFSET_X:u32;
//!         pub const OFFSET_Y:u32;
//!     }
//! }
//!
//!
//!
//! ```
//!
//!
//! [`ReprOffset`]: ./docs/repr_offset_macro/index.html
//! [`unsafe_struct_field_offsets`]: ./macro.unsafe_struct_field_offsets.html
//! [`FieldOffset`]: ./struct.FieldOffset.html
//!
#![no_std]
#![cfg_attr(feature = "priv_raw_ref", feature(raw_ref_op))]
#![deny(clippy::missing_safety_doc)]
#![deny(clippy::shadow_unrelated)]
#![deny(clippy::wildcard_imports)]
#![deny(missing_docs)]

#[doc(hidden)]
pub extern crate self as repr_offset;

#[macro_use]
mod internal_macros;

#[macro_use]
mod macros;

#[cfg(feature = "testing")]
#[macro_use]
mod test_macros;

pub mod docs;

pub mod offset_calc;

mod alignment;

/// Types used for examples,
///
/// These are in the docs purely so that documentation examples only use
/// types that are documented.
///
/// You can only use items from this module when the "for_examples" feature is enabled.
pub mod for_examples {
    #[doc(inline)]
    pub use crate::for_examples_inner::*;
}

#[doc(hidden)]
#[cfg(any(feature = "for_examples", all(rust_1_41, doc)))]
pub mod for_examples_inner;

#[doc(hidden)]
#[cfg(not(any(feature = "for_examples", all(rust_1_41, doc))))]
pub mod for_examples_inner {}

mod struct_field_offset;

pub mod utils;

#[cfg(feature = "testing")]
pub mod types_for_tests;

/// This derive macro [is documented in here](./docs/repr_offset_macro/index.html)
#[doc(inline)]
#[cfg(feature = "derive")]
pub use repr_offset_derive::ReprOffset;

pub use self::{
    alignment::{Aligned, Alignment, CombinePacking, CombinePackingOut, Unaligned},
    struct_field_offset::FieldOffset,
};

#[cfg(all(test, not(feature = "testing")))]
compile_error! { "tests must be run with the \"testing\" feature" }