rquickjs_core/class/
cell.rs

1use super::{Class, JsClass};
2use crate::{result::BorrowError, Ctx, Error, FromJs, IntoJs, Value};
3use core::{
4    cell::{Cell, UnsafeCell},
5    marker::PhantomData,
6    mem::ManuallyDrop,
7    ops::{Deref, DerefMut},
8};
9
10/// A trait to allow classes to choose there borrowing implementation.
11///
12/// # Safety
13/// This trait is not meant to be implemented outside the rquickjs library.
14pub unsafe trait Mutability {
15    #[doc(hidden)]
16    /// The internal type of cell used for this mutability.
17    type Cell<T>;
18
19    #[doc(hidden)]
20    /// Create a new cell.
21    fn new_cell<T>(t: T) -> Self::Cell<T>;
22
23    #[doc(hidden)]
24    /// Will be called before deref
25    ///
26    /// # Safety
27    /// Implementation must ensure that the cell can be immutably borrowed until unborrow is called if
28    /// this function returns without an error.
29    unsafe fn borrow<'a, T>(cell: &'a Self::Cell<T>) -> Result<(), BorrowError>;
30
31    #[doc(hidden)]
32    /// Will be called after the reference returned by deref is no longer in use.
33    ///
34    /// # Safety
35    /// Caller must ensure that the reference returned by deref no longer exists.
36    unsafe fn unborrow<'a, T>(cell: &'a Self::Cell<T>);
37
38    #[doc(hidden)]
39    /// Will be called before deref_mut
40    ///
41    /// # Safety
42    /// Implementation must ensure that the cell can be mutably borrowed until unborrow_mut is called if
43    /// this function returns without an error.
44    unsafe fn borrow_mut<'a, T>(cell: &'a Self::Cell<T>) -> Result<(), BorrowError>;
45
46    #[doc(hidden)]
47    /// Will be called after the reference returned by deref_mut is no longer reachable.
48    ///
49    /// # Safety
50    /// Caller must ensure that the reference returned by deref_mut no longer exists.
51    unsafe fn unborrow_mut<'a, T>(cell: &'a Self::Cell<T>);
52
53    #[doc(hidden)]
54    /// Returns a reference to the cell.
55    ///
56    /// # Safety
57    /// [`borrow`] must first be called on the cell and return without error before calling deref.
58    unsafe fn deref<'a, T>(cell: &'a Self::Cell<T>) -> &'a T;
59
60    #[doc(hidden)]
61    #[allow(clippy::mut_from_ref)]
62    /// Returns a reference to the cell.
63    ///
64    /// # Safety
65    /// [`borrow_mut`] must first be called on the cell and return without error before calling deref.
66    unsafe fn deref_mut<'a, T>(cell: &'a Self::Cell<T>) -> &'a mut T;
67}
68
69/// A marker type used for marking the mutability of a class.
70/// When a class has `Readable` as it Mutable type you can only borrow it immutable.
71pub enum Readable {}
72
73unsafe impl Mutability for Readable {
74    type Cell<T> = T;
75
76    fn new_cell<T>(t: T) -> Self::Cell<T> {
77        t
78    }
79
80    unsafe fn borrow<'a, T>(_cell: &'a Self::Cell<T>) -> Result<(), BorrowError> {
81        Ok(())
82    }
83
84    unsafe fn unborrow<'a, T>(_cell: &'a Self::Cell<T>) {}
85
86    unsafe fn borrow_mut<'a, T>(_cell: &'a Self::Cell<T>) -> Result<(), BorrowError> {
87        Err(BorrowError::NotWritable)
88    }
89
90    unsafe fn unborrow_mut<'a, T>(_cell: &'a Self::Cell<T>) {}
91
92    unsafe fn deref<'a, T>(cell: &'a Self::Cell<T>) -> &'a T {
93        cell
94    }
95
96    unsafe fn deref_mut<'a, T>(_cell: &'a Self::Cell<T>) -> &'a mut T {
97        unreachable!()
98    }
99}
100
101/// A marker type used for marking the mutability of a class.
102/// When a class has `Writable` as it Mutable type you can borrow it both mutability and immutable.
103pub enum Writable {}
104
105pub struct WritableCell<T> {
106    count: Cell<usize>,
107    value: UnsafeCell<T>,
108}
109
110#[doc(hidden)]
111#[allow(dead_code)]
112pub struct WriteBorrow<'a, T> {
113    cell: &'a WritableCell<T>,
114    _marker: PhantomData<&'a T>,
115}
116
117impl<'a, T> Deref for WriteBorrow<'a, T> {
118    type Target = T;
119
120    fn deref(&self) -> &Self::Target {
121        unsafe { &(*self.cell.value.get()) }
122    }
123}
124
125impl<'a, T> Drop for WriteBorrow<'a, T> {
126    fn drop(&mut self) {
127        self.cell.count.set(self.cell.count.get() - 1);
128    }
129}
130
131#[doc(hidden)]
132#[allow(dead_code)]
133pub struct WriteBorrowMut<'a, T> {
134    cell: &'a WritableCell<T>,
135    _marker: PhantomData<&'a T>,
136}
137
138impl<'a, T> Deref for WriteBorrowMut<'a, T> {
139    type Target = T;
140
141    fn deref(&self) -> &Self::Target {
142        unsafe { &(*self.cell.value.get()) }
143    }
144}
145
146impl<'a, T> DerefMut for WriteBorrowMut<'a, T> {
147    fn deref_mut(&mut self) -> &mut Self::Target {
148        unsafe { &mut (*self.cell.value.get()) }
149    }
150}
151
152impl<'a, T> Drop for WriteBorrowMut<'a, T> {
153    fn drop(&mut self) {
154        self.cell.count.set(0);
155    }
156}
157
158unsafe impl Mutability for Writable {
159    type Cell<T> = WritableCell<T>;
160
161    fn new_cell<T>(t: T) -> Self::Cell<T> {
162        WritableCell {
163            count: Cell::new(0),
164            value: UnsafeCell::new(t),
165        }
166    }
167
168    unsafe fn borrow<'a, T>(cell: &'a Self::Cell<T>) -> Result<(), BorrowError> {
169        let count = cell.count.get();
170        if count == usize::MAX {
171            return Err(BorrowError::AlreadyBorrowed);
172        }
173        cell.count.set(count + 1);
174        Ok(())
175    }
176
177    unsafe fn unborrow<'a, T>(cell: &'a Self::Cell<T>) {
178        cell.count.set(cell.count.get() - 1);
179    }
180
181    unsafe fn borrow_mut<'a, T>(cell: &'a Self::Cell<T>) -> Result<(), BorrowError> {
182        let count = cell.count.get();
183        if count != 0 {
184            return Err(BorrowError::AlreadyBorrowed);
185        }
186        cell.count.set(usize::MAX);
187        Ok(())
188    }
189
190    unsafe fn unborrow_mut<'a, T>(cell: &'a Self::Cell<T>) {
191        cell.count.set(0);
192    }
193
194    unsafe fn deref<'a, T>(cell: &'a Self::Cell<T>) -> &'a T {
195        &*cell.value.get()
196    }
197
198    unsafe fn deref_mut<'a, T>(cell: &'a Self::Cell<T>) -> &'a mut T {
199        &mut *cell.value.get()
200    }
201}
202
203/// A cell type for Rust classes passed to JavaScript.
204///
205/// Implements [`RefCell`](std::cell::RefCell)-like borrow checking.
206pub struct JsCell<'js, T: JsClass<'js>> {
207    pub(crate) cell: <T::Mutable as Mutability>::Cell<T>,
208}
209
210impl<'js, T: JsClass<'js>> JsCell<'js, T> {
211    /// Create a new `JsCell`
212    pub fn new(t: T) -> Self {
213        JsCell {
214            cell: <T::Mutable as Mutability>::new_cell(t),
215        }
216    }
217
218    /// Borrow the contained value immutable.
219    ///
220    /// # Panic
221    /// Panics if the value is already borrowed mutably
222    pub fn borrow<'a>(&'a self) -> Borrow<'a, 'js, T> {
223        unsafe {
224            <T::Mutable as Mutability>::borrow(&self.cell).unwrap();
225            Borrow(&self.cell)
226        }
227    }
228
229    /// Try to borrow the contained value immutable.
230    pub fn try_borrow<'a>(&'a self) -> Result<Borrow<'a, 'js, T>, BorrowError> {
231        unsafe {
232            <T::Mutable as Mutability>::borrow(&self.cell)?;
233            Ok(Borrow(&self.cell))
234        }
235    }
236
237    /// Borrow the contained value mutably.
238    ///
239    /// # Panic
240    /// Panics if the value is already borrowed mutably or the class can't be borrowed mutably.
241    pub fn borrow_mut<'a>(&'a self) -> BorrowMut<'a, 'js, T> {
242        unsafe {
243            <T::Mutable as Mutability>::borrow_mut(&self.cell).unwrap();
244            BorrowMut(&self.cell)
245        }
246    }
247
248    /// Try to borrow the contained value mutably.
249    pub fn try_borrow_mut<'a>(&'a self) -> Result<BorrowMut<'a, 'js, T>, BorrowError> {
250        unsafe {
251            <T::Mutable as Mutability>::borrow_mut(&self.cell)?;
252            Ok(BorrowMut(&self.cell))
253        }
254    }
255}
256
257/// A borrow guard for a borrowed class.
258pub struct Borrow<'a, 'js, T: JsClass<'js> + 'a>(&'a <T::Mutable as Mutability>::Cell<T>);
259
260impl<'a, 'js, T: JsClass<'js> + 'a> Drop for Borrow<'a, 'js, T> {
261    fn drop(&mut self) {
262        unsafe { <T::Mutable as Mutability>::unborrow(self.0) }
263    }
264}
265
266impl<'a, 'js, T: JsClass<'js>> Deref for Borrow<'a, 'js, T> {
267    type Target = T;
268
269    fn deref(&self) -> &Self::Target {
270        unsafe { <T::Mutable as Mutability>::deref(self.0) }
271    }
272}
273
274/// A borrow guard for a mutably borrowed class.
275pub struct BorrowMut<'a, 'js, T: JsClass<'js> + 'a>(&'a <T::Mutable as Mutability>::Cell<T>);
276
277impl<'a, 'js, T: JsClass<'js> + 'a> Drop for BorrowMut<'a, 'js, T> {
278    fn drop(&mut self) {
279        unsafe { <T::Mutable as Mutability>::unborrow_mut(self.0) }
280    }
281}
282
283impl<'a, 'js, T: JsClass<'js>> Deref for BorrowMut<'a, 'js, T> {
284    type Target = T;
285
286    fn deref(&self) -> &Self::Target {
287        unsafe { <T::Mutable as Mutability>::deref(self.0) }
288    }
289}
290
291impl<'a, 'js, T: JsClass<'js>> DerefMut for BorrowMut<'a, 'js, T> {
292    fn deref_mut(&mut self) -> &mut Self::Target {
293        unsafe { <T::Mutable as Mutability>::deref_mut(self.0) }
294    }
295}
296
297/// An owned borrow of a class object which keeps the borrow alive for the duration of the objects lifetime.
298pub struct OwnedBorrow<'js, T: JsClass<'js> + 'js>(ManuallyDrop<Class<'js, T>>);
299
300impl<'js, T: JsClass<'js> + 'js> OwnedBorrow<'js, T> {
301    /// Borrow a class owned.
302    ///
303    /// # Panic
304    /// Panics if the class cannot be borrowed
305    pub fn from_class(class: Class<'js, T>) -> Self {
306        Self::try_from_class(class).unwrap()
307    }
308
309    /// Try to borrow a class owned.
310    pub fn try_from_class(class: Class<'js, T>) -> Result<Self, BorrowError> {
311        unsafe {
312            <T::Mutable as Mutability>::borrow(&class.get_cell().cell)?;
313        }
314        Ok(OwnedBorrow(ManuallyDrop::new(class)))
315    }
316
317    /// Turn the owned borrow back into the class releasing the borrow.
318    pub fn into_inner(mut self) -> Class<'js, T> {
319        unsafe { <T::Mutable as Mutability>::unborrow(&self.0.get_cell().cell) };
320        let res = unsafe { ManuallyDrop::take(&mut self.0) };
321        core::mem::forget(self);
322        res
323    }
324}
325
326impl<'js, T: JsClass<'js> + 'js> Drop for OwnedBorrow<'js, T> {
327    fn drop(&mut self) {
328        unsafe {
329            <T::Mutable as Mutability>::unborrow(&self.0.get_cell().cell);
330            ManuallyDrop::drop(&mut self.0)
331        }
332    }
333}
334
335impl<'js, T: JsClass<'js> + 'js> Deref for OwnedBorrow<'js, T> {
336    type Target = T;
337    fn deref(&self) -> &Self::Target {
338        unsafe { <T::Mutable as Mutability>::deref(&self.0.get_cell().cell) }
339    }
340}
341
342impl<'js, T: JsClass<'js>> FromJs<'js> for OwnedBorrow<'js, T> {
343    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self, Error> {
344        let cls = Class::from_js(ctx, value)?;
345        OwnedBorrow::try_from_class(cls).map_err(Error::ClassBorrow)
346    }
347}
348
349impl<'js, T: JsClass<'js>> IntoJs<'js> for OwnedBorrow<'js, T> {
350    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>, Error> {
351        self.into_inner().into_js(ctx)
352    }
353}
354
355/// An owned mutable borrow of a class object which keeps the borrow alive for the duration of the objects lifetime.
356pub struct OwnedBorrowMut<'js, T: JsClass<'js> + 'js>(ManuallyDrop<Class<'js, T>>);
357
358impl<'js, T: JsClass<'js> + 'js> OwnedBorrowMut<'js, T> {
359    /// Borrow a class mutably owned.
360    ///
361    /// # Panic
362    /// Panics if the class cannot be borrowed
363    pub fn from_class(class: Class<'js, T>) -> Self {
364        Self::try_from_class(class).unwrap()
365    }
366
367    /// Try to borrow a class mutably owned.
368    pub fn try_from_class(class: Class<'js, T>) -> Result<Self, BorrowError> {
369        unsafe {
370            <T::Mutable as Mutability>::borrow_mut(&class.get_cell().cell)?;
371        }
372        Ok(OwnedBorrowMut(ManuallyDrop::new(class)))
373    }
374
375    /// Turn the owned borrow back into the class releasing the borrow.
376    pub fn into_inner(mut self) -> Class<'js, T> {
377        unsafe { <T::Mutable as Mutability>::unborrow_mut(&self.0.get_cell().cell) };
378        let res = unsafe { ManuallyDrop::take(&mut self.0) };
379        core::mem::forget(self);
380        res
381    }
382}
383
384impl<'js, T: JsClass<'js> + 'js> Drop for OwnedBorrowMut<'js, T> {
385    fn drop(&mut self) {
386        unsafe {
387            <T::Mutable as Mutability>::unborrow_mut(&self.0.get_cell().cell);
388            ManuallyDrop::drop(&mut self.0)
389        }
390    }
391}
392
393impl<'js, T: JsClass<'js> + 'js> Deref for OwnedBorrowMut<'js, T> {
394    type Target = T;
395    fn deref(&self) -> &Self::Target {
396        unsafe { <T::Mutable as Mutability>::deref(&self.0.get_cell().cell) }
397    }
398}
399
400impl<'js, T: JsClass<'js> + 'js> DerefMut for OwnedBorrowMut<'js, T> {
401    fn deref_mut(&mut self) -> &mut Self::Target {
402        unsafe { <T::Mutable as Mutability>::deref_mut(&self.0.get_cell().cell) }
403    }
404}
405
406impl<'js, T: JsClass<'js>> FromJs<'js> for OwnedBorrowMut<'js, T> {
407    fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self, Error> {
408        let cls = Class::from_js(ctx, value)?;
409        OwnedBorrowMut::try_from_class(cls).map_err(Error::ClassBorrow)
410    }
411}
412
413impl<'js, T: JsClass<'js>> IntoJs<'js> for OwnedBorrowMut<'js, T> {
414    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>, Error> {
415        self.into_inner().into_js(ctx)
416    }
417}