160636f74Sopenharmony_ci// Copyright (c) 2020 Gilad Naaman, Ralf Jung
260636f74Sopenharmony_ci//
360636f74Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a copy
460636f74Sopenharmony_ci// of this software and associated documentation files (the "Software"), to deal
560636f74Sopenharmony_ci// in the Software without restriction, including without limitation the rights
660636f74Sopenharmony_ci// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
760636f74Sopenharmony_ci// copies of the Software, and to permit persons to whom the Software is
860636f74Sopenharmony_ci// furnished to do so, subject to the following conditions:
960636f74Sopenharmony_ci//
1060636f74Sopenharmony_ci// The above copyright notice and this permission notice shall be included in all
1160636f74Sopenharmony_ci// copies or substantial portions of the Software.
1260636f74Sopenharmony_ci//
1360636f74Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1460636f74Sopenharmony_ci// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1560636f74Sopenharmony_ci// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1660636f74Sopenharmony_ci// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1760636f74Sopenharmony_ci// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1860636f74Sopenharmony_ci// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1960636f74Sopenharmony_ci// SOFTWARE.
2060636f74Sopenharmony_ci
2160636f74Sopenharmony_ci/// `addr_of!`, or just ref-then-cast when that is not available.
2260636f74Sopenharmony_ci#[cfg(raw_ref_macros)]
2360636f74Sopenharmony_ci#[macro_export]
2460636f74Sopenharmony_ci#[doc(hidden)]
2560636f74Sopenharmony_cimacro_rules! _memoffset__addr_of {
2660636f74Sopenharmony_ci    ($path:expr) => {{
2760636f74Sopenharmony_ci        $crate::__priv::ptr::addr_of!($path)
2860636f74Sopenharmony_ci    }};
2960636f74Sopenharmony_ci}
3060636f74Sopenharmony_ci#[cfg(not(raw_ref_macros))]
3160636f74Sopenharmony_ci#[macro_export]
3260636f74Sopenharmony_ci#[doc(hidden)]
3360636f74Sopenharmony_cimacro_rules! _memoffset__addr_of {
3460636f74Sopenharmony_ci    ($path:expr) => {{
3560636f74Sopenharmony_ci        // This is UB because we create an intermediate reference to uninitialized memory.
3660636f74Sopenharmony_ci        // Nothing we can do about that without `addr_of!` though.
3760636f74Sopenharmony_ci        &$path as *const _
3860636f74Sopenharmony_ci    }};
3960636f74Sopenharmony_ci}
4060636f74Sopenharmony_ci
4160636f74Sopenharmony_ci/// Deref-coercion protection macro.
4260636f74Sopenharmony_ci///
4360636f74Sopenharmony_ci/// Prevents complilation if the specified field name is not a part of the
4460636f74Sopenharmony_ci/// struct definition.
4560636f74Sopenharmony_ci///
4660636f74Sopenharmony_ci/// ```compile_fail
4760636f74Sopenharmony_ci/// use memoffset::_memoffset__field_check;
4860636f74Sopenharmony_ci///
4960636f74Sopenharmony_ci/// struct Foo {
5060636f74Sopenharmony_ci///     foo: i32,
5160636f74Sopenharmony_ci/// }
5260636f74Sopenharmony_ci///
5360636f74Sopenharmony_ci/// type BoxedFoo = Box<Foo>;
5460636f74Sopenharmony_ci///
5560636f74Sopenharmony_ci/// _memoffset__field_check!(BoxedFoo, foo);
5660636f74Sopenharmony_ci/// ```
5760636f74Sopenharmony_ci#[cfg(allow_clippy)]
5860636f74Sopenharmony_ci#[macro_export]
5960636f74Sopenharmony_ci#[doc(hidden)]
6060636f74Sopenharmony_cimacro_rules! _memoffset__field_check {
6160636f74Sopenharmony_ci    ($type:path, $field:tt) => {
6260636f74Sopenharmony_ci        // Make sure the field actually exists. This line ensures that a
6360636f74Sopenharmony_ci        // compile-time error is generated if $field is accessed through a
6460636f74Sopenharmony_ci        // Deref impl.
6560636f74Sopenharmony_ci        #[allow(clippy::unneeded_field_pattern)]
6660636f74Sopenharmony_ci        let $type { $field: _, .. };
6760636f74Sopenharmony_ci    };
6860636f74Sopenharmony_ci}
6960636f74Sopenharmony_ci#[cfg(not(allow_clippy))]
7060636f74Sopenharmony_ci#[macro_export]
7160636f74Sopenharmony_ci#[doc(hidden)]
7260636f74Sopenharmony_cimacro_rules! _memoffset__field_check {
7360636f74Sopenharmony_ci    ($type:path, $field:tt) => {
7460636f74Sopenharmony_ci        // Make sure the field actually exists. This line ensures that a
7560636f74Sopenharmony_ci        // compile-time error is generated if $field is accessed through a
7660636f74Sopenharmony_ci        // Deref impl.
7760636f74Sopenharmony_ci        let $type { $field: _, .. };
7860636f74Sopenharmony_ci    };
7960636f74Sopenharmony_ci}
8060636f74Sopenharmony_ci
8160636f74Sopenharmony_ci/// Deref-coercion protection macro.
8260636f74Sopenharmony_ci///
8360636f74Sopenharmony_ci/// Prevents complilation if the specified type is not a tuple.
8460636f74Sopenharmony_ci///
8560636f74Sopenharmony_ci/// ```compile_fail
8660636f74Sopenharmony_ci/// use memoffset::_memoffset__field_check_tuple;
8760636f74Sopenharmony_ci///
8860636f74Sopenharmony_ci/// _memoffset__field_check_tuple!(i32, 0);
8960636f74Sopenharmony_ci/// ```
9060636f74Sopenharmony_ci#[cfg(allow_clippy)]
9160636f74Sopenharmony_ci#[macro_export]
9260636f74Sopenharmony_ci#[doc(hidden)]
9360636f74Sopenharmony_cimacro_rules! _memoffset__field_check_tuple {
9460636f74Sopenharmony_ci    ($type:ty, $field:tt) => {
9560636f74Sopenharmony_ci        // Make sure the type argument is a tuple
9660636f74Sopenharmony_ci        #[allow(clippy::unneeded_wildcard_pattern)]
9760636f74Sopenharmony_ci        let (_, ..): $type;
9860636f74Sopenharmony_ci    };
9960636f74Sopenharmony_ci}
10060636f74Sopenharmony_ci#[cfg(not(allow_clippy))]
10160636f74Sopenharmony_ci#[macro_export]
10260636f74Sopenharmony_ci#[doc(hidden)]
10360636f74Sopenharmony_cimacro_rules! _memoffset__field_check_tuple {
10460636f74Sopenharmony_ci    ($type:ty, $field:tt) => {
10560636f74Sopenharmony_ci        // Make sure the type argument is a tuple
10660636f74Sopenharmony_ci        let (_, ..): $type;
10760636f74Sopenharmony_ci    };
10860636f74Sopenharmony_ci}
10960636f74Sopenharmony_ci
11060636f74Sopenharmony_ci/// Deref-coercion protection macro for unions.
11160636f74Sopenharmony_ci/// Unfortunately accepts single-field structs as well, which is not ideal,
11260636f74Sopenharmony_ci/// but ultimately pretty harmless.
11360636f74Sopenharmony_ci///
11460636f74Sopenharmony_ci/// ```compile_fail
11560636f74Sopenharmony_ci/// use memoffset::_memoffset__field_check_union;
11660636f74Sopenharmony_ci///
11760636f74Sopenharmony_ci/// union Foo {
11860636f74Sopenharmony_ci///     variant_a: i32,
11960636f74Sopenharmony_ci/// }
12060636f74Sopenharmony_ci///
12160636f74Sopenharmony_ci/// type BoxedFoo = Box<Foo>;
12260636f74Sopenharmony_ci///
12360636f74Sopenharmony_ci/// _memoffset__field_check_union!(BoxedFoo, variant_a);
12460636f74Sopenharmony_ci/// ```
12560636f74Sopenharmony_ci#[cfg(allow_clippy)]
12660636f74Sopenharmony_ci#[macro_export]
12760636f74Sopenharmony_ci#[doc(hidden)]
12860636f74Sopenharmony_cimacro_rules! _memoffset__field_check_union {
12960636f74Sopenharmony_ci    ($type:path, $field:tt) => {
13060636f74Sopenharmony_ci        // Make sure the field actually exists. This line ensures that a
13160636f74Sopenharmony_ci        // compile-time error is generated if $field is accessed through a
13260636f74Sopenharmony_ci        // Deref impl.
13360636f74Sopenharmony_ci        #[allow(clippy::unneeded_wildcard_pattern)]
13460636f74Sopenharmony_ci        // rustc1.19 requires unsafe here for the pattern; not needed in newer versions
13560636f74Sopenharmony_ci        #[allow(unused_unsafe)]
13660636f74Sopenharmony_ci        unsafe {
13760636f74Sopenharmony_ci            let $type { $field: _ };
13860636f74Sopenharmony_ci        }
13960636f74Sopenharmony_ci    };
14060636f74Sopenharmony_ci}
14160636f74Sopenharmony_ci#[cfg(not(allow_clippy))]
14260636f74Sopenharmony_ci#[macro_export]
14360636f74Sopenharmony_ci#[doc(hidden)]
14460636f74Sopenharmony_cimacro_rules! _memoffset__field_check_union {
14560636f74Sopenharmony_ci    ($type:path, $field:tt) => {
14660636f74Sopenharmony_ci        // Make sure the field actually exists. This line ensures that a
14760636f74Sopenharmony_ci        // compile-time error is generated if $field is accessed through a
14860636f74Sopenharmony_ci        // Deref impl.
14960636f74Sopenharmony_ci        // rustc1.19 requires unsafe here for the pattern; not needed in newer versions
15060636f74Sopenharmony_ci        #[allow(unused_unsafe)]
15160636f74Sopenharmony_ci        unsafe {
15260636f74Sopenharmony_ci            let $type { $field: _ };
15360636f74Sopenharmony_ci        }
15460636f74Sopenharmony_ci    };
15560636f74Sopenharmony_ci}
15660636f74Sopenharmony_ci
15760636f74Sopenharmony_ci/// Computes a const raw pointer to the given field of the given base pointer
15860636f74Sopenharmony_ci/// to the given parent type.
15960636f74Sopenharmony_ci///
16060636f74Sopenharmony_ci/// The `base` pointer *must not* be dangling, but it *may* point to
16160636f74Sopenharmony_ci/// uninitialized memory.
16260636f74Sopenharmony_ci#[macro_export(local_inner_macros)]
16360636f74Sopenharmony_cimacro_rules! raw_field {
16460636f74Sopenharmony_ci    ($base:expr, $parent:path, $field:tt) => {{
16560636f74Sopenharmony_ci        _memoffset__field_check!($parent, $field);
16660636f74Sopenharmony_ci        let base = $base; // evaluate $base outside the `unsafe` block
16760636f74Sopenharmony_ci
16860636f74Sopenharmony_ci        // Get the field address.
16960636f74Sopenharmony_ci        // Crucially, we know that this will not trigger a deref coercion because
17060636f74Sopenharmony_ci        // of the field check we did above.
17160636f74Sopenharmony_ci        #[allow(unused_unsafe)] // for when the macro is used in an unsafe block
17260636f74Sopenharmony_ci        unsafe {
17360636f74Sopenharmony_ci            _memoffset__addr_of!((*(base as *const $parent)).$field)
17460636f74Sopenharmony_ci        }
17560636f74Sopenharmony_ci    }};
17660636f74Sopenharmony_ci}
17760636f74Sopenharmony_ci
17860636f74Sopenharmony_ci/// Computes a const raw pointer to the given field of the given base pointer
17960636f74Sopenharmony_ci/// to the given parent tuple typle.
18060636f74Sopenharmony_ci///
18160636f74Sopenharmony_ci/// The `base` pointer *must not* be dangling, but it *may* point to
18260636f74Sopenharmony_ci/// uninitialized memory.
18360636f74Sopenharmony_ci#[cfg(tuple_ty)]
18460636f74Sopenharmony_ci#[macro_export(local_inner_macros)]
18560636f74Sopenharmony_cimacro_rules! raw_field_tuple {
18660636f74Sopenharmony_ci    ($base:expr, $parent:ty, $field:tt) => {{
18760636f74Sopenharmony_ci        _memoffset__field_check_tuple!($parent, $field);
18860636f74Sopenharmony_ci        let base = $base; // evaluate $base outside the `unsafe` block
18960636f74Sopenharmony_ci
19060636f74Sopenharmony_ci        // Get the field address.
19160636f74Sopenharmony_ci        // Crucially, we know that this will not trigger a deref coercion because
19260636f74Sopenharmony_ci        // of the field check we did above.
19360636f74Sopenharmony_ci        #[allow(unused_unsafe)] // for when the macro is used in an unsafe block
19460636f74Sopenharmony_ci        unsafe {
19560636f74Sopenharmony_ci            _memoffset__addr_of!((*(base as *const $parent)).$field)
19660636f74Sopenharmony_ci        }
19760636f74Sopenharmony_ci    }};
19860636f74Sopenharmony_ci}
19960636f74Sopenharmony_ci
20060636f74Sopenharmony_ci/// Computes a const raw pointer to the given field of the given base pointer
20160636f74Sopenharmony_ci/// to the given parent tuple typle.
20260636f74Sopenharmony_ci///
20360636f74Sopenharmony_ci/// The `base` pointer *must not* be dangling, but it *may* point to
20460636f74Sopenharmony_ci/// uninitialized memory.
20560636f74Sopenharmony_ci///
20660636f74Sopenharmony_ci/// ## Note
20760636f74Sopenharmony_ci/// This macro is the same as `raw_field`, except for a different Deref-coercion check that
20860636f74Sopenharmony_ci/// supports unions.
20960636f74Sopenharmony_ci/// Due to macro_rules limitations, this check will accept structs with a single field as well as unions.
21060636f74Sopenharmony_ci/// This is not a stable guarantee, and future versions of this crate might fail
21160636f74Sopenharmony_ci/// on any use of this macro with a struct, without a semver bump.
21260636f74Sopenharmony_ci#[macro_export(local_inner_macros)]
21360636f74Sopenharmony_cimacro_rules! raw_field_union {
21460636f74Sopenharmony_ci    ($base:expr, $parent:path, $field:tt) => {{
21560636f74Sopenharmony_ci        _memoffset__field_check_union!($parent, $field);
21660636f74Sopenharmony_ci        let base = $base; // evaluate $base outside the `unsafe` block
21760636f74Sopenharmony_ci
21860636f74Sopenharmony_ci        // Get the field address.
21960636f74Sopenharmony_ci        // Crucially, we know that this will not trigger a deref coercion because
22060636f74Sopenharmony_ci        // of the field check we did above.
22160636f74Sopenharmony_ci        #[allow(unused_unsafe)] // for when the macro is used in an unsafe block
22260636f74Sopenharmony_ci        unsafe {
22360636f74Sopenharmony_ci            _memoffset__addr_of!((*(base as *const $parent)).$field)
22460636f74Sopenharmony_ci        }
22560636f74Sopenharmony_ci    }};
22660636f74Sopenharmony_ci}
227