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