mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 22:31:14 +00:00
Add a Pinned flag to FieldOffset
So we can have Pinned projection
This commit is contained in:
parent
a19c9619fa
commit
23e9397578
1 changed files with 118 additions and 16 deletions
|
@ -5,22 +5,33 @@ The changes include:
|
||||||
- Only the FieldOffset structure was imported, not the macros
|
- Only the FieldOffset structure was imported, not the macros
|
||||||
- re-export of the FieldOffsets derive macro
|
- re-export of the FieldOffsets derive macro
|
||||||
- add const in most method
|
- add const in most method
|
||||||
|
- Add a PinFlag flag
|
||||||
|
|
||||||
(there is a `//###` comment in front of each change)
|
(there is a `//###` comment in front of some change)
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::fmt;
|
//### added no_std (because we can)
|
||||||
use std::marker::PhantomData;
|
#![no_std]
|
||||||
use std::mem;
|
|
||||||
use std::ops::Add;
|
#[cfg(test)]
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use core::fmt;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use core::mem;
|
||||||
|
use core::ops::Add;
|
||||||
|
use core::pin::Pin;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use const_field_offset_macro::FieldOffsets;
|
pub use const_field_offset_macro::FieldOffsets;
|
||||||
|
|
||||||
/// Represents a pointer to a field of type `U` within the type `T`
|
/// Represents a pointer to a field of type `U` within the type `T`
|
||||||
|
///
|
||||||
|
/// The `Flag` parameter can be set to `AllowPin` to enable the projection
|
||||||
|
/// from Pin<&T> to Pin<&U>
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct FieldOffset<T, U>(
|
pub struct FieldOffset<T, U, PinFlag = NotPinnedFlag>(
|
||||||
/// Offset in bytes of the field within the struct
|
/// Offset in bytes of the field within the struct
|
||||||
usize,
|
usize,
|
||||||
/// ### Changed from Fn in order to allow const.
|
/// ### Changed from Fn in order to allow const.
|
||||||
|
@ -51,16 +62,23 @@ pub struct FieldOffset<T, U>(
|
||||||
/// of.apply(foo)
|
/// of.apply(foo)
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
PhantomData<(PhantomContra<T>, *const U)>,
|
PhantomData<(PhantomContra<T>, *const U, PinFlag)>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Type that can be used in the `Flag` parameter of `FieldOffset` to specify that
|
||||||
|
/// This projection is valid on Pin types.
|
||||||
|
/// See documentation of `FieldOffset::new_from_offset_pinned`
|
||||||
|
pub enum PinnedFlag {}
|
||||||
|
|
||||||
|
/// Type that can be used in the `Flag` parameter of `FieldOffset` to specify that
|
||||||
|
/// This projection is valid on Pin types.
|
||||||
|
type NotPinnedFlag = ();
|
||||||
|
|
||||||
/// `fn` cannot appear dirrectly in a type that need to be const.
|
/// `fn` cannot appear dirrectly in a type that need to be const.
|
||||||
/// Workaround that with an indiretion
|
/// Workaround that with an indiretion
|
||||||
struct PhantomContra<T>(fn(T));
|
struct PhantomContra<T>(fn(T));
|
||||||
|
|
||||||
unsafe impl<T, U> Send for FieldOffset<T, U> {}
|
impl<T, U> FieldOffset<T, U, NotPinnedFlag> {
|
||||||
|
|
||||||
impl<T, U> FieldOffset<T, U> {
|
|
||||||
// Use MaybeUninit to get a fake T
|
// Use MaybeUninit to get a fake T
|
||||||
#[cfg(fieldoffset_maybe_uninit)]
|
#[cfg(fieldoffset_maybe_uninit)]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -118,9 +136,10 @@ impl<T, U> FieldOffset<T, U> {
|
||||||
|
|
||||||
FieldOffset(offset, PhantomData)
|
FieldOffset(offset, PhantomData)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Methods for applying the pointer to member
|
// Methods for applying the pointer to member
|
||||||
|
impl<T, U, Flag> FieldOffset<T, U, Flag> {
|
||||||
/// Apply the field offset to a native pointer.
|
/// Apply the field offset to a native pointer.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn apply_ptr(self, x: *const T) -> *const U {
|
pub fn apply_ptr(self, x: *const T) -> *const U {
|
||||||
|
@ -213,6 +232,50 @@ impl<T, U> FieldOffset<T, U> {
|
||||||
pub unsafe fn unapply_mut<'a>(self, x: &'a mut U) -> &'a mut T {
|
pub unsafe fn unapply_mut<'a>(self, x: &'a mut U) -> &'a mut T {
|
||||||
&mut *self.unapply_ptr_mut(x)
|
&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, PinnedFlag> {
|
||||||
|
FieldOffset::new_from_offset_pinned(self.get_byte_offset())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> FieldOffset<T, U, PinnedFlag> {
|
||||||
|
/// 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 reference.
|
||||||
|
#[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 mutable reference.
|
||||||
|
#[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, PinnedFlag>> for FieldOffset<T, U> {
|
||||||
|
fn from(other: FieldOffset<T, U, PinnedFlag>) -> Self {
|
||||||
|
unsafe { Self::new_from_offset(other.get_byte_offset()) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allow chaining pointer-to-members.
|
/// Allow chaining pointer-to-members.
|
||||||
|
@ -223,22 +286,42 @@ impl<T, U> FieldOffset<T, U> {
|
||||||
/// The requirements on the generic type parameters ensure this is a safe operation.
|
/// 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> {
|
impl<T, U, V> Add<FieldOffset<U, V>> for FieldOffset<T, U> {
|
||||||
type Output = FieldOffset<T, V>;
|
type Output = FieldOffset<T, V>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add(self, other: FieldOffset<U, V>) -> FieldOffset<T, V> {
|
fn add(self, other: FieldOffset<U, V>) -> FieldOffset<T, V> {
|
||||||
FieldOffset(self.0 + other.0, PhantomData)
|
FieldOffset(self.0 + other.0, PhantomData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<T, U, V> Add<FieldOffset<U, V, PinnedFlag>> for FieldOffset<T, U, PinnedFlag> {
|
||||||
|
type Output = FieldOffset<T, V, PinnedFlag>;
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: FieldOffset<U, V, PinnedFlag>) -> FieldOffset<T, V, PinnedFlag> {
|
||||||
|
FieldOffset(self.0 + other.0, PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T, U, V> Add<FieldOffset<U, V>> for FieldOffset<T, U, PinnedFlag> {
|
||||||
|
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, PinnedFlag>> for FieldOffset<T, U> {
|
||||||
|
type Output = FieldOffset<T, V>;
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: FieldOffset<U, V, PinnedFlag>) -> FieldOffset<T, V> {
|
||||||
|
FieldOffset(self.0 + other.0, PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The debug implementation prints the byte offset of the field in hexadecimal.
|
/// The debug implementation prints the byte offset of the field in hexadecimal.
|
||||||
impl<T, U> fmt::Debug for FieldOffset<T, U> {
|
impl<T, U, Flag> fmt::Debug for FieldOffset<T, U, Flag> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
write!(f, "FieldOffset({:#x})", self.0)
|
write!(f, "FieldOffset({:#x})", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> Copy for FieldOffset<T, U> {}
|
impl<T, U, Flag> Copy for FieldOffset<T, U, Flag> {}
|
||||||
impl<T, U> Clone for FieldOffset<T, U> {
|
impl<T, U, Flag> Clone for FieldOffset<T, U, Flag> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
|
@ -303,4 +386,23 @@ mod tests {
|
||||||
}
|
}
|
||||||
assert!(x.y.b == 42.0);
|
assert!(x.y.b == 42.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_pin() {
|
||||||
|
use ::alloc::boxed::Box;
|
||||||
|
// Get a pointer to `b` within `Foo`
|
||||||
|
let foo_b = Foo::field_offsets().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!(*pb == 22.0);
|
||||||
|
|
||||||
|
let mut x = Box::pin(Bar { x: 0, y: Foo { a: 1, b: 52.0, c: false } });
|
||||||
|
let bar_y_b = Bar::field_offsets().y + foo_b_pin;
|
||||||
|
assert!(*bar_y_b.apply(&*x) == 52.0);
|
||||||
|
|
||||||
|
let bar_y_pin = unsafe { Bar::field_offsets().y.as_pinned_projection() };
|
||||||
|
*(bar_y_pin + foo_b_pin).apply_pin_mut(x.as_mut()) = 12.;
|
||||||
|
assert!(x.y.b == 12.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue