@@ -5,6 +5,7 @@ use mozjs_sys::jsapi::JS;
55use mozjs_sys:: jsgc:: GCMethods ;
66use mozjs_sys:: jsval:: JSVal ;
77use mozjs_sys:: trace:: Traceable ;
8+ use std:: marker:: PhantomData ;
89use std:: ops:: { Deref , DerefMut } ;
910
1011/// A vector of items to be rooted with `RootedVec`.
@@ -157,3 +158,219 @@ impl<T: Traceable + 'static> Drop for RootedTraceableBox<T> {
157158 }
158159 }
159160}
161+
162+ /// Inline, fixed capacity buffer of JS values with GC barriers.
163+ /// Backed by `[Heap<JSVal>; N]`, and a manual `len`.
164+ pub struct FixedValueArray < const N : usize > {
165+ elems : [ Heap < JSVal > ; N ] ,
166+ len : usize ,
167+ }
168+
169+ unsafe impl < const N : usize > Traceable for FixedValueArray < N > {
170+ unsafe fn trace ( & self , trc : * mut JSTracer ) {
171+ for i in 0 ..self . len {
172+ self . elems [ i] . trace ( trc) ;
173+ }
174+ }
175+ }
176+
177+ impl < const N : usize > FixedValueArray < N > {
178+ /// Create a new empty array, with all slots initialized to Undefined.
179+ pub fn new ( ) -> Self {
180+ Self {
181+ elems : std:: array:: from_fn ( |_| Heap :: < JSVal > :: default ( ) ) ,
182+ len : 0 ,
183+ }
184+ }
185+
186+ /// Current logical length.
187+ pub fn len ( & self ) -> usize {
188+ self . len
189+ }
190+
191+ /// Max capacity (const generic).
192+ pub fn capacity ( & self ) -> usize {
193+ N
194+ }
195+
196+ /// Push a JSVal into the next slot.
197+ /// Panics if you exceed capacity N.
198+ pub fn push ( & mut self , v : JSVal ) {
199+ assert ! ( self . len < N , "FixedValueArray capacity ({}) exceeded" , N ) ;
200+ self . elems [ self . len ] . set ( v) ;
201+ self . len += 1 ;
202+ }
203+
204+ /// Return a stable HandleValueArray that SpiderMonkey can consume.
205+ pub fn as_handle_value_array ( & self ) -> JS :: HandleValueArray {
206+ JS :: HandleValueArray {
207+ length_ : self . len ,
208+ elements_ : self . elems . as_ptr ( ) as * const JSVal ,
209+ }
210+ }
211+ }
212+
213+ /// A rooted wrapper for a FixedValueArray<N>.
214+ pub struct RootedFixedValueArray < ' a , const N : usize > {
215+ ptr : * mut FixedValueArray < N > ,
216+ _phantom : PhantomData < & ' a mut FixedValueArray < N > > ,
217+ }
218+
219+ impl < ' a , const N : usize > RootedFixedValueArray < ' a , N > {
220+ /// Allocate a FixedValueArray<N>, register it in RootedTraceableSet so the GC
221+ pub fn new ( ) -> Self {
222+ let boxed = Box :: new ( FixedValueArray :: < N > :: new ( ) ) ;
223+ let raw = Box :: into_raw ( boxed) ;
224+
225+ unsafe {
226+ RootedTraceableSet :: add ( raw) ;
227+ }
228+
229+ RootedFixedValueArray {
230+ ptr : raw,
231+ _phantom : PhantomData ,
232+ }
233+ }
234+
235+ /// Push a JSVal into the underlying fixed array.
236+ pub fn push ( & mut self , v : JSVal ) {
237+ unsafe { ( & mut * self . ptr ) . push ( v) }
238+ }
239+
240+ /// Produce a stable HandleValueArray view into the initialized prefix.
241+ pub fn as_handle_value_array ( & self ) -> JS :: HandleValueArray {
242+ unsafe { ( & * self . ptr ) . as_handle_value_array ( ) }
243+ }
244+
245+ pub fn len ( & self ) -> usize {
246+ unsafe { ( & * self . ptr ) . len ( ) }
247+ }
248+
249+ pub fn capacity ( & self ) -> usize {
250+ unsafe { ( & * self . ptr ) . capacity ( ) }
251+ }
252+ }
253+
254+ impl < ' a , const N : usize > Drop for RootedFixedValueArray < ' a , N > {
255+ fn drop ( & mut self ) {
256+ unsafe {
257+ RootedTraceableSet :: remove ( self . ptr ) ;
258+ let _ = Box :: from_raw ( self . ptr ) ;
259+ }
260+ }
261+ }
262+
263+ /// A growable, rooted, GC traceable collection of JS values.
264+ /// Elements are stored in boxed Heap<JSVal> cells so each GC cell has a stable
265+ /// address even if the Vec reallocates.
266+ pub struct DynamicValueArray {
267+ elems : Vec < Box < Heap < JSVal > > > ,
268+ }
269+
270+ unsafe impl Traceable for DynamicValueArray {
271+ unsafe fn trace ( & self , trc : * mut JSTracer ) {
272+ for heap_box in & self . elems {
273+ heap_box. trace ( trc) ;
274+ }
275+ }
276+ }
277+
278+ impl DynamicValueArray {
279+ pub fn new ( ) -> Self {
280+ DynamicValueArray { elems : Vec :: new ( ) }
281+ }
282+
283+ pub fn with_capacity ( cap : usize ) -> Self {
284+ DynamicValueArray {
285+ elems : Vec :: with_capacity ( cap) ,
286+ }
287+ }
288+
289+ pub fn push ( & mut self , v : JSVal ) {
290+ let cell = Heap :: boxed ( v) ;
291+ self . elems . push ( cell) ;
292+ }
293+
294+ pub fn len ( & self ) -> usize {
295+ self . elems . len ( )
296+ }
297+ }
298+
299+ /// A rooted, G -visible wrapper for DynamicValueArray which also owns a scratch
300+ /// Vec<JSVal> used to present a contiguous HandleValueArray view to SpiderMonkey.
301+ pub struct RootedDynamicValueArray {
302+ ptr : * mut DynamicValueArray ,
303+ scratch : Vec < JSVal > ,
304+ }
305+
306+ unsafe impl Traceable for RootedDynamicValueArray {
307+ unsafe fn trace ( & self , trc : * mut JSTracer ) {
308+ ( & * self . ptr ) . trace ( trc)
309+ }
310+ }
311+
312+ impl RootedDynamicValueArray {
313+ pub fn new ( ) -> Self {
314+ let boxed = Box :: new ( DynamicValueArray :: new ( ) ) ;
315+ let raw = Box :: into_raw ( boxed) ;
316+
317+ unsafe {
318+ RootedTraceableSet :: add ( raw) ;
319+ }
320+
321+ RootedDynamicValueArray {
322+ ptr : raw,
323+ scratch : Vec :: new ( ) ,
324+ }
325+ }
326+
327+ pub fn with_capacity ( cap : usize ) -> Self {
328+ let boxed = Box :: new ( DynamicValueArray :: with_capacity ( cap) ) ;
329+ let raw = Box :: into_raw ( boxed) ;
330+
331+ unsafe {
332+ RootedTraceableSet :: add ( raw) ;
333+ }
334+
335+ RootedDynamicValueArray {
336+ ptr : raw,
337+ scratch : Vec :: with_capacity ( cap) ,
338+ }
339+ }
340+
341+ pub fn push ( & mut self , v : JSVal ) {
342+ unsafe {
343+ ( & mut * self . ptr ) . push ( v) ;
344+ }
345+ }
346+
347+ fn rebuild_scratch ( & mut self ) {
348+ let inner = unsafe { & * self . ptr } ;
349+ self . scratch . clear ( ) ;
350+ self . scratch . reserve ( inner. len ( ) ) ;
351+ for heap_box in & inner. elems {
352+ self . scratch . push ( heap_box. get ( ) ) ;
353+ }
354+ }
355+
356+ pub fn as_handle_value_array ( & mut self ) -> JS :: HandleValueArray {
357+ self . rebuild_scratch ( ) ;
358+ JS :: HandleValueArray {
359+ length_ : self . scratch . len ( ) ,
360+ elements_ : self . scratch . as_ptr ( ) ,
361+ }
362+ }
363+
364+ pub fn len ( & self ) -> usize {
365+ unsafe { ( & * self . ptr ) . len ( ) }
366+ }
367+ }
368+
369+ impl Drop for RootedDynamicValueArray {
370+ fn drop ( & mut self ) {
371+ unsafe {
372+ RootedTraceableSet :: remove ( self . ptr ) ;
373+ let _ = Box :: from_raw ( self . ptr ) ;
374+ }
375+ }
376+ }
0 commit comments