despero_hecs_schedule/borrow/
maybe_borrow.rs

1use std::{
2    any::type_name,
3    marker::PhantomData,
4    ops::{Deref, DerefMut},
5    ptr::NonNull,
6};
7
8use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
9use smallvec::smallvec;
10
11use crate::{borrow::Borrows, Access, Context, Error, IntoAccess, Result};
12
13use super::{ComponentBorrow, ContextBorrow};
14
15/// Wrapper type for an immutably borrowed value from schedule context which may
16/// not exist.
17#[repr(transparent)]
18#[derive(Debug)]
19pub struct MaybeRead<'a, T>(pub(crate) Option<AtomicRef<'a, T>>);
20
21// unsafe impl<T> Send for MaybeRead<'_, T> {}
22// unsafe impl<T> Sync for MaybeRead<'_, T> {}
23
24impl<'a, T> Clone for MaybeRead<'a, T> {
25    fn clone(&self) -> Self {
26        match &self.0 {
27            Some(val) => Self(Some(AtomicRef::clone(val))),
28            None => Self(None),
29        }
30    }
31}
32
33impl<'a, T> Deref for MaybeRead<'a, T> {
34    type Target = Option<AtomicRef<'a, T>>;
35
36    fn deref(&self) -> &Self::Target {
37        &self.0
38    }
39}
40
41impl<'a, T> MaybeRead<'a, T> {
42    /// Creates a new MaybeRead borrow from an atomic ref
43    pub fn new(borrow: Option<AtomicRef<'a, T>>) -> Self {
44        Self(borrow)
45    }
46
47    /// Returns the containing option suitable for match expressions
48    pub fn option(&self) -> Option<&AtomicRef<'a, T>> {
49        self.0.as_ref()
50    }
51}
52
53impl<'a, T: 'static> MaybeRead<'a, T> {
54    pub(crate) fn try_from_untyped(cell: Result<&'a AtomicRefCell<NonNull<u8>>>) -> Result<Self> {
55        match cell {
56            Ok(cell) => cell
57                .try_borrow()
58                .map_err(|_| Error::Borrow(type_name::<T>()))
59                .map(|cell| {
60                    Self(Some(AtomicRef::map(cell, |val| unsafe {
61                        val.cast().as_ref()
62                    })))
63                }),
64            Err(Error::MissingData(_)) => Ok(Self(None)),
65            Err(e) => Err(e),
66        }
67    }
68}
69
70/// Wrapper type for an exclusively value from schedule context which may not exist.
71#[repr(transparent)]
72#[derive(Debug)]
73pub struct MaybeWrite<'a, T>(pub(crate) Option<AtomicRefMut<'a, T>>);
74
75impl<'a, T> Deref for MaybeWrite<'a, T> {
76    type Target = Option<AtomicRefMut<'a, T>>;
77
78    fn deref(&self) -> &Self::Target {
79        &self.0
80    }
81}
82
83impl<'a, T> DerefMut for MaybeWrite<'a, T> {
84    fn deref_mut(&mut self) -> &mut Self::Target {
85        &mut self.0
86    }
87}
88
89impl<'a, T> MaybeWrite<'a, T> {
90    /// Creates a new MaybeWrite borrow from an atomic ref
91    pub fn new(borrow: Option<AtomicRefMut<'a, T>>) -> Self {
92        Self(borrow)
93    }
94
95    /// Returns the containing option suitable for match expressions
96    pub fn option(&self) -> Option<&AtomicRefMut<'a, T>> {
97        self.0.as_ref()
98    }
99
100    /// Returns the containing option suitable for match expressions
101    pub fn option_mut(&mut self) -> Option<&mut AtomicRefMut<'a, T>> {
102        self.0.as_mut()
103    }
104}
105
106impl<'a, T: 'static> MaybeWrite<'a, T> {
107    pub(crate) fn try_from_untyped(cell: Result<&'a AtomicRefCell<NonNull<u8>>>) -> Result<Self> {
108        match cell {
109            Ok(cell) => cell
110                .try_borrow_mut()
111                .map_err(|_| Error::BorrowMut(type_name::<T>()))
112                .map(|cell| {
113                    Self(Some(AtomicRefMut::map(cell, |val| unsafe {
114                        val.cast().as_mut()
115                    })))
116                }),
117            Err(Error::MissingData(_)) => Ok(Self(None)),
118            Err(e) => Err(e),
119        }
120    }
121}
122
123struct BorrowMarker<T> {
124    marker: PhantomData<T>,
125}
126
127impl<T: IntoAccess> IntoAccess for BorrowMarker<T> {
128    fn access() -> Access {
129        Access::of::<T>()
130    }
131}
132
133impl<'a, T: 'static> ContextBorrow<'a> for MaybeRead<'a, T> {
134    type Target = Self;
135
136    fn borrow(context: &'a Context) -> Result<Self::Target> {
137        MaybeRead::try_from_untyped(context.cell::<&T>())
138    }
139}
140
141impl<'a, T: 'static> ContextBorrow<'a> for MaybeWrite<'a, T> {
142    type Target = Self;
143
144    fn borrow(context: &'a Context) -> Result<Self::Target> {
145        MaybeWrite::try_from_untyped(context.cell::<&mut T>())
146    }
147}
148
149impl<'a, T: 'static> ComponentBorrow for MaybeRead<'a, T> {
150    fn borrows() -> Borrows {
151        smallvec![BorrowMarker::<&T>::access()]
152    }
153
154    fn has<U: crate::IntoAccess>() -> bool {
155        Access::of::<&T>() == U::access()
156    }
157
158    fn has_dynamic(id: std::any::TypeId, exclusive: bool) -> bool {
159        let l = Access::of::<&T>();
160
161        l.id == id && !exclusive
162    }
163}
164
165impl<'a, T: 'static> ComponentBorrow for MaybeWrite<'a, T> {
166    fn borrows() -> Borrows {
167        smallvec![BorrowMarker::<&mut T>::access()]
168    }
169
170    fn has<U: crate::IntoAccess>() -> bool {
171        Access::of::<&T>().id == U::access().id
172    }
173
174    fn has_dynamic(id: std::any::TypeId, _: bool) -> bool {
175        let l = Access::of::<&T>();
176
177        l.id == id
178    }
179}