Skip to main content

design/
pin.rs

1use std::{
2    mem::{
3        self,
4        ManuallyDrop,
5    },
6    pin::Pin,
7};
8
9use crate::{
10    ops::place::{
11        BorrowPlace,
12        CreateHandle,
13        DerefPlace,
14        DropHusk,
15        DropPlace,
16        MovePlace,
17        PlaceHandle,
18        PlaceProxy,
19        ProjectPlace,
20        ReadMetadata,
21        ReadPlace,
22        WritePlace,
23        borrowck::{
24            AccessKind,
25            Timing,
26        },
27    },
28    place::Subplace,
29    ptr::Metadata,
30};
31
32impl<P> PlaceProxy for Pin<P>
33where
34    P: PlaceProxy,
35{
36    type Target = P::Target;
37}
38
39unsafe impl<ProxyTiming, P> CreateHandle<ProxyTiming> for Pin<P>
40where
41    ProxyTiming: Timing,
42    P: CreateHandle<ProxyTiming>,
43{
44    type Handle = PinnedHandle<P::Handle>;
45
46    const ACCESS: AccessKind = P::ACCESS;
47
48    unsafe fn handle_from_raw(this: *const Self) -> Self::Handle {
49        let ptr: *const Pin<P> = this;
50        let ptr: *const P = ptr.cast();
51        let handle = unsafe { P::handle_from_raw(ptr) };
52        PinnedHandle(handle)
53    }
54}
55
56pub struct PinnedHandle<H>(H);
57
58impl<H> PinnedHandle<H> {
59    pub unsafe fn new_unchecked(handle: H) -> Self {
60        Self(handle)
61    }
62}
63
64impl<H> PlaceHandle for PinnedHandle<H>
65where
66    H: PlaceHandle,
67{
68    type Target = H::Target;
69}
70
71unsafe impl<H> ReadPlace for PinnedHandle<H>
72where
73    H: ReadPlace,
74    H::Target: Sized + Unpin,
75{
76    const ACCESS: AccessKind = H::ACCESS;
77    const SAFE: bool = H::SAFE;
78
79    unsafe fn read_place(self) -> Self::Target {
80        unsafe { self.0.read_place() }
81    }
82}
83
84unsafe impl<H> ReadMetadata for PinnedHandle<H>
85where
86    H: ReadMetadata,
87{
88    fn metadata(self) -> Metadata<Self::Target> {
89        self.0.metadata()
90    }
91}
92
93unsafe impl<H> MovePlace for PinnedHandle<H>
94where
95    H: MovePlace,
96    H::Target: Sized + Unpin,
97{
98}
99
100unsafe impl<H> WritePlace for PinnedHandle<H>
101where
102    H: WritePlace,
103    H::Target: Sized,
104{
105    const ACCESS: AccessKind = H::ACCESS;
106    const SAFE: bool = H::SAFE;
107
108    unsafe fn write_place(self, value: Self::Target) {
109        unsafe { self.0.write_place(value) }
110    }
111}
112
113unsafe impl<H> DropPlace for PinnedHandle<H>
114where
115    H: DropPlace,
116{
117    unsafe fn drop_place(self) {
118        unsafe { self.0.drop_place() };
119    }
120}
121
122unsafe impl<P> DropHusk for Pin<P>
123where
124    P: DropHusk,
125{
126    unsafe fn drop_husk(this: *mut Self) {
127        // The entire pointee is dropped, so no pin guarantee is left.
128        unsafe { P::drop_husk(this.cast()) }
129    }
130}
131
132pub unsafe trait PinnableSubplace: Subplace {
133    /// The structural pinnedness of this subplace.
134    ///
135    /// Must be exactly one of these two GATs:
136    /// - `H` (i.e. the identity GAT)
137    /// - `PinnedHandle<H>`
138    type StructualPinning<H: PlaceHandle<Target = Self::Target>>: PlaceHandle<
139        Target = Self::Target,
140    >;
141
142    /// - If `StructualPinning<H> == H`, then this should be the identity
143    ///   function.
144    /// - If `StructualPinning<H> == PinnedHandle<H>`, then this should be
145    ///   `PinnedHandle::new_unchecked`.
146    unsafe fn from_pinned<H: PlaceHandle<Target = Self::Target>>(
147        handle: H,
148    ) -> Self::StructualPinning<H>;
149}
150
151unsafe impl<H, S> ProjectPlace<S> for PinnedHandle<H>
152where
153    H: ProjectPlace<S>,
154    S: PinnableSubplace<Source = H::Target>,
155{
156    type Projected = S::StructualPinning<H::Projected>;
157
158    unsafe fn project_place(self, subplace: S) -> Self::Projected {
159        let handle = unsafe { self.0.project_place(subplace) };
160        unsafe { S::from_pinned(handle) }
161    }
162}
163
164// FIXME: we probably need something specific to pin here to, but haven't given
165// it much thought...
166unsafe impl<H, PointeeTiming, PointerTiming>
167    DerefPlace<PointeeTiming, PointerTiming> for PinnedHandle<H>
168where
169    Self::Target: CreateHandle<PointeeTiming>,
170    H: DerefPlace<PointeeTiming, PointerTiming>,
171    PointeeTiming: Timing,
172    PointerTiming: Timing,
173{
174    const POINTEE_ACCESS: AccessKind = H::POINTEE_ACCESS;
175    const POINTER_ACCESS: AccessKind = H::POINTER_ACCESS;
176    const SAFE: bool = H::SAFE;
177
178    unsafe fn deref_place(
179        self,
180    ) -> <Self::Target as CreateHandle<PointeeTiming>>::Handle {
181        let handle = unsafe { self.0.deref_place() };
182        handle
183    }
184}
185
186unsafe impl<H, Output> BorrowPlace<Pin<Output>> for PinnedHandle<H>
187where
188    H: BorrowPlace<Output>,
189{
190    const ACCESS: AccessKind = H::ACCESS;
191    type Timing = H::Timing;
192    const SAFE: bool = H::SAFE;
193
194    unsafe fn borrow(self) -> Pin<Output> {
195        unsafe { new_pin_unchecked(self.0.borrow()) }
196    }
197}
198
199unsafe fn new_pin_unchecked<T>(t: T) -> Pin<T> {
200    let t = ManuallyDrop::new(t);
201    // somehow can't use `mem::transmute`?
202    unsafe { mem::transmute_copy::<T, Pin<T>>(&t) }
203}