Skip to content

Instantly share code, notes, and snippets.

@iscgar
Last active October 17, 2017 04:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iscgar/9d47ed1528447bb2eac670ed4872d98c to your computer and use it in GitHub Desktop.
Save iscgar/9d47ed1528447bb2eac670ed4872d98c to your computer and use it in GitHub Desktop.
Rust `offsetof` prototype (`offset_of` and `span_of`)
pub use std::mem
#[macro_export]
macro_rules! offset_of {
($sty:ty, $($field:tt)+) => ({
unsafe {
let root: $sty = $crate::mem::uninitialized();
let base = &root as *const _ as usize;
let end = &root.$($field)* as *const _ as usize;
end - base
}
});
}
#[cfg(test)]
mod tests {
#[test]
fn offset_assert() {
use super::*;
#[repr(C)]
struct Member {
foo: u32,
}
#[repr(C)]
struct Test {
x: u64,
y: [u8; 56],
z: Member,
egg: [[u8; 4]; 4],
}
assert_eq!(offset_of!(Test, x), 0);
assert_eq!(offset_of!(Test, y), 8);
assert_eq!(offset_of!(Test, y[4]), 12);
assert_eq!(offset_of!(Test, z.foo), 64);
assert_eq!(offset_of!(Test, egg[1][3]), 75);
}
}
pub use std::mem
#[macro_export]
macro_rules! span_of {
(@helper $root:ident, [] ..=) => {
compile_error!("Expected a range, found '..='")
};
(@helper $root:ident, [] ..) => {
compile_error!("Expected a range, found '..'")
};
(@helper $root:ident, [] ..= $($field:tt)+) => {
(&$root as *const _ as usize,
&$root.$($field)* as *const _ as usize + $crate::mem::size_of_val(&$root.$($field)*))
};
(@helper $root:ident, [] .. $($field:tt)+) => {
(&$root as *const _ as usize, &$root.$($field)* as *const _ as usize)
};
(@helper $root:ident, $(# $begin:tt)+ [] ..= $($end:tt)+) => {
(&$root.$($begin)* as *const _ as usize,
&$root.$($end)* as *const _ as usize + $crate::mem::size_of_val(&$root.$($end)*))
};
(@helper $root:ident, $(# $begin:tt)+ [] .. $($end:tt)+) => {
(&$root.$($begin)* as *const _ as usize, &$root.$($end)* as *const _ as usize)
};
(@helper $root:ident, $(# $begin:tt)+ [] ..) => {
(&$root.$($begin)* as *const _ as usize,
&$root as *const _ as usize + $crate::mem::size_of_val(&$root))
};
(@helper $root:ident, $(# $begin:tt)+ [] ..=) => {
compile_error!(
"Found inclusive range to the end of a struct. Did you mean '..' instead of '..='?")
};
(@helper $root:ident, $(# $begin:tt)+ []) => {
compile_error!("The second argument of 'span_of!' must be a range")
};
(@helper $root:ident, $(# $begin:tt)+ [] $tt:tt $($rest:tt)*) => {
span_of!(@helper $root, $(#$begin)* #$tt [] $($rest)*)
};
(@helper $root:ident, [] $tt:tt $($rest:tt)*) => {
span_of!(@helper $root, #$tt [] $($rest)*)
};
($sty:ty, $($exp:tt)+) => ({
unsafe {
let root: $sty = $crate::mem::uninitialized();
let base = &root as *const _ as usize;
let (begin, end) = span_of!(@helper root, [] $($exp)*);
begin-base..end-base
}
});
}
#[cfg(test)]
mod tests {
#[test]
fn span_assert() {
use super::*;
#[repr(C)]
struct Member {
foo: u32,
}
#[repr(C)]
struct Test {
x: u64,
y: [u8; 56],
z: Member,
egg: [[u8; 4]; 4],
}
assert_eq!(span_of!(Test, ..x), 0..0);
assert_eq!(span_of!(Test, ..=x), 0..8);
assert_eq!(span_of!(Test, ..y), 0..8);
assert_eq!(span_of!(Test, ..=y), 0..64);
assert_eq!(span_of!(Test, ..y[0]), 0..8);
assert_eq!(span_of!(Test, ..=y[0]), 0..9);
assert_eq!(span_of!(Test, ..z), 0..64);
assert_eq!(span_of!(Test, ..=z), 0..68);
assert_eq!(span_of!(Test, ..z.foo), 0..64);
assert_eq!(span_of!(Test, ..=z.foo), 0..68);
assert_eq!(span_of!(Test, ..egg), 0..68);
assert_eq!(span_of!(Test, ..=egg), 0..84);
assert_eq!(span_of!(Test, ..egg[0]), 0..68);
assert_eq!(span_of!(Test, ..=egg[0]), 0..72);
assert_eq!(span_of!(Test, ..egg[0][0]), 0..68);
assert_eq!(span_of!(Test, ..=egg[0][0]), 0..69);
assert_eq!(span_of!(Test, x..),
offset_of!(Test, x)..mem::size_of::<Test>());
assert_eq!(span_of!(Test, y..),
offset_of!(Test, y)..mem::size_of::<Test>());
assert_eq!(span_of!(Test, y[0]..),
offset_of!(Test, y[0])..mem::size_of::<Test>());
assert_eq!(span_of!(Test, z..),
offset_of!(Test, z)..mem::size_of::<Test>());
assert_eq!(span_of!(Test, z.foo..),
offset_of!(Test, z.foo)..mem::size_of::<Test>());
assert_eq!(span_of!(Test, egg..),
offset_of!(Test, egg)..mem::size_of::<Test>());
assert_eq!(span_of!(Test, egg[0]..),
offset_of!(Test, egg[0])..mem::size_of::<Test>());
assert_eq!(span_of!(Test, egg[0][0]..),
offset_of!(Test, egg[0][0])..mem::size_of::<Test>());
assert_eq!(span_of!(Test, x..y),
offset_of!(Test, x)..offset_of!(Test, y));
assert_eq!(span_of!(Test, x..=y),
offset_of!(Test, x)..offset_of!(Test, y) + mem::size_of::<[u8; 56]>());
assert_eq!(span_of!(Test, x..y[4]),
offset_of!(Test, x)..offset_of!(Test, y[4]));
assert_eq!(span_of!(Test, x..=y[4]),
offset_of!(Test, x)..offset_of!(Test, y) + mem::size_of::<[u8; 5]>());
assert_eq!(span_of!(Test, x..z.foo),
offset_of!(Test, x)..offset_of!(Test, z.foo));
assert_eq!(span_of!(Test, x..=z.foo),
offset_of!(Test, x)..offset_of!(Test, z.foo) + mem::size_of::<u32>());
assert_eq!(span_of!(Test, egg[0][0]..egg[1][0]),
offset_of!(Test, egg[0][0])..offset_of!(Test, egg[1][0]));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment