nginx_config/
visitors.rs

1//! Various visitors for working with AST
2use std::collections::VecDeque;
3
4use ast::Directive;
5use value::Value;
6
7
8/// A deep iterator over all directives in configuration file or a part of it
9#[derive(Debug)]
10pub struct DirectiveIter<'a> {
11    cur: Option<&'a Directive>,
12    queue: VecDeque<&'a Directive>,
13}
14
15impl<'a> DirectiveIter<'a> {
16    /// Start depth-first iteration over config
17    ///
18    /// This is the only constructor so var. But usually you want to use
19    /// [`config.all_directives()`] instead.
20    ///
21    /// [`config.all_directives()`]: ast/fn.all_directives.html
22    pub fn depth_first(start: &[Directive]) -> DirectiveIter {
23        DirectiveIter {
24            cur: None,
25            queue: start.iter().rev().collect()
26        }
27    }
28}
29
30impl<'a> Iterator for DirectiveIter<'a> {
31    type Item = &'a Directive;
32    fn next(&mut self) -> Option<&'a Directive> {
33        match self.cur.take() {
34            Some(dir) => {
35                if let Some(ch) = dir.item.children() {
36                    self.queue.extend(ch.iter().rev());
37                }
38            }
39            None => {}
40        }
41        match self.queue.pop_back() {
42            Some(x) => {
43                self.cur = Some(x);
44                return Some(x);
45            }
46            None => None,
47        }
48    }
49}
50
51/// A recursive mutable depth-first visitor of directives
52pub fn visit_mutable<F>(dirs: &mut Vec<Directive>, mut f: F)
53    where F: FnMut(&mut Directive)
54{
55    _visit_mutable(dirs, &mut f)
56}
57
58fn _visit_mutable<F>(dirs: &mut Vec<Directive>, f: &mut F)
59    where F: FnMut(&mut Directive)
60{
61    for dir in dirs {
62        f(dir);
63        match dir.item.children_mut() {
64            Some(children) => _visit_mutable(children, f),
65            None => {}
66        }
67    }
68}
69
70/// A recursive mutable visitor of all variable values
71///
72/// This function allows to replace all occurrences of some variable.
73/// If `f` returns `None` variable is skipped.
74pub fn replace_vars<'a, F, S>(dirs: &mut Vec<Directive>, mut f: F)
75    where F: FnMut(&str) -> Option<S>,
76          S: AsRef<str> + Into<String> + 'a,
77{
78    let mut inner_visitor = |val: &mut Value| {
79        let ref mut f = f;
80        val.replace_vars(f);
81    };
82    visit_mutable(dirs, |dir: &mut Directive| {
83        let ref mut inner_visitor = inner_visitor;
84        dir.visit_values_mut(inner_visitor);
85    });
86}