103_scan_op_tree/eg/
stash_walker0.rs1use 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); 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 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 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 if let Some(pure) = name.get(..name.len() - 2) {
60 if !self.seen.contains_key(pure) {
61 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}