calltrace/calls/
mod.rs

1pub mod callstack;
2pub mod frame;
3use crate::quote::MatchQuote;
4use anyhow::Result;
5use callstack::CallStack;
6use std::fmt;
7use std::fs::File;
8use std::io::Read;
9use std::iter::Iterator;
10pub struct CallStacks {
11    pub data: Vec<CallStack>,
12}
13
14impl std::fmt::Display for CallStacks {
15    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16        for k in &self.data {
17            write!(f, "{}", &k)?;
18        }
19        writeln!(f)
20    }
21}
22impl Default for CallStacks {
23    fn default() -> Self {
24        Self::new()
25    }
26}
27
28impl IntoIterator for CallStacks{
29    type Item = CallStack;
30    type IntoIter = <Vec<CallStack> as IntoIterator>::IntoIter;
31    fn into_iter(self) -> Self::IntoIter {
32        self.data.into_iter()
33    }
34}
35impl CallStacks {
36    pub fn iter(&self) -> std::slice::Iter<'_, CallStack> {
37        self.data.iter()
38    }
39    pub fn from_file(
40        s: &str,
41        starts: &[&dyn MatchQuote],
42        ends: &[&dyn MatchQuote],
43    ) -> Result<Self> {
44        let mut file = File::open(s)?;
45        let mut content = String::new();
46        let size = file.read_to_string(&mut content)?;
47        if size == 0 {
48            return Ok(CallStacks::default());
49        }
50
51        Ok(Self::from_string(&content, starts, ends))
52    }
53    pub fn new() -> Self {
54        CallStacks { data: vec![] }
55    }
56
57    pub fn push(&mut self, cs: CallStack) {
58        self.data.push(cs);
59    }
60    pub fn from_string(s: &str, starts: &[&dyn MatchQuote], ends: &[&dyn MatchQuote]) -> Self {
61        let mut css = CallStacks::new();
62        let mut cs = Some(CallStack::new()); // according to https://users.rust-lang.org/t/error-reinitialization-might-get-skipped-actually-will-not-get-skipped-in-this-case/80132/2
63        let mut in_frames = false;
64        for line in s.lines() {
65            if starts.iter().any(|s| s.match_quote(line)) && !in_frames {
66                // call stack starts
67                in_frames = true;
68                cs = Some(CallStack::new());
69
70                continue;
71            }
72            if ends.iter().any(|s| s.match_quote(line)) && in_frames {
73                // call stack ends
74                css.push(cs.take().unwrap());
75                in_frames = false;
76                continue;
77            }
78
79            if !line.trim().is_empty() && in_frames {
80                cs.as_mut().unwrap().append(line.trim().to_string());
81            }
82        }
83        css
84    }
85    pub fn len(&self) -> usize {
86        self.data.len()
87    }
88    pub fn is_empty(&self) -> bool {
89        self.data.is_empty()
90    }
91    pub fn has(&self, cs: &CallStack) -> bool {
92        self.data.iter().any(|e| e == cs)
93    }
94}
95
96#[cfg(test)]
97mod test;