summaryrefslogtreecommitdiffstats
path: root/vendor/field-offset
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/field-offset')
-rw-r--r--vendor/field-offset/.cargo-checksum.json1
-rw-r--r--vendor/field-offset/Cargo.toml25
-rw-r--r--vendor/field-offset/LICENSE-APACHE176
-rw-r--r--vendor/field-offset/LICENSE-MIT21
-rw-r--r--vendor/field-offset/README.md34
-rw-r--r--vendor/field-offset/build.rs17
-rw-r--r--vendor/field-offset/src/lib.rs528
7 files changed, 802 insertions, 0 deletions
diff --git a/vendor/field-offset/.cargo-checksum.json b/vendor/field-offset/.cargo-checksum.json
new file mode 100644
index 000000000..ea52156b9
--- /dev/null
+++ b/vendor/field-offset/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"a37868c945b9b9372bc52e8a87a6eb7841dd9cce5c76b75c7a69cf8a992a3014","LICENSE-APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE-MIT":"9dd44491b4cf95dcfa2963943b3ae91bff9a78d13049a9e0b53e0d0b0a9c8f4e","README.md":"7affe2265eb804c7f6ce1d9a95b499f4c88d8b902865d7b1f0122ec6163f07b8","build.rs":"96d9e17f58fc09f2231ed0571c542ff79c71e8cf89ae2c208928899ffb471308","src/lib.rs":"0917ce4c9ab3e15434182df60daabb7ded15f7b863938cdc7f73be60d6e9ae44"},"package":"a3cf3a800ff6e860c863ca6d4b16fd999db8b752819c1606884047b73e468535"} \ No newline at end of file
diff --git a/vendor/field-offset/Cargo.toml b/vendor/field-offset/Cargo.toml
new file mode 100644
index 000000000..fccc0288d
--- /dev/null
+++ b/vendor/field-offset/Cargo.toml
@@ -0,0 +1,25 @@
+# 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 are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+name = "field-offset"
+version = "0.3.5"
+authors = ["Diggory Blake <diggsey@googlemail.com>"]
+description = "Safe pointer-to-member implementation"
+readme = "README.md"
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/Diggsey/rust-field-offset"
+
+[dependencies.memoffset]
+version = "0.8"
+
+[build-dependencies.rustc_version]
+version = "0.4.0"
diff --git a/vendor/field-offset/LICENSE-APACHE b/vendor/field-offset/LICENSE-APACHE
new file mode 100644
index 000000000..d9a10c0d8
--- /dev/null
+++ b/vendor/field-offset/LICENSE-APACHE
@@ -0,0 +1,176 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
diff --git a/vendor/field-offset/LICENSE-MIT b/vendor/field-offset/LICENSE-MIT
new file mode 100644
index 000000000..b4ab2017c
--- /dev/null
+++ b/vendor/field-offset/LICENSE-MIT
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016-2021 Diggory Blake, and other contributors.
+
+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.
diff --git a/vendor/field-offset/README.md b/vendor/field-offset/README.md
new file mode 100644
index 000000000..8ebdf7903
--- /dev/null
+++ b/vendor/field-offset/README.md
@@ -0,0 +1,34 @@
+# field-offset: safe pointer-to-member functionality
+
+This crate implements an `offset_of!(...)` macro which safely encapsulates
+a pointer-to-member.
+
+Example:
+```rust
+struct Foo {
+ x: u32,
+ y: f64
+}
+
+let foo_y = offset_of!(Foo => y);
+
+let mut a = Foo { x: 1, y: 2.0 };
+
+*foo_y.apply_mut(&mut a) = 3.0;
+
+assert!(a.y == 3.0);
+```
+
+The macro returns an instance of `FieldOffset<T, U>`, which represents a
+pointer to a field of type `U` within a containing type, `T`.
+
+The `FieldOffset` type implements `Add`. Applying the resulting field offset
+is equivalent to applying the first field offset, then applying the second
+field offset.
+
+The macro also supports accessing nested fields:
+
+```rust
+let bar_foo_y = offset_of!(Bar => foo: Foo => y);
+```
+
diff --git a/vendor/field-offset/build.rs b/vendor/field-offset/build.rs
new file mode 100644
index 000000000..a2f7a0353
--- /dev/null
+++ b/vendor/field-offset/build.rs
@@ -0,0 +1,17 @@
+extern crate rustc_version;
+use rustc_version::{version, version_meta, Channel, Version};
+
+fn main() {
+ // Assert we haven't travelled back in time
+ assert!(version().unwrap().major >= 1);
+
+ // Check for a minimum version
+ if version().unwrap() >= Version::parse("1.36.0").unwrap() {
+ println!("cargo:rustc-cfg=fieldoffset_maybe_uninit");
+ println!("cargo:rustc-cfg=fieldoffset_has_alloc");
+ }
+
+ if version_meta().unwrap().channel == Channel::Nightly {
+ println!("cargo:rustc-cfg=fieldoffset_assert_in_const_fn");
+ }
+}
diff --git a/vendor/field-offset/src/lib.rs b/vendor/field-offset/src/lib.rs
new file mode 100644
index 000000000..b0a12c779
--- /dev/null
+++ b/vendor/field-offset/src/lib.rs
@@ -0,0 +1,528 @@
+#![no_std]
+#![cfg_attr(fieldoffset_assert_in_const_fn, feature(const_panic))]
+// Explicit lifetimes are clearer when we are working with raw pointers,
+// as the compiler will not warn us if we specify lifetime constraints
+// which are too lax.
+#![allow(clippy::needless_lifetimes)]
+
+#[cfg(all(test, fieldoffset_has_alloc))]
+extern crate alloc;
+
+use core::fmt;
+use core::marker::PhantomData;
+use core::mem;
+use core::ops::Add;
+use core::pin::Pin;
+
+#[doc(hidden)]
+pub extern crate memoffset as __memoffset; // `pub` for macro availability
+
+/// Represents a pointer to a field of type `U` within the type `T`
+///
+/// The `PinFlag` parameter can be set to `AllowPin` to enable the projection
+/// from Pin<&T> to Pin<&U>
+#[repr(transparent)]
+pub struct FieldOffset<T, U, PinFlag = NotPinned>(
+ /// Offset in bytes of the field within the struct
+ usize,
+ /// A pointer-to-member can be thought of as a function from
+ /// `&T` to `&U` with matching lifetimes
+ ///
+ /// ```compile_fail
+ /// use field_offset::FieldOffset;
+ /// struct Foo<'a>(&'a str);
+ /// fn test<'a>(foo: &Foo<'a>, of: FieldOffset<Foo<'static>, &'static str>) -> &'static str {
+ /// let of2 : FieldOffset<Foo<'a>, &'static str> = of; // This must not compile
+ /// of2.apply(foo)
+ /// }
+ /// ```
+ /// That should compile:
+ /// ```
+ /// use field_offset::FieldOffset;
+ /// struct Foo<'a>(&'a str, &'static str);
+ /// fn test<'a>(foo: &'a Foo<'static>, of: FieldOffset<Foo, &'static str>) -> &'a str {
+ /// let of2 : FieldOffset<Foo<'static>, &'static str> = of;
+ /// of.apply(foo)
+ /// }
+ /// fn test2(foo: &Foo<'static>, of: FieldOffset<Foo, &'static str>) -> &'static str {
+ /// let of2 : FieldOffset<Foo<'static>, &'static str> = of;
+ /// of.apply(foo)
+ /// }
+ /// fn test3<'a>(foo: &'a Foo, of: FieldOffset<Foo<'a>, &'a str>) -> &'a str {
+ /// of.apply(foo)
+ /// }
+ /// ```
+ PhantomData<(PhantomContra<T>, U, PinFlag)>,
+);
+
+/// `fn` cannot appear directly in a type that need to be const.
+/// Workaround that with an indirection
+struct PhantomContra<T>(fn(T));
+
+/// Type that can be used in the `PinFlag` parameter of `FieldOffset` to specify that
+/// this projection is valid on Pin types.
+/// See documentation of `FieldOffset::new_from_offset_pinned`
+pub enum AllowPin {}
+
+/// Type that can be used in the `PinFlag` parameter of `FieldOffset` to specify that
+/// this projection is not valid on Pin types.
+pub enum NotPinned {}
+
+impl<T, U> FieldOffset<T, U, NotPinned> {
+ // Use MaybeUninit to get a fake T
+ #[cfg(fieldoffset_maybe_uninit)]
+ #[inline]
+ fn with_uninit_ptr<R, F: FnOnce(*const T) -> R>(f: F) -> R {
+ let uninit = mem::MaybeUninit::<T>::uninit();
+ f(uninit.as_ptr())
+ }
+
+ // Use a dangling pointer to get a fake T
+ #[cfg(not(fieldoffset_maybe_uninit))]
+ #[inline]
+ fn with_uninit_ptr<R, F: FnOnce(*const T) -> R>(f: F) -> R {
+ f(mem::align_of::<T>() as *const T)
+ }
+
+ /// Construct a field offset via a lambda which returns a reference
+ /// to the field in question.
+ ///
+ /// # Safety
+ ///
+ /// The lambda *must not* dereference the provided pointer or access the
+ /// inner value in any way as it may point to uninitialized memory.
+ ///
+ /// For the returned `FieldOffset` to be safe to use, the returned pointer
+ /// must be valid for *any* instance of `T`. For example, returning a pointer
+ /// to a field from an enum with multiple variants will produce a `FieldOffset`
+ /// which is unsafe to use.
+ pub unsafe fn new<F: for<'a> FnOnce(*const T) -> *const U>(f: F) -> Self {
+ let offset = Self::with_uninit_ptr(|base_ptr| {
+ let field_ptr = f(base_ptr);
+ (field_ptr as usize).wrapping_sub(base_ptr as usize)
+ });
+
+ // Construct an instance using the offset
+ Self::new_from_offset(offset)
+ }
+ /// Construct a field offset directly from a byte offset.
+ ///
+ /// # Safety
+ ///
+ /// For the returned `FieldOffset` to be safe to use, the field offset
+ /// must be valid for *any* instance of `T`. For example, returning the offset
+ /// to a field from an enum with multiple variants will produce a `FieldOffset`
+ /// which is unsafe to use.
+ #[inline]
+ pub const unsafe fn new_from_offset(offset: usize) -> Self {
+ // Sanity check: ensure that the field offset plus the field size
+ // is no greater than the size of the containing struct. This is
+ // not sufficient to make the function *safe*, but it does catch
+ // obvious errors like returning a reference to a boxed value,
+ // which is owned by `T` and so has the correct lifetime, but is not
+ // actually a field.
+ #[cfg(fieldoffset_assert_in_const_fn)]
+ assert!(offset + mem::size_of::<U>() <= mem::size_of::<T>());
+ // On stable rust, we can still get an assert in debug mode,
+ // relying on the checked overflow behaviour
+ let _ = mem::size_of::<T>() - (offset + mem::size_of::<U>());
+
+ FieldOffset(offset, PhantomData)
+ }
+}
+
+// Methods for applying the pointer to member
+impl<T, U, PinFlag> FieldOffset<T, U, PinFlag> {
+ /// Apply the field offset to a native pointer.
+ #[inline]
+ pub fn apply_ptr(self, x: *const T) -> *const U {
+ ((x as usize) + self.0) as *const U
+ }
+ /// Apply the field offset to a native mutable pointer.
+ #[inline]
+ pub fn apply_ptr_mut(self, x: *mut T) -> *mut U {
+ ((x as usize) + self.0) as *mut U
+ }
+ /// Apply the field offset to a reference.
+ #[inline]
+ pub fn apply<'a>(self, x: &'a T) -> &'a U {
+ unsafe { &*self.apply_ptr(x) }
+ }
+ /// Apply the field offset to a mutable reference.
+ #[inline]
+ pub fn apply_mut<'a>(self, x: &'a mut T) -> &'a mut U {
+ unsafe { &mut *self.apply_ptr_mut(x) }
+ }
+ /// Get the raw byte offset for this field offset.
+ #[inline]
+ pub const fn get_byte_offset(self) -> usize {
+ self.0
+ }
+
+ // Methods for unapplying the pointer to member
+
+ /// Unapply the field offset to a native pointer.
+ ///
+ /// # Safety
+ ///
+ /// *Warning: very unsafe!*
+ ///
+ /// This applies a negative offset to a pointer. If the safety
+ /// implications of this are not already clear to you, then *do
+ /// not* use this method. Also be aware that Rust has stronger
+ /// aliasing rules than other languages, so it may be UB to
+ /// dereference the resulting pointer even if it points to a valid
+ /// location, due to the presence of other live references.
+ #[inline]
+ pub unsafe fn unapply_ptr(self, x: *const U) -> *const T {
+ ((x as usize) - self.0) as *const T
+ }
+ /// Unapply the field offset to a native mutable pointer.
+ ///
+ /// # Safety
+ ///
+ /// *Warning: very unsafe!*
+ ///
+ /// This applies a negative offset to a pointer. If the safety
+ /// implications of this are not already clear to you, then *do
+ /// not* use this method. Also be aware that Rust has stronger
+ /// aliasing rules than other languages, so it may be UB to
+ /// dereference the resulting pointer even if it points to a valid
+ /// location, due to the presence of other live references.
+ #[inline]
+ pub unsafe fn unapply_ptr_mut(self, x: *mut U) -> *mut T {
+ ((x as usize) - self.0) as *mut T
+ }
+ /// Unapply the field offset to a reference.
+ ///
+ /// # Safety
+ ///
+ /// *Warning: very unsafe!*
+ ///
+ /// This applies a negative offset to a reference. If the safety
+ /// implications of this are not already clear to you, then *do
+ /// not* use this method. Also be aware that Rust has stronger
+ /// aliasing rules than other languages, so this method may cause UB
+ /// even if the resulting reference points to a valid location, due
+ /// to the presence of other live references.
+ #[inline]
+ pub unsafe fn unapply<'a>(self, x: &'a U) -> &'a T {
+ &*self.unapply_ptr(x)
+ }
+ /// Unapply the field offset to a mutable reference.
+ ///
+ /// # Safety
+ ///
+ /// *Warning: very unsafe!*
+ ///
+ /// This applies a negative offset to a reference. If the safety
+ /// implications of this are not already clear to you, then *do
+ /// not* use this method. Also be aware that Rust has stronger
+ /// aliasing rules than other languages, so this method may cause UB
+ /// even if the resulting reference points to a valid location, due
+ /// to the presence of other live references.
+ #[inline]
+ pub unsafe fn unapply_mut<'a>(self, x: &'a mut U) -> &'a mut T {
+ &mut *self.unapply_ptr_mut(x)
+ }
+
+ /// Convert this offset to an offset that is allowed to go from `Pin<&T>`
+ /// to `Pin<&U>`
+ ///
+ /// # Safety
+ ///
+ /// The Pin safety rules for projection must be respected. These rules are
+ /// explained in the
+ /// [Pin documentation](https://doc.rust-lang.org/stable/std/pin/index.html#pinning-is-structural-for-field)
+ pub const unsafe fn as_pinned_projection(self) -> FieldOffset<T, U, AllowPin> {
+ FieldOffset::new_from_offset_pinned(self.get_byte_offset())
+ }
+
+ /// Remove the AllowPin flag
+ pub const fn as_unpinned_projection(self) -> FieldOffset<T, U, NotPinned> {
+ unsafe { FieldOffset::new_from_offset(self.get_byte_offset()) }
+ }
+}
+
+impl<T, U> FieldOffset<T, U, AllowPin> {
+ /// Construct a field offset directly from a byte offset, which can be projected from
+ /// a pinned.
+ ///
+ /// # Safety
+ ///
+ /// In addition to the safety rules of FieldOffset::new_from_offset, the projection
+ /// from `Pin<&T>` to `Pin<&U>` must also be allowed. The rules are explained in the
+ /// [Pin documentation](https://doc.rust-lang.org/stable/std/pin/index.html#pinning-is-structural-for-field)
+ #[inline]
+ pub const unsafe fn new_from_offset_pinned(offset: usize) -> Self {
+ FieldOffset(offset, PhantomData)
+ }
+
+ /// Apply the field offset to a pinned reference and return a pinned
+ /// reference to the field
+ #[inline]
+ pub fn apply_pin<'a>(self, x: Pin<&'a T>) -> Pin<&'a U> {
+ unsafe { x.map_unchecked(|x| self.apply(x)) }
+ }
+ /// Apply the field offset to a pinned mutable reference and return a
+ /// pinned mutable reference to the field
+ #[inline]
+ pub fn apply_pin_mut<'a>(self, x: Pin<&'a mut T>) -> Pin<&'a mut U> {
+ unsafe { x.map_unchecked_mut(|x| self.apply_mut(x)) }
+ }
+}
+
+impl<T, U> From<FieldOffset<T, U, AllowPin>> for FieldOffset<T, U, NotPinned> {
+ fn from(other: FieldOffset<T, U, AllowPin>) -> Self {
+ other.as_unpinned_projection()
+ }
+}
+
+/// Allow chaining pointer-to-members.
+///
+/// Applying the resulting field offset is equivalent to applying the first
+/// field offset, then applying the second field offset.
+///
+/// The requirements on the generic type parameters ensure this is a safe operation.
+impl<T, U, V> Add<FieldOffset<U, V>> for FieldOffset<T, U> {
+ type Output = FieldOffset<T, V>;
+ #[inline]
+ fn add(self, other: FieldOffset<U, V>) -> FieldOffset<T, V> {
+ FieldOffset(self.0 + other.0, PhantomData)
+ }
+}
+impl<T, U, V> Add<FieldOffset<U, V, AllowPin>> for FieldOffset<T, U, AllowPin> {
+ type Output = FieldOffset<T, V, AllowPin>;
+ #[inline]
+ fn add(self, other: FieldOffset<U, V, AllowPin>) -> FieldOffset<T, V, AllowPin> {
+ FieldOffset(self.0 + other.0, PhantomData)
+ }
+}
+impl<T, U, V> Add<FieldOffset<U, V>> for FieldOffset<T, U, AllowPin> {
+ type Output = FieldOffset<T, V>;
+ #[inline]
+ fn add(self, other: FieldOffset<U, V>) -> FieldOffset<T, V> {
+ FieldOffset(self.0 + other.0, PhantomData)
+ }
+}
+impl<T, U, V> Add<FieldOffset<U, V, AllowPin>> for FieldOffset<T, U> {
+ type Output = FieldOffset<T, V>;
+ #[inline]
+ fn add(self, other: FieldOffset<U, V, AllowPin>) -> FieldOffset<T, V> {
+ FieldOffset(self.0 + other.0, PhantomData)
+ }
+}
+
+/// The debug implementation prints the byte offset of the field in hexadecimal.
+impl<T, U, Flag> fmt::Debug for FieldOffset<T, U, Flag> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(f, "FieldOffset({:#x})", self.0)
+ }
+}
+
+impl<T, U, Flag> Copy for FieldOffset<T, U, Flag> {}
+impl<T, U, Flag> Clone for FieldOffset<T, U, Flag> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+/// This macro allows safe construction of a FieldOffset,
+/// by generating a known to be valid lambda to pass to the
+/// constructor. It takes a type, and the identifier of a field
+/// within that type as input.
+///
+/// Examples:
+///
+/// Offset of field `Foo.bar`
+///
+/// ```rust
+/// # #[macro_use]
+/// # extern crate field_offset;
+/// # fn main() {
+/// #[repr(C)]
+/// struct Foo { foo: i32, bar: i32 }
+/// assert_eq!(offset_of!(Foo => bar).get_byte_offset(), 4);
+/// # }
+/// ```
+///
+/// Offset of nested field `Foo.bar.x`
+///
+/// ```rust
+/// # #[macro_use]
+/// # extern crate field_offset;
+/// # fn main() {
+/// struct Bar { a: u8, x: u8 }
+/// struct Foo { foo: i32, bar: Bar }
+/// assert_eq!(offset_of!(Foo => bar: Bar => x).get_byte_offset(), 5);
+/// # }
+/// ```
+#[macro_export]
+macro_rules! offset_of {
+ ($t: path => $f: tt) => {{
+ // Construct the offset
+ #[allow(unused_unsafe)]
+ unsafe {
+ $crate::FieldOffset::<$t, _>::new(|x| {
+ $crate::__memoffset::raw_field!(x, $t, $f)
+ })
+ }
+ }};
+ ($t: path => $f: ident: $($rest: tt)*) => {
+ offset_of!($t => $f) + offset_of!($($rest)*)
+ };
+}
+
+#[cfg(test)]
+mod tests {
+ // Example structs
+ #[derive(Debug)]
+ struct Foo {
+ a: u32,
+ b: f64,
+ c: bool,
+ }
+
+ #[derive(Debug)]
+ struct Bar {
+ x: u32,
+ y: Foo,
+ }
+
+ #[derive(Debug)]
+ struct Tuple(i32, f64);
+
+ #[test]
+ fn test_simple() {
+ // Get a pointer to `b` within `Foo`
+ let foo_b = offset_of!(Foo => b);
+
+ // Construct an example `Foo`
+ let mut x = Foo {
+ a: 1,
+ b: 2.0,
+ c: false,
+ };
+
+ // Apply the pointer to get at `b` and read it
+ {
+ let y = foo_b.apply(&x);
+ assert_eq!(*y, 2.0);
+ }
+
+ // Apply the pointer to get at `b` and mutate it
+ {
+ let y = foo_b.apply_mut(&mut x);
+ *y = 42.0;
+ }
+ assert_eq!(x.b, 42.0);
+ }
+
+ #[test]
+ fn test_tuple() {
+ // Get a pointer to `b` within `Foo`
+ let tuple_1 = offset_of!(Tuple => 1);
+
+ // Construct an example `Foo`
+ let mut x = Tuple(1, 42.0);
+
+ // Apply the pointer to get at `b` and read it
+ {
+ let y = tuple_1.apply(&x);
+ assert_eq!(*y, 42.0);
+ }
+
+ // Apply the pointer to get at `b` and mutate it
+ {
+ let y = tuple_1.apply_mut(&mut x);
+ *y = 5.0;
+ }
+ assert_eq!(x.1, 5.0);
+ }
+
+ #[test]
+ fn test_nested() {
+ // Construct an example `Foo`
+ let mut x = Bar {
+ x: 0,
+ y: Foo {
+ a: 1,
+ b: 2.0,
+ c: false,
+ },
+ };
+
+ // Combine the pointer-to-members
+ let bar_y_b = offset_of!(Bar => y: Foo => b);
+
+ // Apply the pointer to get at `b` and mutate it
+ {
+ let y = bar_y_b.apply_mut(&mut x);
+ *y = 42.0;
+ }
+ assert_eq!(x.y.b, 42.0);
+ }
+
+ struct Parameterized<T, U> {
+ x: T,
+ _y: U,
+ }
+ #[test]
+ fn test_type_parameter() {
+ let _ = offset_of!(Parameterized<Parameterized<bool, bool>, bool> => x: Parameterized<bool, bool> => x);
+ }
+
+ #[test]
+ fn test_const() {
+ use crate::FieldOffset;
+ #[repr(C)]
+ struct SomeStruct {
+ a: u8,
+ b: u32,
+ }
+ const CONST_FIELD_OFFSET: FieldOffset<SomeStruct, u32> =
+ unsafe { FieldOffset::new_from_offset(4) };
+ const CONST_VALUE: usize = CONST_FIELD_OFFSET.get_byte_offset();
+ assert_eq!(offset_of!(SomeStruct => b).get_byte_offset(), CONST_VALUE);
+
+ static STATIC_FIELD_OFFSET: FieldOffset<SomeStruct, u32> =
+ unsafe { FieldOffset::new_from_offset(4) };
+ assert_eq!(
+ offset_of!(SomeStruct => b).get_byte_offset(),
+ STATIC_FIELD_OFFSET.get_byte_offset()
+ );
+ }
+
+ #[cfg(fieldoffset_has_alloc)]
+ #[test]
+ fn test_pin() {
+ use alloc::boxed::Box;
+ use core::pin::Pin;
+
+ // Get a pointer to `b` within `Foo`
+ let foo_b = offset_of!(Foo => b);
+ let foo_b_pin = unsafe { foo_b.as_pinned_projection() };
+ let foo = Box::pin(Foo {
+ a: 21,
+ b: 22.0,
+ c: true,
+ });
+ let pb: Pin<&f64> = foo_b_pin.apply_pin(foo.as_ref());
+ assert_eq!(*pb, 22.0);
+
+ let mut x = Box::pin(Bar {
+ x: 0,
+ y: Foo {
+ a: 1,
+ b: 52.0,
+ c: false,
+ },
+ });
+ let bar_y_b = offset_of!(Bar => y: Foo => b);
+ assert!(*bar_y_b.apply(&*x) == 52.0);
+
+ let bar_y_pin = unsafe { offset_of!(Bar => y).as_pinned_projection() };
+ *(bar_y_pin + foo_b_pin).apply_pin_mut(x.as_mut()) = 12.;
+ assert_eq!(x.y.b, 12.0);
+ }
+}