Skip to main content

onde_sysctl/unix/
ctl_iter.rs

1// unix/ctl_iter.rs
2
3use super::ctl::Ctl;
4use super::funcs::next_oid;
5use crate::ctl_error::SysctlError;
6
7/// An iterator over Sysctl entries.
8pub struct CtlIter {
9    // if we are iterating over a Node, only include OIDs
10    // starting with this base. Set to None if iterating over all
11    // OIDs.
12    base: Ctl,
13    current: Ctl,
14}
15
16impl CtlIter {
17    /// Return an iterator over the complete sysctl tree.
18    pub fn root() -> Self {
19        CtlIter {
20            base: Ctl::Oid(vec![]),
21            current: Ctl::Oid(vec![1]),
22        }
23    }
24
25    /// Return an iterator over all sysctl entries below the given node.
26    pub fn below(node: Ctl) -> Self {
27        CtlIter {
28            base: node.clone(),
29            current: node,
30        }
31    }
32}
33
34impl Iterator for CtlIter {
35    type Item = Result<Ctl, SysctlError>;
36
37    fn next(&mut self) -> Option<Self::Item> {
38        let oid = match next_oid(self.current.oid()?) {
39            Ok(Some(o)) => o,
40            Err(e) => return Some(Err(e)),
41            Ok(None) => return None,
42        };
43
44        // We continue iterating as long as the oid starts with the base
45        let cont = oid.starts_with(self.base.oid()?);
46
47        self.current = Ctl::Oid(oid);
48
49        match cont {
50            true => Some(Ok(self.current.clone())),
51            false => None,
52        }
53    }
54}
55
56/// Ctl implements the IntoIterator trait to allow for easy iteration
57/// over nodes.
58///
59/// # Example
60///
61/// ```
62/// use sysctl::Sysctl;
63///
64/// let kern = sysctl::Ctl::new("kern");
65/// for ctl in kern {
66///     println!("{}", ctl.name().unwrap());
67/// }
68/// ```
69impl IntoIterator for Ctl {
70    type Item = Result<Ctl, SysctlError>;
71    type IntoIter = CtlIter;
72
73    fn into_iter(self) -> Self::IntoIter {
74        CtlIter::below(self)
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use crate::Sysctl;
81
82    #[test]
83    fn ctl_iter_iterate_all() {
84        let root = super::CtlIter::root();
85        let all_ctls: Vec<super::Ctl> = root.into_iter().filter_map(Result::ok).collect();
86        assert_ne!(all_ctls.len(), 0);
87        for ctl in &all_ctls {
88            println!("{:?}", ctl.name());
89        }
90    }
91}