rust_code_analysis/
count.rs

1extern crate num_format;
2
3use num_format::{Locale, ToFormattedString};
4use std::fmt;
5use std::sync::{Arc, Mutex};
6
7use crate::node::Node;
8use crate::traits::*;
9
10/// Counts the types of nodes specified in the input slice
11/// and the number of nodes in a code.
12pub fn count<T: ParserTrait>(parser: &T, filters: &[String]) -> (usize, usize) {
13    let filters = parser.get_filters(filters);
14    let node = parser.get_root();
15    let mut cursor = node.object().walk();
16    let mut stack = Vec::new();
17    let mut good = 0;
18    let mut total = 0;
19
20    stack.push(node);
21
22    while let Some(node) = stack.pop() {
23        total += 1;
24        if filters.any(&node) {
25            good += 1;
26        }
27        cursor.reset(node.object());
28        if cursor.goto_first_child() {
29            loop {
30                stack.push(Node::new(cursor.node()));
31                if !cursor.goto_next_sibling() {
32                    break;
33                }
34            }
35        }
36    }
37    (good, total)
38}
39
40/// Configuration options for counting different
41/// types of nodes in a code.
42pub struct CountCfg {
43    /// Types of nodes to count
44    pub filters: Vec<String>,
45    /// Number of nodes of a certain type counted by each thread
46    pub stats: Arc<Mutex<Count>>,
47}
48
49/// Count of different types of nodes in a code.
50#[derive(Debug, Default)]
51pub struct Count {
52    /// The number of specific types of nodes searched in a code
53    pub good: usize,
54    /// The total number of nodes in a code
55    pub total: usize,
56}
57
58impl Callback for Count {
59    type Res = std::io::Result<()>;
60    type Cfg = CountCfg;
61
62    fn call<T: ParserTrait>(cfg: Self::Cfg, parser: &T) -> Self::Res {
63        let (good, total) = count(parser, &cfg.filters);
64        let mut results = cfg.stats.lock().unwrap();
65        results.good += good;
66        results.total += total;
67        Ok(())
68    }
69}
70
71impl fmt::Display for Count {
72    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73        writeln!(
74            f,
75            "Total nodes: {}",
76            self.total.to_formatted_string(&Locale::en)
77        )?;
78        writeln!(
79            f,
80            "Found nodes: {}",
81            self.good.to_formatted_string(&Locale::en)
82        )?;
83        write!(
84            f,
85            "Percentage: {:.2}%",
86            (self.good as f64) / (self.total as f64) * 100.
87        )
88    }
89}