use std::collections::HashMap;
use crate::itabs::Itab;
pub const STDLIB_INTERFACES: &[&str] = &[
"*io.Reader",
"*io.Writer",
"*io.Closer",
"*io.ReadWriter",
"*io.ReadCloser",
"*io.WriteCloser",
"*io.ReadWriteCloser",
"*io.Seeker",
"*io.ReaderAt",
"*io.WriterAt",
"*io.ReaderFrom",
"*io.WriterTo",
"*io.StringWriter",
"*io.ByteReader",
"*io.ByteScanner",
"*io.RuneReader",
"*io.RuneScanner",
"*error",
"*fmt.Stringer",
"*fmt.GoStringer",
"*fmt.Formatter",
"*fmt.State",
"*fmt.Scanner",
"*fmt.ScanState",
"*net.Conn",
"*net.PacketConn",
"*net.Listener",
"*net.Addr",
"*net.Error",
"*fs.File",
"*fs.FileInfo",
"*fs.DirEntry",
"*fs.FS",
"*fs.ReadDirFile",
"*fs.ReadFileFS",
"*fs.StatFS",
"*fs.SubFS",
"*fs.GlobFS",
"*hash.Hash",
"*hash.Hash32",
"*hash.Hash64",
"*crypto.Signer",
"*crypto.Decrypter",
"*crypto.SignerOpts",
"*crypto.PublicKey",
"*crypto.PrivateKey",
"*encoding.BinaryMarshaler",
"*encoding.BinaryUnmarshaler",
"*encoding.TextMarshaler",
"*encoding.TextUnmarshaler",
"*encoding/json.Marshaler",
"*encoding/json.Unmarshaler",
"*encoding/xml.Marshaler",
"*encoding/xml.Unmarshaler",
"*sort.Interface",
"*context.Context",
"*sync.Locker",
"*database/sql/driver.Driver",
"*database/sql/driver.Conn",
"*database/sql/driver.Stmt",
"*database/sql/driver.Rows",
"*database/sql/driver.Result",
"*database/sql/driver.Tx",
"*database/sql.Scanner",
"*driver.Valuer",
"*http.Handler",
"*http.ResponseWriter",
"*http.RoundTripper",
"*http.CookieJar",
"*http.Flusher",
"*http.Hijacker",
"*http.Pusher",
"*tls.ClientSessionCache",
"*reflect.Type",
];
pub fn classify_itabs(itabs: &[Itab]) -> Vec<(&'static str, usize)> {
let interesting: HashMap<&str, &'static str> =
STDLIB_INTERFACES.iter().map(|s| (*s, *s)).collect();
let mut counts: HashMap<&'static str, usize> = HashMap::new();
for itab in itabs {
if let Some(canonical) = interesting.get(itab.interface_name.as_str()) {
*counts.entry(canonical).or_insert(0) += 1;
}
}
let mut sorted: Vec<(&'static str, usize)> = counts.into_iter().collect();
sorted.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(b.0)));
sorted
}
pub fn is_stdlib_interface(name: &str) -> bool {
STDLIB_INTERFACES.contains(&name)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn recognizes_common_interfaces() {
assert!(is_stdlib_interface("*io.Writer"));
assert!(is_stdlib_interface("*net.Conn"));
assert!(is_stdlib_interface("*sort.Interface"));
assert!(!is_stdlib_interface("*main.MyInterface"));
assert!(!is_stdlib_interface("io.Writer"));
}
}