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
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)]
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
203pub 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 pub fn new(t: T) -> Self {
213 JsCell {
214 cell: <T::Mutable as Mutability>::new_cell(t),
215 }
216 }
217
218 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 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 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 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
257pub 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
274pub 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
297pub struct OwnedBorrow<'js, T: JsClass<'js> + 'js>(ManuallyDrop<Class<'js, T>>);
299
300impl<'js, T: JsClass<'js> + 'js> OwnedBorrow<'js, T> {
301 pub fn from_class(class: Class<'js, T>) -> Self {
306 Self::try_from_class(class).unwrap()
307 }
308
309 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 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
355pub struct OwnedBorrowMut<'js, T: JsClass<'js> + 'js>(ManuallyDrop<Class<'js, T>>);
357
358impl<'js, T: JsClass<'js> + 'js> OwnedBorrowMut<'js, T> {
359 pub fn from_class(class: Class<'js, T>) -> Self {
364 Self::try_from_class(class).unwrap()
365 }
366
367 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 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}