103_scan_op_tree/eg/
stash_walker0.rs

1use libperl_rs::Perl;
2use super::*;
3use super::{sv0::*,gv0::*};
4
5#[cfg(perlapi_ver26)]
6type Seen = std::collections::HashMap<String, bool>;
7
8#[cfg(perlapi_ver26)]
9pub struct StashWalker<'a, F, E>
10where F: Fn(*const libperl_sys::cv) -> bool,
11      E: FnMut(&String, *const libperl_sys::cv)
12{
13    pub perl: &'a Perl,
14    pub seen: Seen,
15    filter: Option<&'a F>,
16    emitter: &'a mut E,
17}
18
19#[cfg(perlapi_ver26)]
20impl<'a, F, E> StashWalker<'a, F, E>
21where F: Fn(*const libperl_sys::cv) -> bool,
22      E: FnMut(&String, *const libperl_sys::cv) 
23 {
24
25    pub fn new(perl: &'a Perl,
26               filter: Option<&'a F>,
27               emitter: &'a mut E) -> Self {
28        let mut seen = Seen::new();
29        seen.insert("main".to_string(), true); // To avoid main::main::main...
30        Self {
31            perl: &perl, seen, filter, emitter
32        }
33    }
34
35    pub fn walk(&mut self, pack: &str) {
36    
37        if self.seen.contains_key(pack) {return};
38        self.seen.insert(pack.to_string(), true);
39        
40        let stash = self.perl.gv_stashpv(pack, 0);
41        if stash.is_null() {return}
42
43        for (name, item) in hv_iter0::HvIter::new(&self.perl, stash) {
44
45            // ref $main::{foo} eq 'CODE'
46            if let Some(Sv::CODE(cv)) = SvRV(item).map(|sv| sv_extract(sv)) {
47                if (self.filter).map_or(true, |f| f(cv)) {
48                    (self.emitter)(&name, cv);
49                }
50            }
51            // ref (\$main::{foo}) eq 'GLOB'
52            else if let Sv::GLOB {gv, ..} = sv_extract(item) {
53                let cv = GvCV(gv);
54                if (self.filter).map_or(true, |f| f(cv)) {
55                    (self.emitter)(&name, cv);
56                }
57                if name.ends_with("::") {
58                    // println!("package name = {}", name);
59                    if let Some(pure) = name.get(..name.len() - 2) {
60                        if !self.seen.contains_key(pure) {
61                            // packages.push(String::from(pure.clone()));
62                            let mut fullpack = String::from(pack);
63                            fullpack.push_str("::");
64                            fullpack.push_str(pure);
65                            self.walk(fullpack.as_str());
66                        }
67                    }
68                }
69            }
70        }
71    }
72}