1use super::{Class, JsClass};
2use crate::{result::BorrowError, Ctx, Error, FromJs, IntoJs, Value};
3use std::{
4 cell::{Cell, UnsafeCell},
5 marker::PhantomData,
6 mem::ManuallyDrop,
7 ops::{Deref, DerefMut},
8};
9
10pub unsafe trait Mutability {
15 #[doc(hidden)]
16 type Cell<T>;
18
19 #[doc(hidden)]
20 fn new_cell<T>(t: T) -> Self::Cell<T>;
22
23 #[doc(hidden)]
24 unsafe fn borrow<'a, T>(cell: &'a Self::Cell<T>) -> Result<(), BorrowError>;
30
31 #[doc(hidden)]
32 unsafe fn unborrow<'a, T>(cell: &'a Self::Cell<T>);
37
38 #[doc(hidden)]
39 unsafe fn borrow_mut<'a, T>(cell: &'a Self::Cell<T>) -> Result<(), BorrowError>;
45
46 #[doc(hidden)]
47 unsafe fn unborrow_mut<'a, T>(cell: &'a Self::Cell<T>);
52
53 #[doc(hidden)]
54 unsafe fn deref<'a, T>(cell: &'a Self::Cell<T>) -> &'a T;
59
60 #[doc(hidden)]
61 #[allow(clippy::mut_from_ref)]
62 unsafe fn deref_mut<'a, T>(cell: &'a Self::Cell<T>) -> &'a mut T;
67}
68
69pub 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
101pub enum Writable {}
104
105pub struct WritableCell<T> {
106 count: Cell<usize>,
107 value: UnsafeCell<T>,
108}
109
110#[doc(hidden)]
111pub struct WriteBorrow<'a, T> {
112 cell: &'a WritableCell<T>,
113 _marker: PhantomData<&'a T>,
114}
115
116impl<'a, T> Deref for WriteBorrow<'a, T> {
117 type Target = T;
118
119 fn deref(&self) -> &Self::Target {
120 unsafe { &(*self.cell.value.get()) }
121 }
122}
123
124impl<'a, T> Drop for WriteBorrow<'a, T> {
125 fn drop(&mut self) {
126 self.cell.count.set(self.cell.count.get() - 1);
127 }
128}
129
130#[doc(hidden)]
131pub struct WriteBorrowMut<'a, T> {
132 cell: &'a WritableCell<T>,
133 _marker: PhantomData<&'a T>,
134}
135
136impl<'a, T> Deref for WriteBorrowMut<'a, T> {
137 type Target = T;
138
139 fn deref(&self) -> &Self::Target {
140 unsafe { &(*self.cell.value.get()) }
141 }
142}
143
144impl<'a, T> DerefMut for WriteBorrowMut<'a, T> {
145 fn deref_mut(&mut self) -> &mut Self::Target {
146 unsafe { &mut (*self.cell.value.get()) }
147 }
148}
149
150impl<'a, T> Drop for WriteBorrowMut<'a, T> {
151 fn drop(&mut self) {
152 self.cell.count.set(0);
153 }
154}
155
156unsafe impl Mutability for Writable {
157 type Cell<T> = WritableCell<T>;
158
159 fn new_cell<T>(t: T) -> Self::Cell<T> {
160 WritableCell {
161 count: Cell::new(0),
162 value: UnsafeCell::new(t),
163 }
164 }
165
166 unsafe fn borrow<'a, T>(cell: &'a Self::Cell<T>) -> Result<(), BorrowError> {
167 let count = cell.count.get();
168 if count == usize::MAX {
169 return Err(BorrowError::AlreadyBorrowed);
170 }
171 cell.count.set(count + 1);
172 Ok(())
173 }
174
175 unsafe fn unborrow<'a, T>(cell: &'a Self::Cell<T>) {
176 cell.count.set(cell.count.get() - 1);
177 }
178
179 unsafe fn borrow_mut<'a, T>(cell: &'a Self::Cell<T>) -> Result<(), BorrowError> {
180 let count = cell.count.get();
181 if count != 0 {
182 return Err(BorrowError::AlreadyBorrowed);
183 }
184 cell.count.set(usize::MAX);
185 Ok(())
186 }
187
188 unsafe fn unborrow_mut<'a, T>(cell: &'a Self::Cell<T>) {
189 cell.count.set(0);
190 }
191
192 unsafe fn deref<'a, T>(cell: &'a Self::Cell<T>) -> &'a T {
193 &*cell.value.get()
194 }
195
196 unsafe fn deref_mut<'a, T>(cell: &'a Self::Cell<T>) -> &'a mut T {
197 &mut *cell.value.get()
198 }
199}
200
201pub struct JsCell<'js, T: JsClass<'js>> {
205 pub(crate) cell: <T::Mutable as Mutability>::Cell<T>,
206}
207
208impl<'js, T: JsClass<'js>> JsCell<'js, T> {
209 pub fn new(t: T) -> Self {
211 JsCell {
212 cell: <T::Mutable as Mutability>::new_cell(t),
213 }
214 }
215
216 pub fn borrow<'a>(&'a self) -> Borrow<'a, 'js, T> {
221 unsafe {
222 <T::Mutable as Mutability>::borrow(&self.cell).unwrap();
223 Borrow(&self.cell)
224 }
225 }
226
227 pub fn try_borrow<'a>(&'a self) -> Result<Borrow<'a, 'js, T>, BorrowError> {
229 unsafe {
230 <T::Mutable as Mutability>::borrow(&self.cell)?;
231 Ok(Borrow(&self.cell))
232 }
233 }
234
235 pub fn borrow_mut<'a>(&'a self) -> BorrowMut<'a, 'js, T> {
240 unsafe {
241 <T::Mutable as Mutability>::borrow_mut(&self.cell).unwrap();
242 BorrowMut(&self.cell)
243 }
244 }
245
246 pub fn try_borrow_mut<'a>(&'a self) -> Result<BorrowMut<'a, 'js, T>, BorrowError> {
248 unsafe {
249 <T::Mutable as Mutability>::borrow_mut(&self.cell)?;
250 Ok(BorrowMut(&self.cell))
251 }
252 }
253}
254
255pub struct Borrow<'a, 'js, T: JsClass<'js> + 'a>(&'a <T::Mutable as Mutability>::Cell<T>);
257
258impl<'a, 'js, T: JsClass<'js> + 'a> Drop for Borrow<'a, 'js, T> {
259 fn drop(&mut self) {
260 unsafe { <T::Mutable as Mutability>::unborrow(self.0) }
261 }
262}
263
264impl<'a, 'js, T: JsClass<'js>> Deref for Borrow<'a, 'js, T> {
265 type Target = T;
266
267 fn deref(&self) -> &Self::Target {
268 unsafe { <T::Mutable as Mutability>::deref(self.0) }
269 }
270}
271
272pub struct BorrowMut<'a, 'js, T: JsClass<'js> + 'a>(&'a <T::Mutable as Mutability>::Cell<T>);
274
275impl<'a, 'js, T: JsClass<'js> + 'a> Drop for BorrowMut<'a, 'js, T> {
276 fn drop(&mut self) {
277 unsafe { <T::Mutable as Mutability>::unborrow_mut(self.0) }
278 }
279}
280
281impl<'a, 'js, T: JsClass<'js>> Deref for BorrowMut<'a, 'js, T> {
282 type Target = T;
283
284 fn deref(&self) -> &Self::Target {
285 unsafe { <T::Mutable as Mutability>::deref(self.0) }
286 }
287}
288
289impl<'a, 'js, T: JsClass<'js>> DerefMut for BorrowMut<'a, 'js, T> {
290 fn deref_mut(&mut self) -> &mut Self::Target {
291 unsafe { <T::Mutable as Mutability>::deref_mut(self.0) }
292 }
293}
294
295pub struct OwnedBorrow<'js, T: JsClass<'js> + 'js>(ManuallyDrop<Class<'js, T>>);
297
298impl<'js, T: JsClass<'js> + 'js> OwnedBorrow<'js, T> {
299 pub fn from_class(class: Class<'js, T>) -> Self {
304 Self::try_from_class(class).unwrap()
305 }
306
307 pub fn try_from_class(class: Class<'js, T>) -> Result<Self, BorrowError> {
309 unsafe {
310 <T::Mutable as Mutability>::borrow(&class.get_cell().cell)?;
311 }
312 Ok(OwnedBorrow(ManuallyDrop::new(class)))
313 }
314
315 pub fn into_inner(mut self) -> Class<'js, T> {
317 unsafe { <T::Mutable as Mutability>::unborrow(&self.0.get_cell().cell) };
318 let res = unsafe { ManuallyDrop::take(&mut self.0) };
319 std::mem::forget(self);
320 res
321 }
322}
323
324impl<'js, T: JsClass<'js> + 'js> Drop for OwnedBorrow<'js, T> {
325 fn drop(&mut self) {
326 unsafe {
327 <T::Mutable as Mutability>::unborrow(&self.0.get_cell().cell);
328 ManuallyDrop::drop(&mut self.0)
329 }
330 }
331}
332
333impl<'js, T: JsClass<'js> + 'js> Deref for OwnedBorrow<'js, T> {
334 type Target = T;
335 fn deref(&self) -> &Self::Target {
336 unsafe { <T::Mutable as Mutability>::deref(&self.0.get_cell().cell) }
337 }
338}
339
340impl<'js, T: JsClass<'js>> FromJs<'js> for OwnedBorrow<'js, T> {
341 fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self, Error> {
342 let cls = Class::from_js(ctx, value)?;
343 OwnedBorrow::try_from_class(cls).map_err(Error::ClassBorrow)
344 }
345}
346
347impl<'js, T: JsClass<'js>> IntoJs<'js> for OwnedBorrow<'js, T> {
348 fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>, Error> {
349 self.into_inner().into_js(ctx)
350 }
351}
352
353pub struct OwnedBorrowMut<'js, T: JsClass<'js> + 'js>(ManuallyDrop<Class<'js, T>>);
355
356impl<'js, T: JsClass<'js> + 'js> OwnedBorrowMut<'js, T> {
357 pub fn from_class(class: Class<'js, T>) -> Self {
362 Self::try_from_class(class).unwrap()
363 }
364
365 pub fn try_from_class(class: Class<'js, T>) -> Result<Self, BorrowError> {
367 unsafe {
368 <T::Mutable as Mutability>::borrow_mut(&class.get_cell().cell)?;
369 }
370 Ok(OwnedBorrowMut(ManuallyDrop::new(class)))
371 }
372
373 pub fn into_inner(mut self) -> Class<'js, T> {
375 unsafe { <T::Mutable as Mutability>::unborrow_mut(&self.0.get_cell().cell) };
376 let res = unsafe { ManuallyDrop::take(&mut self.0) };
377 std::mem::forget(self);
378 res
379 }
380}
381
382impl<'js, T: JsClass<'js> + 'js> Drop for OwnedBorrowMut<'js, T> {
383 fn drop(&mut self) {
384 unsafe {
385 <T::Mutable as Mutability>::unborrow_mut(&self.0.get_cell().cell);
386 ManuallyDrop::drop(&mut self.0)
387 }
388 }
389}
390
391impl<'js, T: JsClass<'js> + 'js> Deref for OwnedBorrowMut<'js, T> {
392 type Target = T;
393 fn deref(&self) -> &Self::Target {
394 unsafe { <T::Mutable as Mutability>::deref(&self.0.get_cell().cell) }
395 }
396}
397
398impl<'js, T: JsClass<'js> + 'js> DerefMut for OwnedBorrowMut<'js, T> {
399 fn deref_mut(&mut self) -> &mut Self::Target {
400 unsafe { <T::Mutable as Mutability>::deref_mut(&self.0.get_cell().cell) }
401 }
402}
403
404impl<'js, T: JsClass<'js>> FromJs<'js> for OwnedBorrowMut<'js, T> {
405 fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self, Error> {
406 let cls = Class::from_js(ctx, value)?;
407 OwnedBorrowMut::try_from_class(cls).map_err(Error::ClassBorrow)
408 }
409}
410
411impl<'js, T: JsClass<'js>> IntoJs<'js> for OwnedBorrowMut<'js, T> {
412 fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>, Error> {
413 self.into_inner().into_js(ctx)
414 }
415}