@@ -157,29 +157,50 @@ impl IntoIterator for Array {
157157 // to the inner slice, then we can:
158158 // - Drop the elements outside our inner view,
159159 // - Move out the elements inside out inner view.
160+ // - Drop the rest of the elements when we're dropped
160161 // Otherwise, we clone everything.
161-
162- unsafe {
163- let mut inner: Rc < [ ManuallyDrop < RichTerm > ] > = transmute ( self . inner ) ;
164- let idx = self . start ;
165- let end = self . end ;
166-
167- if let Some ( slice) = Rc :: get_mut ( & mut inner) {
168- for term in & mut slice[ ..idx] {
162+ //
163+ // If we start as a shared reference, we could become the only reference
164+ // later, but we clone everything anyways, so we don't end up in an
165+ // invalid in-between state where some terms have been freed manually
166+ // and others haven't.
167+
168+ let inner = if Rc :: strong_count ( & self . inner ) != 1 || Rc :: weak_count ( & self . inner ) != 0 {
169+ IntoIterInner :: Shared ( self . inner )
170+ } else {
171+ unsafe {
172+ let mut inner =
173+ transmute :: < Rc < [ RichTerm ] > , Rc < [ ManuallyDrop < RichTerm > ] > > ( self . inner ) ;
174+ let slice =
175+ Rc :: get_mut ( & mut inner) . expect ( "non-unique Rc after checking for uniqueness" ) ;
176+ for term in & mut slice[ ..self . start ] {
169177 ManuallyDrop :: drop ( term)
170178 }
171- for term in & mut slice[ end..] {
179+ for term in & mut slice[ self . end ..] {
172180 ManuallyDrop :: drop ( term)
173181 }
174- }
175182
176- IntoIter { inner, idx, end }
183+ IntoIterInner :: Owned ( inner)
184+ }
185+ } ;
186+ IntoIter {
187+ inner,
188+ idx : self . start ,
189+ end : self . end ,
177190 }
178191 }
179192}
180193
194+ enum IntoIterInner {
195+ Shared ( Rc < [ RichTerm ] > ) ,
196+ // This shouldn't really be an Rc. It should only ever have one reference.
197+ // There may be a way to rewrite this once unsized locals are stabilized.
198+ // But for now, there is no good way to repackage the inner array, so we
199+ // keep it in an Rc.
200+ Owned ( Rc < [ ManuallyDrop < RichTerm > ] > ) ,
201+ }
181202pub struct IntoIter {
182- inner : Rc < [ ManuallyDrop < RichTerm > ] > ,
203+ inner : IntoIterInner ,
183204 idx : usize ,
184205 end : usize ,
185206}
@@ -191,14 +212,14 @@ impl Iterator for IntoIter {
191212 if self . idx == self . end {
192213 None
193214 } else {
194- let term = match Rc :: get_mut ( & mut self . inner ) {
195- None => self . inner [ .. self . end ]
196- . get ( self . idx )
197- . cloned ( )
198- . map ( ManuallyDrop :: into_inner ) ,
199- Some ( slice ) => slice [ .. self . end ]
200- . get_mut ( self . idx )
201- . map ( |t| unsafe { ManuallyDrop :: take ( t ) } ) ,
215+ let term = match & mut self . inner {
216+ IntoIterInner :: Shared ( inner ) => inner. get ( self . idx ) . cloned ( ) ,
217+ IntoIterInner :: Owned ( inner ) => unsafe {
218+ Rc :: get_mut ( inner )
219+ . expect ( "non-unique Rc after checking for uniqueness" )
220+ . get_mut ( self . idx )
221+ . map ( |t| ManuallyDrop :: take ( t ) )
222+ } ,
202223 } ;
203224
204225 self . idx += 1 ;
@@ -207,6 +228,18 @@ impl Iterator for IntoIter {
207228 }
208229}
209230
231+ impl Drop for IntoIter {
232+ fn drop ( & mut self ) {
233+ // drop the rest of the items we haven't iterated through
234+ if let IntoIterInner :: Owned ( inner) = & mut self . inner {
235+ let inner = Rc :: get_mut ( inner) . expect ( "non-unique Rc after checking for uniqueness" ) ;
236+ for term in & mut inner[ self . idx ..self . end ] {
237+ unsafe { ManuallyDrop :: drop ( term) }
238+ }
239+ }
240+ }
241+ }
242+
210243impl ExactSizeIterator for IntoIter {
211244 fn len ( & self ) -> usize {
212245 self . end - self . idx
0 commit comments