memoffset-0.5.3/.gitignore000064400000000000000000000000711352547150100136630ustar0000000000000000/target/ **/*.rs.bk Cargo.lock .idea/ cmake-build-debug/ memoffset-0.5.3/.travis.yml000064400000000000000000000013151356104634700140140ustar0000000000000000sudo: false language: rust cache: cargo: true matrix: include: - rust: 1.20.0 # Oldest supported - rust: 1.36.0 # Oldest supported with MaybeUninit - rust: stable - rust: beta - rust: nightly - env: MIRI rust: nightly os: linux script: - sh ci/miri.sh - env: RUSTFMT rust: 1.36.0 install: - rustup component add rustfmt script: - cargo fmt -- --check - env: RUSTFLAGS="-D warnings" rust: 1.33.0 # `stable`: Locking down for consistent behavior script: - cargo check --tests install: - rustc -Vv - cargo -V script: - rm -rf target/debug/deps/*memoffset* # Avoid rustdoc problems - cargo test --verbose memoffset-0.5.3/build.rs000064400000000000000000000007351356104635400133530ustar0000000000000000extern crate rustc_version; use rustc_version::{version, Version}; fn main() { let version = version().unwrap(); // Assert we haven't travelled back in time assert!(version.major >= 1); // Check for a minimum version if version >= Version::from((1, 36, 0)) { println!("cargo:rustc-cfg=memoffset_maybe_uninit"); } if version >= Version::from((1, 40, 0)) { println!("cargo:rustc-cfg=memoffset_doctests"); } } memoffset-0.5.3/Cargo.toml.orig000064400000000000000000000006511356104636300145720ustar0000000000000000[package] name = "memoffset" version = "0.5.3" authors = ["Gilad Naaman "] description = "offset_of functionality for Rust structs." license = "MIT" readme = "README.md" repository = "https://github.com/Gilnaa/memoffset" keywords = ["mem", "offset", "offset_of", "offsetof"] categories = ["no-std"] [build-dependencies] rustc_version = "0.2.3" [dev-dependencies] doc-comment = "0.3" memoffset-0.5.3/Cargo.toml0000644000000016641356104646200111400ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "memoffset" version = "0.5.3" authors = ["Gilad Naaman "] description = "offset_of functionality for Rust structs." readme = "README.md" keywords = ["mem", "offset", "offset_of", "offsetof"] categories = ["no-std"] license = "MIT" repository = "https://github.com/Gilnaa/memoffset" [dev-dependencies.doc-comment] version = "0.3" [build-dependencies.rustc_version] version = "0.2.3" memoffset-0.5.3/ci/miri.sh000064400000000000000000000004351355751260400135730ustar0000000000000000set -ex MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" rustup default "$MIRI_NIGHTLY" rustup component add miri cargo miri setup cargo miri test memoffset-0.5.3/LICENSE000064400000000000000000000020371352547150100127040ustar0000000000000000Copyright (c) 2017 Gilad Naaman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.memoffset-0.5.3/README.md000064400000000000000000000022551356104634700131660ustar0000000000000000# 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. `memoffset` works under `no_std` environments. ## Usage ## Add the following dependency to your `Cargo.toml`: ```toml [dependencies] memoffset = "0.5" ``` These versions will compile fine with rustc versions greater or equal to 1.20. Add the following lines at the top of your `main.rs` or `lib.rs` files. ```rust,ignore #[macro_use] extern crate memoffset; ``` ## Examples ## ```rust #[macro_use] extern crate memoffset; #[repr(C, packed)] struct Foo { a: u32, b: u32, c: [u8; 5], d: u32, } fn main() { assert_eq!(offset_of!(Foo, b), 4); assert_eq!(offset_of!(Foo, d), 4+4+5); assert_eq!(span_of!(Foo, a), 0..4); assert_eq!(span_of!(Foo, a .. c), 0..8); assert_eq!(span_of!(Foo, a ..= c), 0..13); assert_eq!(span_of!(Foo, ..= d), 0..17); assert_eq!(span_of!(Foo, b ..), 4..17); } ``` memoffset-0.5.3/src/lib.rs000064400000000000000000000052341356104635400136100ustar0000000000000000// Copyright (c) 2017 Gilad Naaman // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //! A crate used for calculating offsets of struct members and their spans. //! //! This functionality currently can not be used in compile time code such as `const` or `const fn` definitions. //! //! ## Examples //! ``` //! #[macro_use] //! extern crate memoffset; //! //! #[repr(C, packed)] //! struct HelpMeIAmTrappedInAStructFactory { //! help_me_before_they_: [u8; 15], //! a: u32 //! } //! //! fn main() { //! assert_eq!(offset_of!(HelpMeIAmTrappedInAStructFactory, a), 15); //! assert_eq!(span_of!(HelpMeIAmTrappedInAStructFactory, a), 15..19); //! assert_eq!(span_of!(HelpMeIAmTrappedInAStructFactory, help_me_before_they_ .. a), 0..15); //! } //! ``` //! //! This functionality can be useful, for example, for checksum calculations: //! //! ```ignore //! #[repr(C, packed)] //! struct Message { //! header: MessageHeader, //! fragment_index: u32, //! fragment_count: u32, //! payload: [u8; 1024], //! checksum: u16 //! } //! //! let checksum_range = &raw[span_of!(Message, header..checksum)]; //! let checksum = crc16(checksum_range); //! ``` #![no_std] #[macro_use] #[cfg(memoffset_doctests)] #[cfg(doctest)] extern crate doc_comment; #[cfg(memoffset_doctests)] #[cfg(doctest)] doctest!("../README.md"); // This `use` statement enables the macros to use `$crate::mem`. // Doing this enables this crate to function under both std and no-std crates. #[doc(hidden)] pub use core::mem; #[doc(hidden)] pub use core::ptr; #[macro_use] mod offset_of; #[macro_use] mod span_of; memoffset-0.5.3/src/offset_of.rs000064400000000000000000000113241356104634700150130ustar0000000000000000// Copyright (c) 2017 Gilad Naaman // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. /// Macro to create a local `base_ptr` raw pointer of the given type, avoiding UB as /// much as is possible currently. #[cfg(memoffset_maybe_uninit)] #[macro_export] #[doc(hidden)] macro_rules! _memoffset__let_base_ptr { ($name:ident, $type:path) => { // No UB here, and the pointer does not dangle, either. // But we have to make sure that `uninit` lives long enough, // so it has to be in the same scope as `$name`. That's why // `let_base_ptr` declares a variable (several, actually) // instad of returning one. let uninit = $crate::mem::MaybeUninit::<$type>::uninit(); let $name = uninit.as_ptr(); }; } #[cfg(not(memoffset_maybe_uninit))] #[macro_export] #[doc(hidden)] macro_rules! _memoffset__let_base_ptr { ($name:ident, $type:path) => { // No UB right here, but we will later dereference this pointer to // offset into a field, and that is UB when the pointer is dangling. let $name = $crate::mem::align_of::<$type>() as *const $type; }; } /// Deref-coercion protection macro. #[macro_export] #[doc(hidden)] macro_rules! _memoffset__field_check { ($type:path, $field:tt) => { // Make sure the field actually exists. This line ensures that a // compile-time error is generated if $field is accessed through a // Deref impl. let $type { $field: _, .. }; }; } /// Calculates the offset of the specified field from the start of the struct. /// /// ## Examples /// ``` /// #[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); /// } /// ``` #[macro_export(local_inner_macros)] macro_rules! offset_of { ($parent:path, $field:tt) => {{ _memoffset__field_check!($parent, $field); // Get a base pointer. _memoffset__let_base_ptr!(base_ptr, $parent); // Get the field address. This is UB because we are creating a reference to // the uninitialized field. // Crucially, we know that this will not trigger a deref coercion because // of the `field_check!` we did above. #[allow(unused_unsafe)] // for when the macro is used in an unsafe block let field_ptr = unsafe { &(*base_ptr).$field as *const _ }; let offset = (field_ptr as usize) - (base_ptr as usize); offset }}; } #[cfg(test)] mod tests { #[test] fn offset_simple() { #[repr(C)] struct Foo { a: u32, b: [u8; 2], c: i64, } assert_eq!(offset_of!(Foo, a), 0); assert_eq!(offset_of!(Foo, b), 4); assert_eq!(offset_of!(Foo, c), 8); } #[test] #[cfg(not(miri))] // this creates unaligned references fn offset_simple_packed() { #[repr(C, packed)] struct Foo { a: u32, b: [u8; 2], c: i64, } assert_eq!(offset_of!(Foo, a), 0); assert_eq!(offset_of!(Foo, b), 4); assert_eq!(offset_of!(Foo, c), 6); } #[test] fn tuple_struct() { #[repr(C)] struct Tup(i32, i32); assert_eq!(offset_of!(Tup, 0), 0); assert_eq!(offset_of!(Tup, 1), 4); } #[test] fn path() { mod sub { #[repr(C)] pub struct Foo { pub x: u32, } } assert_eq!(offset_of!(sub::Foo, x), 0); } } memoffset-0.5.3/src/span_of.rs000064400000000000000000000215171355751260400144720ustar0000000000000000// Copyright (c) 2017 Gilad Naaman // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. /// Reexport for `local_inner_macros`; see /// . #[doc(hidden)] #[macro_export] macro_rules! _memoffset__compile_error { ($($inner:tt)*) => { compile_error! { $($inner)* } } } /// 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. /// /// ```ignore /// span_of!(Struct, member) /// ``` /// /// 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 /// // Exclusive /// span_of!(Struct, member_a .. member_b) /// // Inclusive /// span_of!(Struct, member_a ..= member_b) /// /// // Open-ended ranges /// span_of!(Struct, .. end) /// span_of!(Struct, start ..) /// ``` /// /// *Note*: /// This macro uses recursion in order to resolve the range expressions, so there is a limit to /// the complexity of the expression. /// In order to raise the limit, the compiler's recursion limit should be lifted. /// /// ## Examples /// ``` /// #[macro_use] /// extern crate memoffset; /// /// #[repr(C)] /// struct Florp { /// a: u32 /// } /// /// #[repr(C)] /// struct Blarg { /// x: [u32; 2], /// y: [u8; 56], /// z: Florp, /// egg: [[u8; 4]; 4] /// } /// /// fn main() { /// assert_eq!(0..84, span_of!(Blarg, ..)); /// assert_eq!(0..8, span_of!(Blarg, .. y)); /// assert_eq!(0..64, span_of!(Blarg, ..= y)); /// assert_eq!(0..8, span_of!(Blarg, x)); /// assert_eq!(8..84, span_of!(Blarg, y ..)); /// assert_eq!(0..8, span_of!(Blarg, x .. y)); /// assert_eq!(0..64, span_of!(Blarg, x ..= y)); /// } /// ``` #[macro_export(local_inner_macros)] macro_rules! span_of { (@helper $root:ident, [] ..=) => { _memoffset__compile_error!("Expected a range, found '..='") }; (@helper $root:ident, [] ..) => { _memoffset__compile_error!("Expected a range, found '..'") }; // Lots of UB due to taking references to uninitialized fields! But that can currently // not be avoided. // No explicit begin for range. (@helper $root:ident, $parent:path, [] ..) => {{ ($root as usize, $root as usize + $crate::mem::size_of_val(&(*$root))) }}; (@helper $root:ident, $parent:path, [] ..= $field:tt) => {{ _memoffset__field_check!($parent, $field); ($root as usize, &(*$root).$field as *const _ as usize + $crate::mem::size_of_val(&(*$root).$field)) }}; (@helper $root:ident, $parent:path, [] .. $field:tt) => {{ _memoffset__field_check!($parent, $field); ($root as usize, &(*$root).$field as *const _ as usize) }}; // Explicit begin and end for range. (@helper $root:ident, $parent:path, # $begin:tt [] ..= $end:tt) => {{ _memoffset__field_check!($parent, $begin); _memoffset__field_check!($parent, $end); (&(*$root).$begin as *const _ as usize, &(*$root).$end as *const _ as usize + $crate::mem::size_of_val(&(*$root).$end)) }}; (@helper $root:ident, $parent:path, # $begin:tt [] .. $end:tt) => {{ _memoffset__field_check!($parent, $begin); _memoffset__field_check!($parent, $end); (&(*$root).$begin as *const _ as usize, &(*$root).$end as *const _ as usize) }}; // No explicit end for range. (@helper $root:ident, $parent:path, # $begin:tt [] ..) => {{ _memoffset__field_check!($parent, $begin); (&(*$root).$begin as *const _ as usize, $root as usize + $crate::mem::size_of_val(&*$root)) }}; (@helper $root:ident, $parent:path, # $begin:tt [] ..=) => {{ _memoffset__compile_error!( "Found inclusive range to the end of a struct. Did you mean '..' instead of '..='?") }}; // Just one field. (@helper $root:ident, $parent:path, # $begin:tt []) => {{ _memoffset__field_check!($parent, $begin); (&(*$root).$begin as *const _ as usize, &(*$root).$begin as *const _ as usize + $crate::mem::size_of_val(&(*$root).$begin)) }}; // Parsing. (@helper $root:ident, $parent:path, $(# $begin:tt)+ [] $tt:tt $($rest:tt)*) => {{ span_of!(@helper $root, $parent, $(#$begin)* #$tt [] $($rest)*) }}; (@helper $root:ident, $parent:path, [] $tt:tt $($rest:tt)*) => {{ span_of!(@helper $root, $parent, #$tt [] $($rest)*) }}; // Entry point. ($sty:path, $($exp:tt)+) => ({ unsafe { // Get a base pointer. _memoffset__let_base_ptr!(root, $sty); let base = root as usize; let (begin, end) = span_of!(@helper root, $sty, [] $($exp)*); begin-base..end-base } }); } #[cfg(test)] mod tests { use core::mem; #[test] fn span_simple() { #[repr(C)] struct Foo { a: u32, b: [u8; 2], c: i64, } assert_eq!(span_of!(Foo, a), 0..4); assert_eq!(span_of!(Foo, b), 4..6); assert_eq!(span_of!(Foo, c), 8..8 + 8); } #[test] #[cfg(not(miri))] // this creates unaligned references fn span_simple_packed() { #[repr(C, packed)] struct Foo { a: u32, b: [u8; 2], c: i64, } assert_eq!(span_of!(Foo, a), 0..4); assert_eq!(span_of!(Foo, b), 4..6); assert_eq!(span_of!(Foo, c), 6..6 + 8); } #[test] fn span_forms() { #[repr(C)] struct Florp { a: u32, } #[repr(C)] struct Blarg { x: u64, y: [u8; 56], z: Florp, egg: [[u8; 4]; 5], } // Love me some brute force assert_eq!(0..8, span_of!(Blarg, x)); assert_eq!(64..68, span_of!(Blarg, z)); assert_eq!(68..mem::size_of::(), span_of!(Blarg, egg)); assert_eq!(8..64, span_of!(Blarg, y..z)); assert_eq!(0..64, span_of!(Blarg, x..=y)); } #[test] fn ig_test() { #[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, ..z), 0..64); assert_eq!(span_of!(Test, ..=z), 0..68); assert_eq!(span_of!(Test, ..egg), 0..68); assert_eq!(span_of!(Test, ..=egg), 0..84); assert_eq!(span_of!(Test, ..), 0..mem::size_of::()); assert_eq!( span_of!(Test, x..), offset_of!(Test, x)..mem::size_of::() ); assert_eq!( span_of!(Test, y..), offset_of!(Test, y)..mem::size_of::() ); assert_eq!( span_of!(Test, z..), offset_of!(Test, z)..mem::size_of::() ); assert_eq!( span_of!(Test, egg..), offset_of!(Test, egg)..mem::size_of::() ); 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]>() ); } } memoffset-0.5.3/.cargo_vcs_info.json0000644000000001121356104646200131250ustar00{ "git": { "sha1": "c0ad55cb4a2f8e972864036d9cff52a6f4b0d204" } }