@@ -11,13 +11,13 @@ use core::cmp::Ordering;
1111use core:: fmt;
1212use core:: ops;
1313
14- use anyhow:: Result ;
14+ use anyhow:: { bail , Result } ;
1515
1616use crate :: value:: Value ;
1717
1818#[ cfg( feature = "rvm" ) ]
1919#[ allow( unused_imports) ] // surface for downstream PRs
20- pub use iter:: Cursor ;
20+ pub use iter:: ArrayCursor ;
2121#[ allow( unused_imports) ] // surface for downstream PRs
2222pub use iter:: { IntoIter , Iter , IterMut } ;
2323
@@ -32,6 +32,21 @@ pub use iter::{IntoIter, Iter, IterMut};
3232/// - [`Array::iter`] — sequence order; non-resumable.
3333/// - [`Array::cursor`] / [`Array::next`] — sequence order, resumable. Used by
3434/// interpreter/RVM when iteration must yield mid-flight.
35+ ///
36+ /// # Memory-limit enforcement
37+ ///
38+ /// Growth-path methods that take a fallible `Result` return value
39+ /// ([`Array::push`], [`Array::extend_from_slice`], [`Array::insert`],
40+ /// [`Array::with_capacity`], [`Array::try_from_vec`], [`Array::try_from_iter`])
41+ /// consult the configured cooperative memory limit and report
42+ /// `Err` when it is exceeded; the array is left in a consistent state (any
43+ /// in-progress mutation that would have crossed the limit is rolled back).
44+ ///
45+ /// Infallible trait impls ([`Extend`], [`FromIterator`], [`From<Vec<Value>>`])
46+ /// match the [`crate::value::Object`] convention and **do not** consult the
47+ /// cooperative limit — they exist for ergonomic / migration use and rely on the
48+ /// allocator to fail on true OOM. Limit-aware callers must use the explicit
49+ /// fallible methods above.
3550#[ derive( Default , Clone , Eq , PartialEq ) ]
3651pub struct Array {
3752 inner : Vec < Value > ,
@@ -46,12 +61,14 @@ impl Array {
4661
4762 /// Create an empty `Array` with space for at least `capacity` elements.
4863 ///
49- /// Returns `None` if the requested capacity is too large or cannot be
50- /// reserved by the allocator.
64+ /// Returns `None` if the requested capacity is too large for the
65+ /// allocator, or if reserving it would push memory usage past the
66+ /// configured cooperative limit.
5167 #[ inline]
5268 pub fn with_capacity ( capacity : usize ) -> Option < Self > {
5369 let mut inner = Vec :: new ( ) ;
5470 inner. try_reserve ( capacity) . ok ( ) ?;
71+ crate :: utils:: limits:: check_memory_limit_if_needed ( ) . ok ( ) ?;
5572 Some ( Self { inner } )
5673 }
5774
@@ -106,12 +123,18 @@ impl Array {
106123
107124 /// Appends `value` to the end of the array.
108125 ///
109- /// Returns an error if the configured memory limit is exceeded after the
110- /// growth operation.
126+ /// Returns `Err` if the cooperative memory limit would be exceeded by the
127+ /// appended element; in that case the value is rolled back (popped) before
128+ /// returning, so the array length is unchanged.
111129 #[ inline]
112130 pub fn push ( & mut self , value : Value ) -> Result < ( ) > {
113131 self . inner . push ( value) ;
114- crate :: utils:: limits:: check_memory_limit_if_needed ( ) . map_err ( anyhow:: Error :: new)
132+ if let Err ( err) = crate :: utils:: limits:: check_memory_limit_if_needed ( ) {
133+ // Roll back the mutation so the caller observes a consistent state.
134+ self . inner . pop ( ) ;
135+ return Err ( anyhow:: Error :: new ( err) ) ;
136+ }
137+ Ok ( ( ) )
115138 }
116139
117140 #[ inline]
@@ -126,15 +149,22 @@ impl Array {
126149
127150 /// Inserts `value` at `index`, shifting existing elements right.
128151 ///
129- /// Returns `Some(())` on success, or `None` if `index > self.len()`
130- /// (rather than panicking — this is a host-reachable API surface).
152+ /// Returns `Err` if `index > self.len()` (rather than panicking — this is
153+ /// a host-reachable API surface) or if the cooperative memory limit would
154+ /// be exceeded by the appended element; in the limit case the insertion is
155+ /// rolled back so the array length is unchanged.
131156 #[ inline]
132- pub fn insert ( & mut self , index : usize , value : Value ) -> Option < ( ) > {
133- if index > self . inner . len ( ) {
134- return None ;
157+ pub fn insert ( & mut self , index : usize , value : Value ) -> Result < ( ) > {
158+ let len = self . inner . len ( ) ;
159+ if index > len {
160+ bail ! ( "Array::insert: index {index} out of bounds (len={len})" ) ;
135161 }
136162 self . inner . insert ( index, value) ;
137- Some ( ( ) )
163+ if let Err ( err) = crate :: utils:: limits:: check_memory_limit_if_needed ( ) {
164+ self . inner . remove ( index) ;
165+ return Err ( anyhow:: Error :: new ( err) ) ;
166+ }
167+ Ok ( ( ) )
138168 }
139169
140170 /// Removes and returns the element at `index`, shifting subsequent
@@ -175,11 +205,17 @@ impl Array {
175205
176206 /// Extends the array by cloning values from `other`.
177207 ///
178- /// Checks the configured memory limit after each appended element.
179- #[ inline]
208+ /// Checks the cooperative memory limit after each appended element; on
209+ /// failure, all elements appended by this call (including the offending
210+ /// one) are rolled back so the array length is unchanged.
180211 pub fn extend_from_slice ( & mut self , other : & [ Value ] ) -> Result < ( ) > {
212+ let original_len = self . inner . len ( ) ;
181213 for value in other {
182- self . push ( value. clone ( ) ) ?;
214+ self . inner . push ( value. clone ( ) ) ;
215+ if let Err ( err) = crate :: utils:: limits:: check_memory_limit_if_needed ( ) {
216+ self . inner . truncate ( original_len) ;
217+ return Err ( anyhow:: Error :: new ( err) ) ;
218+ }
183219 }
184220 Ok ( ( ) )
185221 }
@@ -189,6 +225,27 @@ impl Array {
189225 self . inner . reverse ( ) ;
190226 }
191227
228+ /// Build an `Array` from an existing `Vec<Value>` with memory-limit
229+ /// enforcement. Returns `Err` if the cooperative limit is exceeded after
230+ /// taking ownership of `values`.
231+ #[ inline]
232+ pub fn try_from_vec ( values : Vec < Value > ) -> Result < Self > {
233+ let array = Self { inner : values } ;
234+ crate :: utils:: limits:: check_memory_limit_if_needed ( ) . map_err ( anyhow:: Error :: new) ?;
235+ Ok ( array)
236+ }
237+
238+ /// Collect an iterator of `Value`s into an `Array` with memory-limit
239+ /// enforcement per-element. Rolls back any partially-collected state on
240+ /// limit failure (the returned `Err` leaves nothing behind).
241+ pub fn try_from_iter < I : IntoIterator < Item = Value > > ( iter : I ) -> Result < Self > {
242+ let mut array = Self :: new ( ) ;
243+ for value in iter {
244+ array. push ( value) ?;
245+ }
246+ Ok ( array)
247+ }
248+
192249 /// Wrap into a `Value::Array`.
193250 #[ inline]
194251 pub fn into_value ( self ) -> Value {
@@ -205,13 +262,13 @@ impl Array {
205262 /// current contents at each stored index.
206263 #[ cfg( feature = "rvm" ) ]
207264 #[ inline]
208- pub const fn cursor ( & self ) -> Cursor {
209- Cursor { next : 0 }
265+ pub const fn cursor ( & self ) -> ArrayCursor {
266+ ArrayCursor { next : 0 }
210267 }
211268
212269 /// Advance `cursor` and yield the next `(index, value)` pair. O(1).
213270 #[ cfg( feature = "rvm" ) ]
214- pub fn next < ' a > ( & ' a self , cursor : & mut Cursor ) -> Option < ( usize , & ' a Value ) > {
271+ pub fn next < ' a > ( & ' a self , cursor : & mut ArrayCursor ) -> Option < ( usize , & ' a Value ) > {
215272 let index = cursor. next ;
216273 let value = self . inner . get ( index) ?;
217274 cursor. next = index. saturating_add ( 1 ) ;
@@ -256,25 +313,25 @@ impl ops::Index<usize> for Array {
256313 }
257314}
258315
259- fn abort_on_growth_error ( result : Result < ( ) > ) {
260- if result . is_err ( ) {
261- alloc :: alloc :: handle_alloc_error ( core :: alloc :: Layout :: new :: < Value > ( ) ) ;
262- }
263- }
316+ // Bulk-insertion trait impls mirror the [`crate::value::Object`] convention:
317+ // they delegate directly to the inner container and **do not** consult the
318+ // cooperative memory limit. Limit-aware callers must use [`Array::push`],
319+ // [`Array::extend_from_slice`], [`Array::try_from_vec`], or
320+ // [`Array::try_from_iter`].
264321
265322impl Extend < Value > for Array {
323+ #[ inline]
266324 fn extend < I : IntoIterator < Item = Value > > ( & mut self , iter : I ) {
267- for value in iter {
268- abort_on_growth_error ( self . push ( value) ) ;
269- }
325+ self . inner . extend ( iter) ;
270326 }
271327}
272328
273329impl FromIterator < Value > for Array {
330+ #[ inline]
274331 fn from_iter < I : IntoIterator < Item = Value > > ( iter : I ) -> Self {
275- let mut array = Self :: new ( ) ;
276- array . extend ( iter) ;
277- array
332+ Self {
333+ inner : Vec :: from_iter ( iter) ,
334+ }
278335 }
279336}
280337
0 commit comments