Last active
October 17, 2017 04:52
-
-
Save iscgar/9d47ed1528447bb2eac670ed4872d98c to your computer and use it in GitHub Desktop.
Rust `offsetof` prototype (`offset_of` and `span_of`)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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