rustemo/glr/
gss.rs

1use std::{
2    cell::RefCell,
3    collections::{HashSet, VecDeque},
4    fmt::Debug,
5    ops::Range,
6    rc::Rc,
7};
8
9use petgraph::{graph::Edges, prelude::*};
10
11use crate::{
12    context::Context, input::Input, lexer::Token, location::Location, lr::builder::LRBuilder,
13    parser::State,
14};
15
16/// Graph Structured Stack
17///
18/// Nodes keep information about state while edges keep all alternative
19/// sub-trees constructed by reduction across the edge.
20pub struct GssGraph<'i, I: Input + ?Sized, S, P, TK: Copy>(
21    #[allow(clippy::type_complexity)] Graph<GssHead<'i, I, S, TK>, Rc<Parent<'i, I, P, TK>>>,
22);
23
24impl<I, S, P, TK> Default for GssGraph<'_, I, S, P, TK>
25where
26    I: Input + ?Sized,
27    TK: Copy,
28{
29    fn default() -> Self {
30        Self(Default::default())
31    }
32}
33
34impl<'i, I, S, P, TK> GssGraph<'i, I, S, P, TK>
35where
36    I: Input + ?Sized,
37    TK: Copy,
38{
39    pub fn new() -> Self {
40        Self::default()
41    }
42
43    #[inline]
44    pub fn add_head(&mut self, head: GssHead<'i, I, S, TK>) -> NodeIndex {
45        self.0.add_node(head)
46    }
47
48    #[inline]
49    pub fn head(&self, head: NodeIndex) -> &GssHead<'i, I, S, TK> {
50        self.0.node_weight(head).expect("Invalid Gss head index!")
51    }
52
53    #[inline]
54    pub fn head_mut(&mut self, head: NodeIndex) -> &mut GssHead<'i, I, S, TK> {
55        self.0
56            .node_weight_mut(head)
57            .expect("Invalid Gss head index!")
58    }
59
60    #[inline]
61    pub fn parent(&self, index: EdgeIndex) -> Rc<Parent<'i, I, P, TK>> {
62        self.0.edge_weight(index).unwrap().clone()
63    }
64
65    #[inline]
66    pub fn add_parent(
67        &mut self,
68        start: NodeIndex,
69        end: NodeIndex,
70        parent: Rc<Parent<'i, I, P, TK>>,
71    ) -> EdgeIndex {
72        self.0.add_edge(start, end, parent)
73    }
74
75    /// Registers a new solution for the given parent link between start and end
76    /// nodes.
77    ///
78    /// If the link doesn't exist create it.
79    ///
80    /// Returns EdgeIndex of the created link or None if no link is created.
81    pub fn add_solution(
82        &mut self,
83        start: NodeIndex,
84        end: NodeIndex,
85        solution: Rc<SPPFTree<'i, I, P, TK>>,
86    ) -> Option<EdgeIndex> {
87        if let Some(edge) = self.edge_between(start, end) {
88            self.parent(edge).possibilities.borrow_mut().push(solution);
89            None
90        } else {
91            Some(self.add_parent(start, end, Rc::new(Parent::new(end, start, vec![solution]))))
92        }
93    }
94
95    #[inline]
96    pub fn backedges(&self, head: NodeIndex) -> Edges<'_, Rc<Parent<'i, I, P, TK>>, Directed> {
97        self.0.edges_directed(head, Direction::Outgoing)
98    }
99
100    #[inline]
101    pub fn start(&self, edge: EdgeIndex) -> NodeIndex {
102        self.0
103            .edge_endpoints(edge)
104            .expect("Invalid Gss edge index!")
105            .0
106    }
107
108    #[inline]
109    pub fn end(&self, edge: EdgeIndex) -> NodeIndex {
110        self.0
111            .edge_endpoints(edge)
112            .expect("Invalid Gss edge index!")
113            .1
114    }
115
116    #[inline]
117    pub fn edge_between(&self, start: NodeIndex, end: NodeIndex) -> Option<EdgeIndex> {
118        self.0.find_edge(start, end)
119    }
120}
121
122/// A node/head in the Graph Structured Stack (GSS). Implements [`Context`] for
123/// GLR parsing.
124///
125/// Each head is related to a LR parser state and a single token ahead. Lexical
126/// ambiguity, where a head may be followed by multiple different tokens, is
127/// handled by splitting the head and using the same GLR mechanics for syntax
128/// ambiguity handling. Effectively, we have per-token sub-frontiers.
129#[derive(Debug)]
130pub struct GssHead<'i, I, S, TK>
131where
132    I: Input + ?Sized,
133{
134    /// LR state reached when this node is created. Since LR state is related to
135    /// grammar symbol this carries also an information is what is the last
136    /// grammar symbol the parser has seen when reaching the current position.
137    state: S,
138
139    /// A frontier this node belongs to
140    pub frontier: usize,
141
142    /// Current position in the input
143    position: usize,
144
145    /// The range of token/non-terminal during shift/reduce operation.
146    range: Range<usize>,
147
148    location: Location,
149
150    /// Layout before the first token ahead
151    layout_ahead: Option<&'i I>,
152
153    /// Token found ahead of this node. At first it is initialized to `None`.
154    /// Finding more than one token at the current position will split the head.
155    token_ahead: Option<Token<'i, I, TK>>,
156}
157
158impl<I, S, TK> Clone for GssHead<'_, I, S, TK>
159where
160    I: Input + ?Sized,
161    S: State,
162    TK: Copy,
163{
164    fn clone(&self) -> Self {
165        Self {
166            state: self.state,
167            frontier: self.frontier,
168            position: self.position,
169            range: self.range.clone(),
170            location: self.location,
171            layout_ahead: self.layout_ahead,
172            token_ahead: self.token_ahead().cloned(),
173        }
174    }
175}
176
177impl<I: Input + ?Sized, S: Default, TK> Default for GssHead<'_, I, S, TK> {
178    fn default() -> Self {
179        Self {
180            state: Default::default(),
181            frontier: Default::default(),
182            position: Default::default(),
183            range: Default::default(),
184            location: I::start_location(),
185            layout_ahead: Default::default(),
186            token_ahead: Default::default(),
187        }
188    }
189}
190
191impl<'i, I, S, TK> GssHead<'i, I, S, TK>
192where
193    I: Input + ?Sized,
194    S: State,
195    TK: Copy,
196{
197    #[allow(clippy::too_many_arguments)]
198    pub fn new(
199        state: S,
200        frontier: usize,
201        position: usize,
202        range: Range<usize>,
203        location: Location,
204        layout_ahead: Option<&'i I>,
205        token_ahead: Option<Token<'i, I, TK>>,
206    ) -> Self {
207        Self {
208            state,
209            frontier,
210            position,
211            range,
212            location,
213            layout_ahead,
214            token_ahead,
215        }
216    }
217    pub fn with_tok_state(&self, token_ahead: Token<'i, I, TK>, state: S) -> Self {
218        Self {
219            state,
220            token_ahead: Some(token_ahead),
221            range: self.range(),
222            ..*self
223        }
224    }
225    pub fn with_tok(&self, token_ahead: Token<'i, I, TK>) -> Self {
226        Self {
227            token_ahead: Some(token_ahead),
228            range: self.range(),
229            ..*self
230        }
231    }
232}
233
234impl<'i, S, I, TK> Context<'i, I, S, TK> for GssHead<'i, I, S, TK>
235where
236    I: Input + ?Sized,
237    S: State,
238{
239    #[inline]
240    fn state(&self) -> S {
241        self.state
242    }
243
244    #[inline]
245    fn set_state(&mut self, state: S) {
246        self.state = state
247    }
248
249    #[inline]
250    fn position(&self) -> usize {
251        self.position
252    }
253
254    #[inline]
255    fn set_position(&mut self, position: usize) {
256        self.position = position
257    }
258
259    #[inline]
260    fn location(&self) -> Location {
261        self.location
262    }
263
264    #[inline]
265    fn set_location(&mut self, location: Location) {
266        self.location = location
267    }
268
269    #[inline]
270    fn range(&self) -> Range<usize> {
271        self.range.clone()
272    }
273
274    #[inline]
275    fn set_range(&mut self, range: Range<usize>) {
276        self.range = range
277    }
278
279    #[inline]
280    fn token_ahead(&self) -> Option<&Token<'i, I, TK>> {
281        self.token_ahead.as_ref()
282    }
283
284    #[inline]
285    fn set_token_ahead(&mut self, token: Token<'i, I, TK>) {
286        self.token_ahead = Some(token)
287    }
288
289    #[inline]
290    fn layout_ahead(&self) -> Option<&'i I> {
291        self.layout_ahead
292    }
293
294    #[inline]
295    fn set_layout_ahead(&mut self, layout: Option<&'i I>) {
296        self.layout_ahead = layout
297    }
298}
299
300/// A node of the Shared Packed Parse Forest (SPPF) (sub)tree
301#[derive(Debug)]
302pub enum SPPFTree<'i, I, P, TK>
303where
304    I: Input + ?Sized,
305    TK: Copy,
306{
307    Term {
308        token: Token<'i, I, TK>,
309        data: TreeData<'i, I>,
310    },
311    NonTerm {
312        prod: P,
313        data: TreeData<'i, I>,
314
315        /// Child nodes determined by the production.
316        /// References to Parent backlinks to support ambiguity as
317        /// the parent links keeps all solutions along that back-path.
318        children: RefCell<VecDeque<Rc<Parent<'i, I, P, TK>>>>,
319    },
320    // Empty Tree
321    Empty,
322}
323
324impl<'i, I, P, TK> SPPFTree<'i, I, P, TK>
325where
326    I: Input + ?Sized,
327    TK: Copy,
328{
329    fn solutions(&self) -> usize {
330        match self {
331            SPPFTree::Term { .. } => 1,
332            SPPFTree::NonTerm { children, .. } => {
333                children.borrow().iter().map(|p| p.solutions()).product()
334            }
335            SPPFTree::Empty => 0,
336        }
337    }
338
339    #[allow(clippy::mutable_key_type)]
340    fn ambiguities(&self, visited: &mut HashSet<Rc<Parent<'i, I, P, TK>>>) -> usize {
341        match self {
342            SPPFTree::Term { .. } | SPPFTree::Empty => 0,
343            SPPFTree::NonTerm { children, .. } => children
344                .borrow()
345                .iter()
346                .map(|p| {
347                    if visited.contains(p) {
348                        0
349                    } else {
350                        visited.insert(Rc::clone(p));
351                        p.ambiguities(visited)
352                    }
353                })
354                .sum(),
355        }
356    }
357}
358
359/// Implementation of Context trait for usage in Tree::build.
360impl<'i, I, S, P, TK> Context<'i, I, S, TK> for SPPFTree<'i, I, P, TK>
361where
362    I: Input + ?Sized,
363    TK: Copy,
364    S: State,
365{
366    fn state(&self) -> S {
367        panic!("state() called on SPPFTree")
368    }
369
370    fn set_state(&mut self, _state: S) {}
371
372    fn position(&self) -> usize {
373        panic!("position() called on SPPFTree")
374    }
375
376    fn set_position(&mut self, _position: usize) {}
377
378    fn location(&self) -> Location {
379        match self {
380            SPPFTree::Term { data, .. } | SPPFTree::NonTerm { data, .. } => data.location,
381            _ => panic!("Called location() on empty tree!"),
382        }
383    }
384
385    fn set_location(&mut self, _location: Location) {}
386
387    fn range(&self) -> Range<usize> {
388        match self {
389            SPPFTree::Term { data, .. } | SPPFTree::NonTerm { data, .. } => data.range.clone(),
390            _ => panic!("Called range() on empty tree!"),
391        }
392    }
393
394    fn set_range(&mut self, _range: Range<usize>) {}
395
396    fn token_ahead(&self) -> Option<&Token<'i, I, TK>> {
397        None
398    }
399
400    fn set_token_ahead(&mut self, _token: Token<'i, I, TK>) {}
401
402    fn layout_ahead(&self) -> Option<&'i I> {
403        match self {
404            SPPFTree::Term { data, .. } | SPPFTree::NonTerm { data, .. } => data.layout,
405            _ => panic!("Called layout_ahead() on empty tree!"),
406        }
407    }
408
409    fn set_layout_ahead(&mut self, _layout: Option<&'i I>) {}
410}
411
412impl<I, P, TK> Default for SPPFTree<'_, I, P, TK>
413where
414    I: Input + ?Sized,
415    TK: Copy,
416{
417    fn default() -> Self {
418        Self::Empty
419    }
420}
421
422impl<I, P, TK> Clone for SPPFTree<'_, I, P, TK>
423where
424    I: Input + ?Sized,
425    P: Clone,
426    TK: Copy,
427{
428    fn clone(&self) -> Self {
429        match self {
430            Self::Term { token, data } => Self::Term {
431                token: token.clone(),
432                data: data.clone(),
433            },
434            Self::NonTerm {
435                prod,
436                data,
437                children,
438            } => Self::NonTerm {
439                prod: prod.clone(),
440                data: data.clone(),
441                children: children.clone(),
442            },
443            Self::Empty => Self::Empty,
444        }
445    }
446}
447
448/// Additional data shared by both term/non-term tree nodes.
449#[derive(Debug)]
450pub struct TreeData<'i, I>
451where
452    I: Input + ?Sized,
453{
454    pub range: Range<usize>,
455    pub location: Location,
456    pub layout: Option<&'i I>,
457}
458
459impl<I> Clone for TreeData<'_, I>
460where
461    I: Input + ?Sized,
462{
463    fn clone(&self) -> Self {
464        Self {
465            range: self.range.clone(),
466            location: self.location,
467            layout: self.layout,
468        }
469    }
470}
471
472/// Parent backlink in the GSS structure. Keeps all possibilities/ambiguities
473/// between the root_node and the head_node.
474#[derive(Debug)]
475pub struct Parent<'i, I, P, TK>
476where
477    I: Input + ?Sized,
478    TK: Copy,
479{
480    pub root_node: NodeIndex,
481    pub head_node: NodeIndex,
482
483    /// This models ambiguity. `RefCell` is needed as we need an Interior
484    /// Mutability pattern to add new possibilities as they are discovered while
485    /// keeping the rest of the structure immutable.
486    pub possibilities: RefCell<Vec<Rc<SPPFTree<'i, I, P, TK>>>>,
487}
488
489impl<I, P, TK> PartialEq for Parent<'_, I, P, TK>
490where
491    I: Input + ?Sized,
492    TK: Copy,
493{
494    fn eq(&self, other: &Self) -> bool {
495        self.root_node == other.root_node && self.head_node == other.head_node
496    }
497}
498impl<I, P, TK> Eq for Parent<'_, I, P, TK>
499where
500    I: Input + ?Sized,
501    TK: Copy,
502{
503}
504
505impl<I, P, TK> std::hash::Hash for Parent<'_, I, P, TK>
506where
507    I: Input + ?Sized,
508    TK: Copy,
509{
510    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
511        self.root_node.hash(state);
512        self.head_node.hash(state);
513    }
514}
515
516impl<'i, I, P, TK> Parent<'i, I, P, TK>
517where
518    I: Input + ?Sized,
519    TK: Copy,
520{
521    pub fn new(
522        root_node: NodeIndex,
523        head_node: NodeIndex,
524        possibilities: Vec<Rc<SPPFTree<'i, I, P, TK>>>,
525    ) -> Self {
526        Self {
527            root_node,
528            head_node,
529            possibilities: RefCell::new(possibilities),
530        }
531    }
532
533    /// Number of possible solutions in this parent link.
534    ///
535    /// If there >1 solutions we have ambiguity along the input span covered by
536    /// this parent link.
537    pub fn solutions(&self) -> usize {
538        self.possibilities
539            .borrow()
540            .iter()
541            .map(|n| n.solutions())
542            .sum()
543    }
544
545    /// Number of ambiguous nodes in the span covered by this parent link.
546    /// If there is more than one possibility this parent link is ambiguous.
547    #[allow(clippy::mutable_key_type)]
548    pub fn ambiguities(&self, visited: &mut HashSet<Rc<Parent<'i, I, P, TK>>>) -> usize {
549        let ambiguity: usize = if self.possibilities.borrow().len() > 1 {
550            1
551        } else {
552            0
553        };
554
555        ambiguity
556            + self
557                .possibilities
558                .borrow()
559                .iter()
560                .map(|n| n.ambiguities(visited))
561                .sum::<usize>()
562    }
563}
564
565/// A wrapper type around `SPPFTree` structure to provide a view of a
566/// specific tree which index is given in idx.
567pub struct Tree<'i, I, P, TK>
568where
569    I: Input + ?Sized,
570    TK: Copy,
571{
572    idx: usize,
573    root: Rc<SPPFTree<'i, I, P, TK>>,
574}
575
576impl<I, P, TK> Debug for Tree<'_, I, P, TK>
577where
578    I: Input + ?Sized + Debug,
579    TK: Copy,
580{
581    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
582        match &*self.root {
583            SPPFTree::Term { token, .. } => write!(f, "{:#?}", token.value),
584            SPPFTree::NonTerm { .. } => write!(f, "{:#?}", self.children()),
585            SPPFTree::Empty => write!(f, "EMPTY"),
586        }
587    }
588}
589
590impl<'i, I, P, TK> Tree<'i, I, P, TK>
591where
592    I: Input + ?Sized,
593    TK: Copy,
594{
595    pub fn new(root: Rc<SPPFTree<'i, I, P, TK>>, idx: usize) -> Self {
596        Self { root, idx }
597    }
598
599    /// Return child nodes by disambiguating SPPFTree parent links based on the
600    /// current tree index and weighted numbering system.
601    pub fn children(&self) -> Vec<Tree<'i, I, P, TK>> {
602        match *self.root {
603            SPPFTree::Term { .. } | SPPFTree::Empty => vec![],
604            SPPFTree::NonTerm { ref children, .. } => {
605                let mut tree_idx = self.idx;
606                // Calculate counter division based on weighted numbering
607                // system. Basically, enumerating variations of children
608                // solutions.
609                let weights = children
610                    .borrow()
611                    .iter()
612                    .map(|c| c.solutions())
613                    .collect::<Vec<_>>();
614                children
615                    .borrow()
616                    .iter()
617                    .enumerate()
618                    .map(|(idx, child)| {
619                        let factor: usize = weights[(idx + 1)..].iter().product();
620                        let tree_idx_residual = tree_idx / factor;
621                        tree_idx %= factor;
622                        let (root, new_tree_idx) =
623                            Self::find_tree_root(&child.possibilities.borrow(), tree_idx_residual)
624                                .expect("Tree index must be valid.");
625                        Tree::new(root, new_tree_idx)
626                    })
627                    .collect()
628            }
629        }
630    }
631
632    /// Build an output of the tree using the given builder.
633    pub fn build<B: LRBuilder<'i, I, GssHead<'i, I, S, TK>, S, P, TK>, S>(
634        &self,
635        builder: &mut B,
636    ) -> B::Output
637    where
638        S: State,
639        P: Copy,
640    {
641        let mut context = GssHead::default();
642        self.build_inner(&mut context, builder);
643        builder.get_result()
644    }
645
646    fn build_inner<B: LRBuilder<'i, I, C, S, P, TK>, C, S>(&self, context: &mut C, builder: &mut B)
647    where
648        C: Context<'i, I, S, TK> + Default,
649        S: State,
650        P: Copy,
651    {
652        match &*self.root {
653            SPPFTree::Term { token, .. } => {
654                context.set_location(Context::<I, S, TK>::location(&*self.root));
655                builder.shift_action(context, token.clone())
656            }
657            SPPFTree::NonTerm { prod, .. } => {
658                let children = self.children();
659                children.iter().for_each(|c| {
660                    c.build_inner(context, builder);
661                });
662                context.set_location(Context::<I, S, TK>::location(&*self.root));
663                builder.reduce_action(context, *prod, children.len())
664            }
665            SPPFTree::Empty => (),
666        }
667    }
668
669    /// For the given tree index finds the right tree root in the given slice of
670    /// trees based on the number of solutions for each tree.
671    #[allow(clippy::type_complexity)]
672    fn find_tree_root(
673        roots: &[Rc<SPPFTree<'i, I, P, TK>>],
674        tree_idx: usize,
675    ) -> Option<(Rc<SPPFTree<'i, I, P, TK>>, usize)> {
676        if roots.is_empty() {
677            return None;
678        }
679        let mut tree_idx = tree_idx;
680        let mut root_idx = 0;
681        let mut solutions = roots[root_idx].solutions();
682        while solutions <= tree_idx {
683            root_idx += 1;
684            if root_idx >= roots.len() {
685                // Tree index is out of bounds
686                return None;
687            }
688            tree_idx -= solutions;
689            solutions = roots[root_idx].solutions();
690        }
691        Some((Rc::clone(&roots[root_idx]), tree_idx))
692    }
693
694    // TODO: Implement iteration
695}
696
697/// Shared Packed Parse Forest (SPPF) returned by the GLR parser.
698///
699/// A forest is an ordered collection of trees. Basically, a wrapper around GSS
700/// structure to provide information about number of trees/solutions,
701/// ambiguities and to provide tree extraction/navigation.
702///
703/// Trees of the forest are ordered and each tree can be extracted as either an
704/// eager or a lazy tree given its index.
705#[derive(Debug)]
706pub struct Forest<'i, I, P, TK>
707where
708    I: Input + ?Sized,
709    TK: Copy,
710{
711    /// Root nodes of trees which are possible solutions.
712    ///
713    /// Each `SPPFTree` contains one or more trees lazily extracted using the
714    /// `Tree` type.
715    results: Vec<Rc<SPPFTree<'i, I, P, TK>>>,
716}
717
718impl<'i, I, P, TK> Forest<'i, I, P, TK>
719where
720    I: Input + ?Sized,
721    TK: Copy,
722{
723    pub fn new(results: Vec<Rc<SPPFTree<'i, I, P, TK>>>) -> Self {
724        Forest { results }
725    }
726
727    #[inline]
728    pub fn get_first_tree(&self) -> Option<Tree<'i, I, P, TK>> {
729        self.get_tree(0)
730    }
731
732    /// Extracts a tree with the given index
733    pub fn get_tree(&self, idx: usize) -> Option<Tree<'i, I, P, TK>> {
734        Tree::find_tree_root(&self.results, idx).map(|(root, idx)| Tree::new(root, idx))
735    }
736
737    #[inline]
738    pub fn is_empty(&self) -> bool {
739        self.results.is_empty()
740    }
741
742    /// The total number of trees/solutions in this forest.
743    #[inline]
744    pub fn solutions(&self) -> usize {
745        self.results.iter().map(|n| n.solutions()).sum()
746    }
747
748    /// Total number of ambiguous places/nodes in this forest.
749    ///
750    /// Extracted trees are unambiguous but forests may have ambiguities.
751    /// If there is >1 trees in the forest there are ambiguities.
752    #[inline]
753    pub fn ambiguities(&self) -> usize {
754        #[allow(clippy::mutable_key_type)]
755        let mut visited: HashSet<Rc<Parent<'i, I, P, TK>>> = HashSet::new();
756        self.results
757            .iter()
758            .map(|n| n.ambiguities(&mut visited))
759            .sum::<usize>()
760            + if self.results.len() > 1 { 1 } else { 0 }
761    }
762}
763
764/// Support for into_iter, i.e. iteration in for loops
765pub struct ForestIntoIter<'i, I, P, TK>
766where
767    I: Input + ?Sized,
768    TK: Copy,
769{
770    forest: Forest<'i, I, P, TK>,
771    tree_idx: usize,
772}
773
774impl<'i, I, P, TK> IntoIterator for Forest<'i, I, P, TK>
775where
776    I: Input + ?Sized,
777    TK: Copy,
778{
779    type Item = Tree<'i, I, P, TK>;
780    type IntoIter = ForestIntoIter<'i, I, P, TK>;
781
782    fn into_iter(self) -> Self::IntoIter {
783        ForestIntoIter {
784            forest: self,
785            tree_idx: 0,
786        }
787    }
788}
789
790impl<'i, I, P, TK> Iterator for ForestIntoIter<'i, I, P, TK>
791where
792    I: Input + ?Sized,
793    TK: Copy,
794{
795    type Item = Tree<'i, I, P, TK>;
796
797    fn next(&mut self) -> Option<Self::Item> {
798        let tree = self.forest.get_tree(self.tree_idx);
799        if tree.is_some() {
800            self.tree_idx += 1;
801        }
802        tree
803    }
804}
805
806/// Support for iter()
807impl<'i, I, P, TK> Forest<'i, I, P, TK>
808where
809    I: Input + ?Sized,
810    TK: Copy,
811{
812    pub fn iter<'f>(&'f self) -> ForestIterator<'i, 'f, I, P, TK> {
813        ForestIterator {
814            forest: self,
815            tree_idx: 0,
816        }
817    }
818}
819
820pub struct ForestIterator<'i, 'f, I, P, TK>
821where
822    I: Input + ?Sized,
823    TK: Copy,
824{
825    forest: &'f Forest<'i, I, P, TK>,
826    tree_idx: usize,
827}
828
829impl<'i, I, P, TK> Iterator for ForestIterator<'i, '_, I, P, TK>
830where
831    I: Input + ?Sized,
832    TK: Copy,
833{
834    type Item = Tree<'i, I, P, TK>;
835
836    fn next(&mut self) -> Option<Self::Item> {
837        let tree = self.forest.get_tree(self.tree_idx);
838        if tree.is_some() {
839            self.tree_idx += 1;
840        }
841        tree
842    }
843}
844
845/// For loop iteration over borrowed Forest
846impl<'i, 'f, I, P, TK> IntoIterator for &'f Forest<'i, I, P, TK>
847where
848    I: Input + ?Sized,
849    TK: Copy,
850{
851    type Item = Tree<'i, I, P, TK>;
852    type IntoIter = ForestIterator<'i, 'f, I, P, TK>;
853
854    fn into_iter(self) -> Self::IntoIter {
855        self.iter()
856    }
857}