boa_engine/object/builtins/
jssharedarraybuffer.rs1use crate::{
3 Context, JsResult, JsValue,
4 builtins::array_buffer::{SharedArrayBuffer, utils::SliceRef},
5 error::JsNativeError,
6 object::JsObject,
7 value::TryFromJs,
8};
9use boa_gc::{Finalize, Trace};
10use std::{ops::Deref, sync::atomic::Ordering};
11
12#[derive(Debug, Clone, Trace, Finalize)]
14#[boa_gc(unsafe_no_drop)]
15pub struct JsSharedArrayBuffer {
16 inner: JsObject<SharedArrayBuffer>,
17}
18
19impl From<JsSharedArrayBuffer> for JsObject<SharedArrayBuffer> {
20 #[inline]
21 fn from(value: JsSharedArrayBuffer) -> Self {
22 value.inner
23 }
24}
25
26impl From<JsObject<SharedArrayBuffer>> for JsSharedArrayBuffer {
27 #[inline]
28 fn from(value: JsObject<SharedArrayBuffer>) -> Self {
29 JsSharedArrayBuffer { inner: value }
30 }
31}
32
33impl JsSharedArrayBuffer {
34 #[inline]
36 pub fn new(byte_length: usize, context: &mut Context) -> JsResult<Self> {
37 let inner = SharedArrayBuffer::allocate(
38 &context
39 .intrinsics()
40 .constructors()
41 .shared_array_buffer()
42 .constructor()
43 .into(),
44 byte_length as u64,
45 None,
46 context,
47 )?;
48
49 Ok(Self { inner })
50 }
51
52 #[inline]
54 pub fn from_buffer(buffer: SharedArrayBuffer, context: &mut Context) -> Self {
55 let proto = context
56 .intrinsics()
57 .constructors()
58 .shared_array_buffer()
59 .prototype();
60
61 let inner = JsObject::new(context.root_shape(), proto, buffer);
62
63 Self { inner }
64 }
65
66 #[inline]
72 pub fn from_object(object: JsObject) -> JsResult<Self> {
73 object
74 .downcast::<SharedArrayBuffer>()
75 .map(|inner| Self { inner })
76 .map_err(|_| {
77 JsNativeError::typ()
78 .with_message("object is not a SharedArrayBuffer")
79 .into()
80 })
81 }
82
83 #[inline]
85 #[must_use]
86 pub fn byte_length(&self) -> usize {
87 self.borrow().data().len(Ordering::SeqCst)
88 }
89
90 #[must_use]
108 pub fn to_vec(&self) -> Vec<u8> {
109 let obj = self.borrow();
110 let src = obj.data().bytes(Ordering::SeqCst);
111 let src = SliceRef::AtomicSlice(src);
112 src.to_vec()
113 }
114
115 #[inline]
117 #[must_use]
118 pub fn inner(&self) -> SharedArrayBuffer {
119 self.borrow().data().clone()
120 }
121}
122
123impl From<JsSharedArrayBuffer> for JsObject {
124 #[inline]
125 fn from(o: JsSharedArrayBuffer) -> Self {
126 o.inner.upcast()
127 }
128}
129
130impl From<JsSharedArrayBuffer> for JsValue {
131 #[inline]
132 fn from(o: JsSharedArrayBuffer) -> Self {
133 o.inner.upcast().into()
134 }
135}
136
137impl Deref for JsSharedArrayBuffer {
138 type Target = JsObject<SharedArrayBuffer>;
139
140 #[inline]
141 fn deref(&self) -> &Self::Target {
142 &self.inner
143 }
144}
145
146impl TryFromJs for JsSharedArrayBuffer {
147 fn try_from_js(value: &JsValue, _context: &mut Context) -> JsResult<Self> {
148 if let Some(o) = value.as_object() {
149 Self::from_object(o.clone())
150 } else {
151 Err(JsNativeError::typ()
152 .with_message("value is not a SharedArrayBuffer object")
153 .into())
154 }
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161
162 #[test]
163 fn shared_array_buffer_to_vec_roundtrip() {
164 let context = &mut Context::default();
165 let len = 64;
166 let sab = JsSharedArrayBuffer::new(len, context).unwrap();
167 assert_eq!(sab.byte_length(), len);
168
169 let inner = sab.inner();
171 let atoms = inner.bytes(Ordering::SeqCst);
172 atoms[0].store(1, Ordering::SeqCst);
173 atoms[1].store(2, Ordering::SeqCst);
174 atoms[len - 1].store(255, Ordering::SeqCst);
175
176 let bytes = sab.to_vec();
177 assert_eq!(bytes.len(), len);
178 assert_eq!(bytes[0], 1);
179 assert_eq!(bytes[1], 2);
180 assert_eq!(bytes[len - 1], 255);
181 }
182
183 #[test]
184 fn shared_array_buffer_to_vec_zero_length() {
185 let context = &mut Context::default();
186 let sab = JsSharedArrayBuffer::new(0, context).unwrap();
187 assert_eq!(sab.byte_length(), 0);
188
189 let bytes = sab.to_vec();
190 assert!(bytes.is_empty());
191 }
192}