Skip to main content

_01_places/
projection.rs

1use std::{
2    marker::PhantomData,
3    ptr::Pointee,
4};
5
6use crate::*;
7
8// TODO: inspect projections
9pub trait Projection {
10    type Source: ?Sized;
11    type Target: ?Sized;
12
13    fn offset(&self, meta: <Self::Source as Pointee>::Metadata) -> usize;
14    fn project_metadata(
15        &self,
16        meta: <Self::Source as Pointee>::Metadata,
17    ) -> <Self::Target as Pointee>::Metadata;
18}
19
20/// Extension trait so that `Projection` stays dyn-compatible.
21impl<P: Projection + ?Sized> ProjectionExt for P {}
22pub trait ProjectionExt: Projection {
23    /// Convenience method that simply calls the corresponding PlaceBorrow
24    /// method.
25    unsafe fn borrow<'a, X, Y>(&self, ptr: *const X) -> Y
26    where
27        X: HasPlace<Target = Self::Source>,
28        Y: HasPlace<Target = Self::Target>,
29        X: PlaceBorrow<'a, Self, Y>,
30    {
31        unsafe { PlaceBorrow::borrow(ptr, self) }
32    }
33    /// Convenience method that simply calls the corresponding PlaceRead method.
34    unsafe fn read<X>(&self, ptr: *const X) -> Self::Target
35    where
36        X: PlaceRead<Self>,
37        Self::Target: Sized,
38    {
39        unsafe { PlaceRead::read(ptr, self) }
40    }
41    /// Convenience method that simply calls the corresponding PlaceRead method.
42    unsafe fn write<X>(&self, ptr: *mut X, val: Self::Target)
43    where
44        X: PlaceWrite<Self>,
45        Self::Target: Sized,
46    {
47        unsafe { PlaceWrite::write(ptr, self, val) }
48    }
49    /// Convenience method that simply calls the corresponding PlaceDeref
50    /// method.
51    unsafe fn deref<X>(&self, ptr: *mut X) -> *const Self::Target
52    where
53        X: HasPlace<Target = Self::Source>,
54        X: PlaceDeref<Self>,
55        Self::Target: HasPlace,
56    {
57        unsafe { PlaceDeref::double_deref(ptr, self) }
58    }
59
60    /// When the target is sized, we know a projection is just an offset so we
61    /// can make it sized even if we had a `dyn Projection`.
62    ///
63    /// Definitely a bit hacky.
64    fn as_sized(&self) -> SizedProj<Self::Source, Self::Target>
65    where
66        Self::Source: Sized,
67        Self::Target: Sized,
68    {
69        SizedProj(self.offset(()), PhantomData, PhantomData)
70    }
71
72    fn compose<Q>(self, other: Q) -> ComposeProj<Self, Q>
73    where
74        Self: Sized,
75        Q: Projection<Source = Self::Target>,
76    {
77        ComposeProj { p: self, q: other }
78    }
79}
80
81pub struct NoopProj<T: ?Sized>(PhantomData<T>);
82impl<T> Default for NoopProj<T> {
83    fn default() -> Self {
84        Self(Default::default())
85    }
86}
87impl<T> Clone for NoopProj<T> {
88    fn clone(&self) -> Self {
89        Self(self.0.clone())
90    }
91}
92impl<T: ?Sized> Projection for NoopProj<T> {
93    type Source = T;
94    type Target = T;
95    fn offset(&self, _m: <Self::Source as Pointee>::Metadata) -> usize {
96        0
97    }
98    fn project_metadata(
99        &self,
100        m: <Self::Source as Pointee>::Metadata,
101    ) -> <Self::Target as Pointee>::Metadata {
102        m
103    }
104}
105
106/// Sized projection that holds only an offset.
107#[derive(#[automatically_derived]
impl<S: ::core::clone::Clone + ?Sized, T: ::core::clone::Clone>
    ::core::clone::Clone for SizedProj<S, T> {
    #[inline]
    fn clone(&self) -> SizedProj<S, T> {
        SizedProj(::core::clone::Clone::clone(&self.0),
            ::core::clone::Clone::clone(&self.1),
            ::core::clone::Clone::clone(&self.2))
    }
}Clone)]
108pub struct SizedProj<S: ?Sized, T>(usize, PhantomData<S>, PhantomData<T>);
109impl<S, T> Projection for SizedProj<S, T> {
110    type Source = S;
111    type Target = T;
112    fn offset(&self, _m: <Self::Source as Pointee>::Metadata) -> usize {
113        self.0
114    }
115    fn project_metadata(
116        &self,
117        _: <Self::Source as Pointee>::Metadata,
118    ) -> <Self::Target as Pointee>::Metadata {
119    }
120}
121
122/// Projection `P` followed by `Q`. `P` may be unsized.
123#[derive(#[automatically_derived]
impl<P: ::core::clone::Clone + ?Sized, Q: ::core::clone::Clone>
    ::core::clone::Clone for ComposeProj<P, Q> {
    #[inline]
    fn clone(&self) -> ComposeProj<P, Q> {
        ComposeProj {
            q: ::core::clone::Clone::clone(&self.q),
            p: ::core::clone::Clone::clone(&self.p),
        }
    }
}Clone)]
124pub struct ComposeProj<P: ?Sized, Q> {
125    q: Q,
126    p: P,
127}
128impl<P, Q> Projection for ComposeProj<P, Q>
129where
130    P: Projection + ?Sized,
131    Q: Projection<Source = P::Target>,
132{
133    type Source = P::Source;
134    type Target = Q::Target;
135    fn offset(&self, meta: <Self::Source as Pointee>::Metadata) -> usize {
136        let qmeta = self.p.project_metadata(meta);
137        self.p.offset(meta) + self.q.offset(qmeta)
138    }
139    fn project_metadata(
140        &self,
141        meta: <Self::Source as Pointee>::Metadata,
142    ) -> <Self::Target as Pointee>::Metadata {
143        self.q.project_metadata(self.p.project_metadata(meta))
144    }
145}