@@ -109,6 +109,8 @@ pub struct Node {
109109 pub children : RefCell < Vec < Handle > > ,
110110 /// Represents this node's data.
111111 pub data : NodeData ,
112+ /// Flag to control whether to free any children on destruction.
113+ leak_children_on_drop : Cell < bool > ,
112114}
113115
114116impl Node {
@@ -118,8 +120,38 @@ impl Node {
118120 data : data,
119121 parent : Cell :: new ( None ) ,
120122 children : RefCell :: new ( Vec :: new ( ) ) ,
123+ leak_children_on_drop : Cell :: new ( true ) ,
121124 } )
122125 }
126+
127+ /// Drop any child nodes remaining in this node at destruction.
128+ ///
129+ /// RcDom's destructor automatically drops any nodes and children that are
130+ /// present in the document. This setting only affects nodes that are dropped
131+ /// by manipulating the tree before RcDom's destructor runs (such as manually
132+ /// removing children from a node after parsing is complete).
133+ ///
134+ /// Unsafety: due to the representation of children, this can trigger
135+ /// stack overflow if dropping a node with a very deep tree of children.
136+ /// This is not a recommended configuration to use when interacting with
137+ /// arbitrary HTML content.
138+ pub unsafe fn free_child_nodes_on_drop ( & self ) {
139+ self . leak_children_on_drop . set ( false ) ;
140+ }
141+ }
142+
143+ impl Drop for Node {
144+ fn drop ( & mut self ) {
145+ if !self . children . borrow ( ) . is_empty ( ) {
146+ if self . leak_children_on_drop . get ( ) {
147+ warn ! ( "Dropping node with children outside of RcDom's destructor. \
148+ Leaking memory for {} children.", self . children. borrow( ) . len( ) ) ;
149+ for child in mem:: replace ( & mut * self . children . borrow_mut ( ) , vec ! [ ] ) {
150+ mem:: forget ( child) ;
151+ }
152+ }
153+ }
154+ }
123155}
124156
125157impl fmt:: Debug for Node {
@@ -195,6 +227,18 @@ pub struct RcDom {
195227 pub quirks_mode : QuirksMode ,
196228}
197229
230+ impl Drop for RcDom {
231+ fn drop ( & mut self ) {
232+ // Ensure that node destructors execute linearly, rather
233+ // than recursing through a tree of arbitrary depth.
234+ let mut to_be_processed = vec ! [ self . document. clone( ) ] ;
235+ while let Some ( node) = to_be_processed. pop ( ) {
236+ to_be_processed. extend_from_slice ( & * node. children . borrow ( ) ) ;
237+ node. children . borrow_mut ( ) . clear ( ) ;
238+ }
239+ }
240+ }
241+
198242impl TreeSink for RcDom {
199243 type Output = Self ;
200244 fn finish ( self ) -> Self {
@@ -418,61 +462,71 @@ impl Default for RcDom {
418462 }
419463}
420464
465+ enum SerializeOp {
466+ Open ( Handle ) ,
467+ Close ( QualName )
468+ }
469+
421470impl Serialize for Handle {
422471 fn serialize < S > ( & self , serializer : & mut S , traversal_scope : TraversalScope ) -> io:: Result < ( ) >
423472 where
424473 S : Serializer ,
425474 {
426- match ( & traversal_scope, & self . data ) {
427- (
428- _,
429- & NodeData :: Element {
430- ref name,
431- ref attrs,
432- ..
433- } ,
434- ) => {
435- if traversal_scope == IncludeNode {
436- try!( serializer. start_elem (
437- name. clone ( ) ,
438- attrs. borrow ( ) . iter ( ) . map ( |at| ( & at. name , & at. value [ ..] ) )
439- ) ) ;
440- }
441-
442- for handle in self . children . borrow ( ) . iter ( ) {
443- try!( handle. clone ( ) . serialize ( serializer, IncludeNode ) ) ;
444- }
475+ let mut ops = match traversal_scope {
476+ IncludeNode => vec ! [ SerializeOp :: Open ( self . clone( ) ) ] ,
477+ ChildrenOnly ( _) => self
478+ . children
479+ . borrow ( )
480+ . iter ( )
481+ . map ( |h| SerializeOp :: Open ( h. clone ( ) ) ) . collect ( ) ,
482+ } ;
445483
446- if traversal_scope == IncludeNode {
447- try!( serializer. end_elem ( name. clone ( ) ) ) ;
484+ while !ops. is_empty ( ) {
485+ match ops. remove ( 0 ) {
486+ SerializeOp :: Open ( handle) => {
487+ match & handle. data {
488+ & NodeData :: Element {
489+ ref name,
490+ ref attrs,
491+ ..
492+ } => {
493+ try!( serializer. start_elem (
494+ name. clone ( ) ,
495+ attrs. borrow ( ) . iter ( ) . map ( |at| ( & at. name , & at. value [ ..] ) )
496+ ) ) ;
497+
498+ ops. insert ( 0 , SerializeOp :: Close ( name. clone ( ) ) ) ;
499+
500+ for child in handle. children . borrow ( ) . iter ( ) . rev ( ) {
501+ ops. insert ( 0 , SerializeOp :: Open ( child. clone ( ) ) ) ;
502+ }
503+ }
504+
505+ & NodeData :: Doctype { ref name, .. } => serializer. write_doctype ( & name) ?,
506+
507+ & NodeData :: Text { ref contents } => {
508+ serializer. write_text ( & contents. borrow ( ) ) ?
509+ }
510+
511+ & NodeData :: Comment { ref contents } => {
512+ serializer. write_comment ( & contents) ?
513+ } ,
514+
515+ & NodeData :: ProcessingInstruction {
516+ ref target,
517+ ref contents,
518+ } => serializer. write_processing_instruction ( target, contents) ?,
519+
520+ & NodeData :: Document => panic ! ( "Can't serialize Document node itself" ) ,
521+ }
448522 }
449- Ok ( ( ) )
450- } ,
451523
452- ( & ChildrenOnly ( _) , & NodeData :: Document ) => {
453- for handle in self . children . borrow ( ) . iter ( ) {
454- try!( handle. clone ( ) . serialize ( serializer, IncludeNode ) ) ;
524+ SerializeOp :: Close ( name) => {
525+ try!( serializer. end_elem ( name) ) ;
455526 }
456- Ok ( ( ) )
457- } ,
458-
459- ( & ChildrenOnly ( _) , _) => Ok ( ( ) ) ,
460-
461- ( & IncludeNode , & NodeData :: Doctype { ref name, .. } ) => serializer. write_doctype ( & name) ,
462- ( & IncludeNode , & NodeData :: Text { ref contents } ) => {
463- serializer. write_text ( & contents. borrow ( ) )
464- } ,
465- ( & IncludeNode , & NodeData :: Comment { ref contents } ) => {
466- serializer. write_comment ( & contents)
467- } ,
468- (
469- & IncludeNode ,
470- & NodeData :: ProcessingInstruction {
471- ref target,
472- ref contents,
473- } ,
474- ) => serializer. write_processing_instruction ( target, contents) ,
475- ( & IncludeNode , & NodeData :: Document ) => panic ! ( "Can't serialize Document node itself" ) ,
527+ }
476528 }
529+
530+ Ok ( ( ) )
477531 }
478532}
0 commit comments