1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
//! Provides temporary access to JavaScript typed arrays. //! //! ## Typed Arrays //! //! JavaScript's [typed arrays][typed-arrays] are objects that allow reading and writing //! raw binary data in memory. //! //! Typed arrays are managed with the [`ArrayBuffer`][ArrayBuffer] type, which controls //! the storage of the underlying data buffer, and several typed views for managing access //! to the buffer. Neon provides access to the `ArrayBuffer` class with the //! [`JsArrayBuffer`](crate::types::JsArrayBuffer) type. //! //! Node also provides a [`Buffer`][Buffer] type, which is built on top of `ArrayBuffer` //! and provides additional functionality. Neon provides access to the `Buffer` class //! with the [`JsBuffer`](crate::types::JsBuffer) type. //! //! Many of Node's I/O APIs work with these types, and they can also be used for //! compact in-memory data structures, which can be shared efficiently between //! JavaScript and Rust without copying. //! //! ## Borrowing //! //! Neon makes it possible to [borrow][borrow] temporary access to the internal memory //! of a typed array by pausing execution of JavaScript with a //! [`Lock`](crate::context::Lock) and returning a reference to a //! [`BinaryData`](crate::types::BinaryData) struct. The [`Borrow`](Borrow) and //! [`BorrowMut`](BorrowMut) traits provide the methods for borrowing this typed array data. //! //! [typed-arrays]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays //! [borrow]: https://doc.rust-lang.org/beta/rust-by-example/scope/borrow.html //! [ArrayBuffer]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer //! [Buffer]: https://nodejs.org/api/buffer.html pub(crate) mod internal; use std::fmt; use std::ops::{Deref, DerefMut, Drop}; use std::os::raw::c_void; use self::internal::Pointer; use crate::context::Lock; /// A trait for JS values whose internal contents can be borrowed immutably by Rust while the JS engine is locked. pub trait Borrow: Sized { /// The type of the value's internal contents. type Target: Pointer; /// Borrow the contents of this value immutably. /// /// If there is already an outstanding mutable loan for this value, this method panics. fn borrow<'a>(self, lock: &'a Lock<'a>) -> Ref<'a, Self::Target> { match self.try_borrow(lock) { Ok(r) => r, Err(e) => panic!("{}", e), } } /// Borrow the contents of this value immutably. /// /// If there is already an outstanding mutable loan for this value, this method fails with a `LoanError`. fn try_borrow<'a>(self, lock: &'a Lock<'a>) -> Result<Ref<'a, Self::Target>, LoanError>; } /// A trait for JS values whose internal contents can be borrowed mutably by Rust while the JS engine is locked. pub trait BorrowMut: Borrow { /// Borrow the contents of this value mutably. /// /// If there is already an outstanding loan for this value, this method panics. fn borrow_mut<'a>(self, lock: &'a Lock<'a>) -> RefMut<'a, Self::Target> { match self.try_borrow_mut(lock) { Ok(r) => r, Err(e) => panic!("{}", e), } } /// Borrow the contents of this value mutably. /// /// If there is already an outstanding loan for this value, this method panics. fn try_borrow_mut<'a>(self, lock: &'a Lock<'a>) -> Result<RefMut<'a, Self::Target>, LoanError>; } /// An error produced by a failed loan in the `Borrow` or `BorrowMut` traits. pub enum LoanError { /// Indicates that there is already an outstanding mutable loan for the object at this address. Mutating(*const c_void), /// Indicates that there is already an outstanding immutable loan for the object at this address. Frozen(*const c_void), } impl fmt::Display for LoanError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { LoanError::Mutating(p) => { write!(f, "outstanding mutable loan exists for object at {:?}", p) } LoanError::Frozen(p) => { write!(f, "object at {:?} is frozen", p) } } } } /// An immutable reference to the contents of a borrowed JS value. pub struct Ref<'a, T: Pointer> { pointer: T, lock: &'a Lock<'a>, } impl<'a, T: Pointer> Ref<'a, T> { pub(crate) unsafe fn new(lock: &'a Lock<'a>, pointer: T) -> Result<Self, LoanError> { let mut ledger = lock.ledger.borrow_mut(); ledger.try_borrow(pointer.as_ptr())?; Ok(Ref { pointer, lock }) } } impl<'a, T: Pointer> Drop for Ref<'a, T> { fn drop(&mut self) { let mut ledger = self.lock.ledger.borrow_mut(); ledger.settle(unsafe { self.pointer.as_ptr() }); } } impl<'a, T: Pointer> Deref for Ref<'a, T> { type Target = T; fn deref(&self) -> &Self::Target { &self.pointer } } /// A mutable reference to the contents of a borrowed JS value. pub struct RefMut<'a, T: Pointer> { pointer: T, lock: &'a Lock<'a>, } impl<'a, T: Pointer> RefMut<'a, T> { pub(crate) unsafe fn new(lock: &'a Lock<'a>, mut pointer: T) -> Result<Self, LoanError> { let mut ledger = lock.ledger.borrow_mut(); ledger.try_borrow_mut(pointer.as_mut())?; Ok(RefMut { pointer, lock }) } } impl<'a, T: Pointer> Drop for RefMut<'a, T> { fn drop(&mut self) { let mut ledger = self.lock.ledger.borrow_mut(); ledger.settle_mut(unsafe { self.pointer.as_mut() }); } } impl<'a, T: Pointer> Deref for RefMut<'a, T> { type Target = T; fn deref(&self) -> &Self::Target { &self.pointer } } impl<'a, T: Pointer> DerefMut for RefMut<'a, T> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.pointer } }