mirror of
https://gitee.com/openharmony/third_party_rust_memoffset
synced 2024-11-23 07:10:22 +00:00
Cleanup. Macors no longer thoretically allocate.
This commit is contained in:
parent
32cbbb79ac
commit
057a247d25
@ -4,6 +4,7 @@ version = "0.1.0"
|
||||
authors = ["Gilad Naaman <gilad.naaman@gmail.com>"]
|
||||
description="offset_of functionality for Rust structs."
|
||||
license="Apache-2.0"
|
||||
readme="README.md"
|
||||
|
||||
[dependencies]
|
||||
|
||||
|
43
README.md
Normal file
43
README.md
Normal file
@ -0,0 +1,43 @@
|
||||
# memoffset #
|
||||
|
||||
[![](http://meritbadge.herokuapp.com/memoffset)](https://crates.io/crates/memoffset)
|
||||
|
||||
C-Like `offset_of` functionality for Rust structs.
|
||||
|
||||
Introduces the following macros:
|
||||
* `offset_of!` for obtaining the offset of a member of a struct.
|
||||
* `span_of!` for obtaining the range that a field, or fields, span.
|
||||
|
||||
## Usage ##
|
||||
Add the following dependency to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
memoffset = "0.1"
|
||||
```
|
||||
|
||||
Add the following lines at the top of your `main.rs` or `lib.rs` files.
|
||||
|
||||
```rust
|
||||
#[macro_use]
|
||||
extern crate memoffset;
|
||||
```
|
||||
|
||||
## Examples ##
|
||||
```rust
|
||||
#[repr(C, packed)]
|
||||
struct Foo {
|
||||
a: u32,
|
||||
b: u32,
|
||||
c: [u8; 5],
|
||||
d: u32,
|
||||
}
|
||||
|
||||
assert_eq!(offset_of!(Foo, b), 4);
|
||||
assert_eq!(offset_of!(Foo, c[3]), 11);
|
||||
|
||||
assert_eq!(span_of!(Foo, a), 0..4);
|
||||
assert_eq!(span_of!(Foo, a .. c), 0..8);
|
||||
assert_eq!(span_of!(Foo, a .. c[1]), 0..9);
|
||||
assert_eq!(span_of!(Foo, a .. =c[1]), 0..10);
|
||||
```
|
248
src/lib.rs
248
src/lib.rs
@ -1,3 +1,9 @@
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A crate used for calculating offsets of struct members and their spans.
|
||||
//!
|
||||
//! Some of the funcationality of the crate makes no sense when used along with structs that
|
||||
@ -42,243 +48,13 @@
|
||||
|
||||
#[cfg(feature="std")]
|
||||
#[doc(hidden)]
|
||||
pub use std::mem;
|
||||
pub use std::{mem, ptr};
|
||||
|
||||
#[cfg(not(feature="std"))]
|
||||
#[doc(hidden)]
|
||||
pub use core::mem;
|
||||
pub use core::{mem, ptr};
|
||||
|
||||
/// Calculates the offset of the specified field from the start of the struct.
|
||||
/// This macro supports arbitrary amount of subscripts and recursive member-accesses.
|
||||
///
|
||||
/// *Note*: This macro may not make much sense when used on structs that are not `#[repr(C, packed)]`
|
||||
///
|
||||
/// ## Examples - Simple
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate memoffset;
|
||||
///
|
||||
/// #[repr(C, packed)]
|
||||
/// struct Foo {
|
||||
/// a: u32,
|
||||
/// b: u64,
|
||||
/// c: [u8; 5]
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// assert_eq!(offset_of!(Foo, a), 0);
|
||||
/// assert_eq!(offset_of!(Foo, b), 4);
|
||||
/// assert_eq!(offset_of!(Foo, c[2]), 14);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Examples - Advanced
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate memoffset;
|
||||
///
|
||||
/// #[repr(C, packed)]
|
||||
/// struct UnnecessarilyComplicatedStruct {
|
||||
/// member: [UnnecessarilyComplexStruct; 12]
|
||||
/// }
|
||||
///
|
||||
/// #[repr(C, packed)]
|
||||
/// struct UnnecessarilyComplexStruct {
|
||||
/// a: u32,
|
||||
/// b: u64,
|
||||
/// c: [u8; 5]
|
||||
/// }
|
||||
///
|
||||
///
|
||||
/// fn main() {
|
||||
/// assert_eq!(offset_of!(UnnecessarilyComplicatedStruct, member[3].c[3]), 66);
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! offset_of {
|
||||
($father:ty, $($field:tt)+) => ({
|
||||
let root: $father = unsafe { $crate::mem::uninitialized() };
|
||||
|
||||
let base = &root as *const _ as usize;
|
||||
let member = &root.$($field)+ as *const _ as usize;
|
||||
|
||||
$crate::mem::forget(root);
|
||||
|
||||
member - base
|
||||
});
|
||||
}
|
||||
|
||||
/// Produces a range instance representing the sub-slice containing the specified member.
|
||||
///
|
||||
/// This macro provides 2 forms of differing functionalities.
|
||||
///
|
||||
/// The first form is identical to the appearance of the `offset_of!` macro,
|
||||
/// and just like `offset_of!`, it has no limit on the depth of fields / subscripts used.
|
||||
///
|
||||
/// ```ignore
|
||||
/// span_of!(Struct, member[index].field)
|
||||
/// ```
|
||||
///
|
||||
/// The second form of `span_of!` returns a sub-slice which starts at one field, and ends at another.
|
||||
/// The general pattern of this form is:
|
||||
///
|
||||
/// ```ignore
|
||||
/// span_of!(Struct, member_a .. member_b)
|
||||
/// ```
|
||||
///
|
||||
/// Due to `macro_rules`' parsing restrictions, the first expression - the start-anchor - is limited to subscripts,
|
||||
/// with no sub-field access.
|
||||
/// The second expression - the end anchor - has no such limitations.
|
||||
///
|
||||
/// By default this form excludes the end-anchor from the range, but inclusive ranges can be opted-in using "..=" instead.
|
||||
///
|
||||
/// *Note*: This macro may not make much sense when used on structs that are not `#[repr(C, packed)]`
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate memoffset;
|
||||
///
|
||||
/// #[repr(C, packed)]
|
||||
/// struct Florp {
|
||||
/// a: u32
|
||||
/// }
|
||||
///
|
||||
/// #[repr(C, packed)]
|
||||
/// struct Blarg {
|
||||
/// x: u64,
|
||||
/// y: [u8; 56],
|
||||
/// z: Florp,
|
||||
/// egg: [[u8; 4]; 4]
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// assert_eq!(0..8, span_of!(Blarg, x));
|
||||
/// assert_eq!(64..68, span_of!(Blarg, z.a));
|
||||
/// assert_eq!(79..80, span_of!(Blarg, egg[2][3]));
|
||||
///
|
||||
/// assert_eq!(8..64, span_of!(Blarg, y[0] .. z));
|
||||
/// assert_eq!(0..42, span_of!(Blarg, x .. y[34]));
|
||||
/// assert_eq!(0..64, span_of!(Blarg, x ..= y));
|
||||
/// assert_eq!(58..68, span_of!(Blarg, y[50] ..= z));
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! span_of {
|
||||
($father:ty, $field_a:ident $([$index:expr])* .. $($field_b:tt)+) => ({
|
||||
let root: $father = unsafe { $crate::mem::uninitialized() };
|
||||
|
||||
let start = offset_of!($father, $field_a $([$index])*);
|
||||
let end = offset_of!($father, $($field_b)+);
|
||||
|
||||
$crate::mem::forget(root);
|
||||
|
||||
start..end
|
||||
});
|
||||
|
||||
($father:ty, $field_a:ident $([$index:expr])* ..= $($field_b:tt)+) => ({
|
||||
let root: $father = unsafe { $crate::mem::uninitialized() };
|
||||
|
||||
let start = offset_of!($father, $field_a $([$index])*);
|
||||
let end = offset_of!($father, $($field_b)+) +
|
||||
$crate::mem::size_of_val(&root.$($field_b)+);
|
||||
|
||||
$crate::mem::forget(root);
|
||||
|
||||
start..end
|
||||
});
|
||||
|
||||
($father:ty, $($field:tt)+) => ({
|
||||
let root: $father = unsafe { $crate::mem::uninitialized() };
|
||||
|
||||
let start = offset_of!($father, $($field)+);
|
||||
let end = start + $crate::mem::size_of_val(&root.$($field)+);
|
||||
|
||||
$crate::mem::forget(root);
|
||||
|
||||
start..end
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[repr(C, packed)]
|
||||
struct Foo {
|
||||
a: u32,
|
||||
b: [u8; 4],
|
||||
c: i64
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn offset_simple() {
|
||||
assert_eq!(offset_of!(Foo, a), 0);
|
||||
assert_eq!(offset_of!(Foo, b), 4);
|
||||
assert_eq!(offset_of!(Foo, c), 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn offset_index() {
|
||||
assert_eq!(offset_of!(Foo, b[2]), 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn offset_index_out_of_bounds() {
|
||||
offset_of!(Foo, b[4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn span_simple() {
|
||||
assert_eq!(span_of!(Foo, a), 0..4);
|
||||
assert_eq!(span_of!(Foo, b), 4..8);
|
||||
assert_eq!(span_of!(Foo, c), 8..16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn span_index() {
|
||||
assert_eq!(span_of!(Foo, b[1]), 5..6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn huge() {
|
||||
struct Huge {
|
||||
preamble: [u8; 8192],
|
||||
member: u8
|
||||
}
|
||||
|
||||
assert_eq!(offset_of!(Huge, member), 8192);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn span_forms() {
|
||||
#[repr(C, packed)]
|
||||
struct Florp {
|
||||
a: u32
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct Blarg {
|
||||
x: u64,
|
||||
y: [u8; 56],
|
||||
z: Florp,
|
||||
egg: [[u8; 4]; 4]
|
||||
}
|
||||
|
||||
// Love me some brute force
|
||||
assert_eq!(0..8, span_of!(Blarg, x));
|
||||
assert_eq!(64..68, span_of!(Blarg, z.a));
|
||||
assert_eq!(79..80, span_of!(Blarg, egg[2][3]));
|
||||
|
||||
assert_eq!(8..64, span_of!(Blarg, y[0] .. z));
|
||||
assert_eq!(0..42, span_of!(Blarg, x .. y[34]));
|
||||
assert_eq!(0..64, span_of!(Blarg, x ..= y));
|
||||
assert_eq!(58..68, span_of!(Blarg, y[50] ..= z));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tuple_struct() {
|
||||
#[repr(C,packed)]
|
||||
struct Tup(i32, i32);
|
||||
assert_eq!(offset_of!(Tup, 0), 0);
|
||||
}
|
||||
}
|
||||
#[macro_use]
|
||||
mod offset_of;
|
||||
#[macro_use]
|
||||
mod span_of;
|
99
src/offset_of.rs
Normal file
99
src/offset_of.rs
Normal file
@ -0,0 +1,99 @@
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/// Calculates the offset of the specified field from the start of the struct.
|
||||
/// This macro supports arbitrary amount of subscripts and recursive member-accesses.
|
||||
///
|
||||
/// *Note*: This macro may not make much sense when used on structs that are not `#[repr(C, packed)]`
|
||||
///
|
||||
/// ## Examples - Simple
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate memoffset;
|
||||
///
|
||||
/// #[repr(C, packed)]
|
||||
/// struct Foo {
|
||||
/// a: u32,
|
||||
/// b: u64,
|
||||
/// c: [u8; 5]
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// assert_eq!(offset_of!(Foo, a), 0);
|
||||
/// assert_eq!(offset_of!(Foo, b), 4);
|
||||
/// assert_eq!(offset_of!(Foo, c[2]), 14);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Examples - Advanced
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate memoffset;
|
||||
///
|
||||
/// #[repr(C, packed)]
|
||||
/// struct UnnecessarilyComplicatedStruct {
|
||||
/// member: [UnnecessarilyComplexStruct; 12]
|
||||
/// }
|
||||
///
|
||||
/// #[repr(C, packed)]
|
||||
/// struct UnnecessarilyComplexStruct {
|
||||
/// a: u32,
|
||||
/// b: u64,
|
||||
/// c: [u8; 5]
|
||||
/// }
|
||||
///
|
||||
///
|
||||
/// fn main() {
|
||||
/// assert_eq!(offset_of!(UnnecessarilyComplicatedStruct, member[3].c[3]), 66);
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! offset_of {
|
||||
($father:ty, $($field:tt)+) => ({
|
||||
let root: *const $father = $crate::ptr::null();
|
||||
|
||||
let base = root as usize;
|
||||
let member = unsafe { &(*root).$($field)* } as *const _ as usize;
|
||||
|
||||
member - base
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[repr(C, packed)]
|
||||
struct Foo {
|
||||
a: u32,
|
||||
b: [u8; 4],
|
||||
c: i64
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn offset_simple() {
|
||||
assert_eq!(offset_of!(Foo, a), 0);
|
||||
assert_eq!(offset_of!(Foo, b), 4);
|
||||
assert_eq!(offset_of!(Foo, c), 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn offset_index() {
|
||||
assert_eq!(offset_of!(Foo, b[2]), 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn offset_index_out_of_bounds() {
|
||||
offset_of!(Foo, b[4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tuple_struct() {
|
||||
#[repr(C,packed)]
|
||||
struct Tup(i32, i32);
|
||||
|
||||
assert_eq!(offset_of!(Tup, 0), 0);
|
||||
}
|
||||
}
|
137
src/span_of.rs
Normal file
137
src/span_of.rs
Normal file
@ -0,0 +1,137 @@
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/// Produces a range instance representing the sub-slice containing the specified member.
|
||||
///
|
||||
/// This macro provides 2 forms of differing functionalities.
|
||||
///
|
||||
/// The first form is identical to the appearance of the `offset_of!` macro,
|
||||
/// and just like `offset_of!`, it has no limit on the depth of fields / subscripts used.
|
||||
///
|
||||
/// ```ignore
|
||||
/// span_of!(Struct, member[index].field)
|
||||
/// ```
|
||||
///
|
||||
/// The second form of `span_of!` returns a sub-slice which starts at one field, and ends at another.
|
||||
/// The general pattern of this form is:
|
||||
///
|
||||
/// ```ignore
|
||||
/// span_of!(Struct, member_a .. member_b)
|
||||
/// ```
|
||||
///
|
||||
/// Due to `macro_rules`' parsing restrictions, the first expression - the start-anchor - is limited to subscripts,
|
||||
/// with no sub-field access.
|
||||
/// The second expression - the end anchor - has no such limitations.
|
||||
///
|
||||
/// By default this form excludes the end-anchor from the range, but inclusive ranges can be opted-in using "..=" instead.
|
||||
///
|
||||
/// *Note*: This macro may not make much sense when used on structs that are not `#[repr(C, packed)]`
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate memoffset;
|
||||
///
|
||||
/// #[repr(C, packed)]
|
||||
/// struct Florp {
|
||||
/// a: u32
|
||||
/// }
|
||||
///
|
||||
/// #[repr(C, packed)]
|
||||
/// struct Blarg {
|
||||
/// x: u64,
|
||||
/// y: [u8; 56],
|
||||
/// z: Florp,
|
||||
/// egg: [[u8; 4]; 4]
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// assert_eq!(0..8, span_of!(Blarg, x));
|
||||
/// assert_eq!(64..68, span_of!(Blarg, z.a));
|
||||
/// assert_eq!(79..80, span_of!(Blarg, egg[2][3]));
|
||||
///
|
||||
/// assert_eq!(8..64, span_of!(Blarg, y[0] .. z));
|
||||
/// assert_eq!(0..42, span_of!(Blarg, x .. y[34]));
|
||||
/// assert_eq!(0..64, span_of!(Blarg, x ..= y));
|
||||
/// assert_eq!(58..68, span_of!(Blarg, y[50] ..= z));
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! span_of {
|
||||
($father:ty, $field_a:ident $([$index:expr])* .. $($field_b:tt)+) => ({
|
||||
let start = offset_of!($father, $field_a $([$index])*);
|
||||
let end = offset_of!($father, $($field_b)+);
|
||||
|
||||
start..end
|
||||
});
|
||||
|
||||
($father:ty, $field_a:ident $([$index:expr])* ..= $($field_b:tt)+) => ({
|
||||
let root: *const $father = $crate::ptr::null();
|
||||
|
||||
let start = offset_of!($father, $field_a $([$index])*);
|
||||
let end = offset_of!($father, $($field_b)+) +
|
||||
unsafe { $crate::mem::size_of_val(&(*root).$($field_b)+) };
|
||||
|
||||
start..end
|
||||
});
|
||||
($father:ty, $($field:tt)+) => ({
|
||||
let root: *const $father = $crate::ptr::null();
|
||||
|
||||
let start = offset_of!($father, $($field)+);
|
||||
let end = start +
|
||||
unsafe { $crate::mem::size_of_val(&(*root).$($field)+) };
|
||||
|
||||
start..end
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[repr(C, packed)]
|
||||
struct Foo {
|
||||
a: u32,
|
||||
b: [u8; 4],
|
||||
c: i64
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn span_simple() {
|
||||
assert_eq!(span_of!(Foo, a), 0..4);
|
||||
assert_eq!(span_of!(Foo, b), 4..8);
|
||||
assert_eq!(span_of!(Foo, c), 8..16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn span_index() {
|
||||
assert_eq!(span_of!(Foo, b[1]), 5..6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn span_forms() {
|
||||
#[repr(C, packed)]
|
||||
struct Florp {
|
||||
a: u32
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct Blarg {
|
||||
x: u64,
|
||||
y: [u8; 56],
|
||||
z: Florp,
|
||||
egg: [[u8; 4]; 4]
|
||||
}
|
||||
|
||||
// Love me some brute force
|
||||
assert_eq!(0..8, span_of!(Blarg, x));
|
||||
assert_eq!(64..68, span_of!(Blarg, z.a));
|
||||
assert_eq!(79..80, span_of!(Blarg, egg[2][3]));
|
||||
|
||||
assert_eq!(8..64, span_of!(Blarg, y[0] .. z));
|
||||
assert_eq!(0..42, span_of!(Blarg, x .. y[34]));
|
||||
assert_eq!(0..64, span_of!(Blarg, x ..= y));
|
||||
assert_eq!(58..68, span_of!(Blarg, y[50] ..= z));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user