use crate::{FieldInfo, QuarryError, Result, StructInfo};
use log::debug;
use serde_json::Value;
use std::collections::HashMap;
use std::sync::{Mutex, OnceLock};
const STD_SRC_PREFIX: &str = "std/src/";
const ALLOC_SRC_PREFIX: &str = "alloc/src/";
const CORE_SRC_PREFIX: &str = "core/src/";
const CRATE_PREFIX: &str = "crate::";
static STDLIB_CACHE: OnceLock<Mutex<Option<HashMap<String, StructInfo>>>> = OnceLock::new();
fn init_stdlib_types() -> Result<HashMap<String, StructInfo>> {
debug!("Initializing standard library type database");
let result = analyze_stdlib_with_rustdoc();
match &result {
Ok(types) => debug!(
"Successfully initialized stdlib database with {} types",
types.len()
),
Err(e) => debug!("Failed to initialize stdlib database: {:?}", e),
}
result
}
fn analyze_stdlib_with_rustdoc() -> Result<HashMap<String, StructInfo>> {
debug!("Starting rustdoc analysis of standard library");
debug!("Locating standard library source path");
let stdlib_path = find_stdlib_source_path()?;
debug!("Found stdlib source at: {:?}", stdlib_path);
debug!("Generating rustdoc JSON for standard library");
let types = generate_stdlib_rustdoc_json(&stdlib_path)?;
debug!(
"Generated and parsed {} types from rustdoc JSON",
types.len()
);
Ok(types)
}
fn find_stdlib_source_path() -> Result<std::path::PathBuf> {
debug!("Finding standard library source path via nightly rustc");
let output = std::process::Command::new("rustc")
.args(&["+nightly", "--print", "sysroot"])
.output()
.map_err(QuarryError::Io)?;
if !output.status.success() {
debug!("Failed to get sysroot from nightly rustc");
let error_msg = String::from_utf8_lossy(&output.stderr);
debug!("Error output: {}", error_msg);
return Err(QuarryError::TypeNotFound(
"Could not find Rust nightly sysroot. Make sure nightly toolchain is installed with: rustup toolchain install nightly".to_string(),
));
}
let sysroot_string = String::from_utf8_lossy(&output.stdout);
let sysroot = sysroot_string.trim();
debug!("Found sysroot: {}", sysroot);
let stdlib_path = std::path::PathBuf::from(sysroot)
.join("lib")
.join("rustlib")
.join("src")
.join("rust")
.join("library")
.join("std")
.join("src");
debug!("Checking for stdlib source at: {:?}", stdlib_path);
if !stdlib_path.exists() {
debug!("Standard library source not found at expected path");
return Err(QuarryError::TypeNotFound(
"Standard library source not found. Try installing rust-src component for nightly toolchain with: rustup component add rust-src --toolchain nightly".to_string()
));
}
debug!("Standard library source found successfully");
Ok(stdlib_path)
}
fn generate_stdlib_rustdoc_json(
stdlib_src_path: &std::path::Path,
) -> Result<HashMap<String, StructInfo>> {
debug!(
"Generating rustdoc JSON for stdlib at: {:?}",
stdlib_src_path
);
let library_root = stdlib_src_path.parent().ok_or_else(|| {
QuarryError::TypeNotFound("Could not find library root directory".to_string())
})?;
debug!("Using library root directory: {:?}", library_root);
let cargo_toml_path = library_root.join("Cargo.toml");
if !cargo_toml_path.exists() {
debug!("Cargo.toml not found at: {:?}", cargo_toml_path);
return Err(QuarryError::TypeNotFound(
"Standard library Cargo.toml not found. The rust-src component may be incomplete."
.to_string(),
));
}
debug!("Found Cargo.toml at: {:?}", cargo_toml_path);
let temp_dir = std::env::temp_dir().join("quarry_stdlib_docs");
debug!("Using temporary directory: {:?}", temp_dir);
if temp_dir.exists() {
debug!("Cleaning existing temporary directory");
std::fs::remove_dir_all(&temp_dir).map_err(QuarryError::Io)?;
}
std::fs::create_dir_all(&temp_dir).map_err(QuarryError::Io)?;
debug!("Executing cargo doc on the actual standard library workspace");
let output = std::process::Command::new("cargo")
.args(&[
"+nightly", "doc", "--package", "std", "--package", "alloc", "--package", "core", "--lib", "--no-deps", "--document-private-items", "--target-dir",
temp_dir.to_str().unwrap(), ])
.env("RUSTDOCFLAGS", "-Z unstable-options --output-format json") .env("RUSTC_BOOTSTRAP", "1") .env("__CARGO_DEFAULT_LIB_METADATA", "stable") .current_dir(library_root) .output()
.map_err(QuarryError::Io)?;
if !output.status.success() {
let error_msg = String::from_utf8_lossy(&output.stderr);
debug!("Cargo doc command failed with error: {}", error_msg);
let stdout_msg = String::from_utf8_lossy(&output.stdout);
if !stdout_msg.trim().is_empty() {
debug!("Cargo doc stdout: {}", stdout_msg);
}
return Err(QuarryError::TypeNotFound(format!(
"Failed to generate rustdoc JSON for standard library: {}",
error_msg
)));
}
debug!("Cargo doc execution completed successfully");
let mut all_types = HashMap::new();
let crate_names = ["std", "alloc", "core"];
for crate_name in &crate_names {
let json_path = temp_dir.join("doc").join(format!("{}.json", crate_name));
debug!("Looking for {} JSON output at: {:?}", crate_name, json_path);
if json_path.exists() {
debug!("Found {} JSON at: {:?}", crate_name, json_path);
let crate_types = parse_rustdoc_json_directly(&json_path)?;
debug!(
"Parsed {} types from {} crate",
crate_types.len(),
crate_name
);
for (name, struct_info) in crate_types {
all_types.insert(name, struct_info);
}
} else {
debug!("No JSON found for {} crate at: {:?}", crate_name, json_path);
}
}
if all_types.is_empty() {
debug!(
"No types found after parsing all expected JSON files (std.json, alloc.json, core.json)"
);
return Err(QuarryError::TypeNotFound(format!(
"Failed to parse any types from generated rustdoc JSON files"
)));
}
debug!(
"Successfully merged {} total types from all crates",
all_types.len()
);
Ok(all_types)
}
fn parse_rustdoc_json_directly(json_path: &std::path::Path) -> Result<HashMap<String, StructInfo>> {
debug!("Parsing rustdoc JSON from: {:?}", json_path);
let mut types = HashMap::new();
debug!("Reading JSON file content");
let json_content = std::fs::read_to_string(json_path).map_err(QuarryError::Io)?;
debug!("JSON file size: {} bytes", json_content.len());
debug!("Parsing JSON content");
let json: Value = serde_json::from_str(&json_content)
.map_err(|e| QuarryError::Io(std::io::Error::new(std::io::ErrorKind::InvalidData, e)))?;
debug!("Looking for 'index' section in JSON");
if let Some(index) = json.get("index") {
if let Some(index_obj) = index.as_object() {
debug!("Found index with {} items", index_obj.len());
let mut processed = 0;
for (_item_id, item_data) in index_obj {
if let Some(struct_info) = parse_item_for_struct(item_data, &json)? {
debug!("Found struct: {}", struct_info.name);
insert_struct_with_full_name(&mut types, struct_info);
}
processed += 1;
}
debug!(
"Finished processing {} items, found {} structs",
processed,
types.len()
);
} else {
debug!("Index section is not an object");
}
} else {
debug!("No 'index' section found in JSON");
}
Ok(types)
}
fn parse_item_for_struct(item_data: &Value, full_json: &Value) -> Result<Option<StructInfo>> {
let item_obj = match item_data.as_object() {
Some(obj) => obj,
None => return Ok(None),
};
let inner = match item_obj.get("inner") {
Some(inner) => inner,
None => return Ok(None),
};
let inner_obj = match inner.as_object() {
Some(obj) => obj,
None => return Ok(None),
};
let struct_data = match inner_obj.get("struct") {
Some(data) => data,
None => return Ok(None), };
let name = item_obj
.get("name")
.and_then(|n| n.as_str())
.unwrap_or("")
.to_string();
if name.is_empty() {
return Ok(None);
}
debug!("Parsing struct details for: {}", name);
debug!("Getting full path for struct: {}", name);
let full_path = get_full_path_for_item(item_obj);
let struct_name = if full_path.is_empty() {
name.clone()
} else {
full_path
};
debug!("Full struct name: {}", struct_name);
let mut struct_info = StructInfo::new(&struct_name);
debug!("Parsing struct kind and fields for: {}", struct_name);
if let Some(struct_obj) = struct_data.as_object() {
parse_struct_kind_and_fields(&mut struct_info, struct_obj, full_json)?;
debug!(
"Found {} fields for struct {}",
struct_info.fields.len(),
struct_name
);
}
if let Some(visibility) = item_obj.get("visibility") {
debug!("Struct {} visibility: {:?}", struct_name, visibility);
}
Ok(Some(struct_info))
}
fn get_full_path_for_item(item_obj: &serde_json::Map<String, Value>) -> String {
let item_name = item_obj
.get("name")
.and_then(|n| n.as_str())
.unwrap_or("unknown");
debug!("Getting full path for item: {}", item_name);
if let Some(span) = item_obj.get("span") {
debug!("Found span data for item: {}", item_name);
if let Some(span_obj) = span.as_object() {
if let Some(filename) = span_obj.get("filename") {
if let Some(filename_str) = filename.as_str() {
debug!("Source filename for {}: {}", item_name, filename_str);
if let Some(module_path) = extract_module_path_from_filename(filename_str) {
let full_path = format!("{}::{}", module_path, item_name);
debug!("Constructed full path for {}: {}", item_name, full_path);
return full_path;
} else {
debug!(
"Could not extract module path from filename: {}",
filename_str
);
}
}
}
}
}
debug!("Using fallback name for item: {}", item_name);
item_name.to_string()
}
fn process_path_parts(path_after_src: &str) -> Vec<&str> {
path_after_src
.split('/')
.filter(|&part| part != "mod.rs" && part != "lib.rs")
.map(|part| {
if part.ends_with(".rs") {
&part[..part.len() - 3]
} else {
part
}
})
.collect()
}
fn extract_module_path_from_filename(filename: &str) -> Option<String> {
debug!("Extracting module path from filename: {}", filename);
if let Some(pos) = filename.find(STD_SRC_PREFIX) {
debug!("Found std library pattern in filename at position: {}", pos);
let after_src = &filename[pos + STD_SRC_PREFIX.len()..]; debug!("Path after 'std/src/': {}", after_src);
let path_parts = process_path_parts(after_src);
debug!("Filtered path parts: {:?}", path_parts);
if !path_parts.is_empty() {
let module_path = match path_parts.as_slice() {
["collections", "hash", "map"] => "std::collections".to_string(),
["collections", "hash", "set"] => "std::collections".to_string(),
["collections", "btree", "map"] => "std::collections".to_string(),
["collections", "btree", "set"] => "std::collections".to_string(),
["collections", "linked_list"] => "std::collections".to_string(),
["collections", "vec_deque"] => "std::collections".to_string(),
["collections", "binary_heap"] => "std::collections".to_string(),
parts if parts.len() >= 2 && parts[0] == "collections" => {
format!("std::collections")
}
_ => format!("std::{}", path_parts.join("::")),
};
debug!("Constructed module path: {}", module_path);
return Some(module_path);
} else {
debug!("No path parts found, using 'std' as module path");
return Some("std".to_string());
}
}
if let Some(pos) = filename.find(ALLOC_SRC_PREFIX) {
debug!(
"Found alloc library pattern in filename at position: {}",
pos
);
let after_src = &filename[pos + ALLOC_SRC_PREFIX.len()..]; debug!("Path after 'alloc/src/': {}", after_src);
let path_parts = process_path_parts(after_src);
debug!("Filtered alloc path parts: {:?}", path_parts);
if !path_parts.is_empty() {
let module_path = format!("alloc::{}", path_parts.join("::"));
debug!("Constructed alloc module path: {}", module_path);
return Some(module_path);
} else {
debug!("No alloc path parts found, using 'alloc' as module path");
return Some("alloc".to_string());
}
}
if let Some(pos) = filename.find(CORE_SRC_PREFIX) {
debug!(
"Found core library pattern in filename at position: {}",
pos
);
let after_src = &filename[pos + CORE_SRC_PREFIX.len()..]; debug!("Path after 'core/src/': {}", after_src);
let path_parts = process_path_parts(after_src);
debug!("Filtered core path parts: {:?}", path_parts);
if !path_parts.is_empty() {
let module_path = format!("core::{}", path_parts.join("::"));
debug!("Constructed core module path: {}", module_path);
return Some(module_path);
} else {
debug!("No core path parts found, using 'core' as module path");
return Some("core".to_string());
}
}
debug!(
"No recognized library pattern found in filename: {}",
filename
);
None
}
fn parse_struct_kind_and_fields(
struct_info: &mut StructInfo,
struct_obj: &serde_json::Map<String, Value>,
full_json: &Value,
) -> Result<()> {
debug!("Parsing struct kind for: {}", struct_info.name);
if let Some(kind) = struct_obj.get("kind") {
if let Some(kind_obj) = kind.as_object() {
if let Some(plain) = kind_obj.get("plain") {
debug!("Found plain struct type for: {}", struct_info.name);
if let Some(plain_obj) = plain.as_object() {
if let Some(field_ids) = plain_obj.get("fields").and_then(|f| f.as_array()) {
debug!(
"Found {} field IDs for struct: {}",
field_ids.len(),
struct_info.name
);
struct_info.fields =
parse_fields_by_ids(field_ids, full_json, &struct_info.simple_name)?;
}
}
} else if let Some(tuple) = kind_obj.get("tuple") {
debug!("Found tuple struct type for: {}", struct_info.name);
struct_info.is_tuple_struct = true;
if let Some(tuple_obj) = tuple.as_object() {
if let Some(field_ids) = tuple_obj.get("fields").and_then(|f| f.as_array()) {
struct_info.fields =
parse_fields_by_ids(field_ids, full_json, &struct_info.simple_name)?;
}
}
} else if kind_obj.get("unit").is_some() {
struct_info.is_unit_struct = true;
}
} else if kind.as_str() == Some("unit") {
struct_info.is_unit_struct = true;
}
}
Ok(())
}
fn parse_fields_by_ids(
field_ids: &[Value],
full_json: &Value,
struct_name: &str,
) -> Result<Vec<FieldInfo>> {
debug!(
"Parsing {} field IDs for struct: {}",
field_ids.len(),
struct_name
);
let mut fields = Vec::new();
if let Some(index) = full_json.get("index").and_then(|i| i.as_object()) {
for (i, field_id) in field_ids.iter().enumerate() {
if let Some(field_id_num) = field_id.as_u64() {
let field_id_str = field_id_num.to_string();
debug!(
"Looking up field {} (ID: {}) for struct {}",
i + 1,
field_id_str,
struct_name
);
if let Some(field_item) = index.get(&field_id_str).and_then(|f| f.as_object()) {
let field_name = field_item
.get("name")
.and_then(|n| n.as_str())
.unwrap_or("unknown")
.to_string();
let visibility = field_item
.get("visibility")
.and_then(|v| v.as_str())
.unwrap_or("private");
let is_public = visibility == "public";
debug!(
"Field '{}' visibility: {} (public: {})",
field_name, visibility, is_public
);
let field_type = if let Some(field_inner) =
field_item.get("inner").and_then(|i| i.as_object())
{
if let Some(struct_field) = field_inner.get("struct_field") {
extract_type_name_from_json(struct_field)
.unwrap_or("unknown".to_string())
} else {
"unknown".to_string()
}
} else {
"unknown".to_string()
};
debug!(
"Parsed field: {} -> {} (public: {})",
field_name, field_type, is_public
);
fields.push(FieldInfo {
name: field_name,
type_name: field_type,
is_public,
struct_name: struct_name.to_string(),
});
} else {
debug!("Could not find field item for ID: {}", field_id_str);
}
} else {
debug!("Field ID is not a valid number: {:?}", field_id);
}
}
} else {
debug!("No index found in rustdoc JSON for field lookup");
}
debug!("Parsed {} fields for struct: {}", fields.len(), struct_name);
Ok(fields)
}
fn insert_struct_with_full_name(types: &mut HashMap<String, StructInfo>, struct_info: StructInfo) {
debug!("Inserting struct with full name: {}", struct_info.name);
types.insert(struct_info.name.clone(), struct_info);
}
fn extract_type_name_from_json(type_value: &Value) -> Option<String> {
if let Some(primitive) = type_value.get("primitive").and_then(|p| p.as_str()) {
return Some(primitive.to_string());
}
if let Some(resolved_path) = type_value
.get("resolved_path")
.and_then(|rp| rp.as_object())
{
let path = resolved_path
.get("path")
.and_then(|p| p.as_str())
.unwrap_or("UnknownPath");
let clean_path = if path.starts_with(CRATE_PREFIX) {
let without_crate = &path[CRATE_PREFIX.len()..];
match without_crate {
"vec::Vec" => "Vec",
"string::String" => "String",
"collections::hash_map::HashMap" => "HashMap",
"collections::hash_set::HashSet" => "HashSet",
_ => without_crate,
}
} else {
path
};
if let Some(args) = resolved_path.get("args") {
if let Some(angle_bracketed) = args.get("angle_bracketed").and_then(|ab| ab.as_object())
{
if let Some(args_array) = angle_bracketed.get("args").and_then(|a| a.as_array()) {
let type_args: Vec<String> = args_array
.iter()
.filter_map(|arg| {
if let Some(type_obj) = arg.get("type") {
extract_type_name_from_json(type_obj)
} else {
None
}
})
.collect();
if !type_args.is_empty() {
return Some(format!("{}<{}>", clean_path, type_args.join(", ")));
}
}
}
}
return Some(clean_path.to_string());
}
if let Some(generic) = type_value.get("generic").and_then(|g| g.as_str()) {
return Some(generic.to_string());
}
None
}
pub(crate) fn mine_stdlib_struct_info(name: &str) -> Result<StructInfo> {
debug!("Mining stdlib struct info for: '{}'", name);
let cache = STDLIB_CACHE.get_or_init(|| Mutex::new(None));
let mut cache_guard = cache.lock().unwrap();
if cache_guard.is_none() {
debug!("Cache not initialized, initializing stdlib types cache");
match init_stdlib_types() {
Ok(types) => {
debug!("Successfully initialized cache with {} types", types.len());
*cache_guard = Some(types);
}
Err(e) => {
debug!("Failed to initialize stdlib types cache: {:?}", e);
return Err(e);
}
}
} else {
debug!("Using existing initialized cache");
}
let stdlib_types = cache_guard.as_ref().unwrap();
debug!("Looking for exact match for: '{}'", name);
if let Some(info) = stdlib_types.get(name) {
debug!("Found exact match for: '{}'", name);
return Ok(info.clone());
}
debug!("No exact match found, trying alias resolution for: '{}'", name);
if let Some(actual_path) = resolve_std_alias(name) {
debug!("Resolved '{}' to actual path: '{}'", name, actual_path);
if let Some(info) = stdlib_types.get(&actual_path) {
debug!("Found struct via alias resolution: '{}'", name);
let mut aliased_info = info.clone();
aliased_info.name = name.to_string();
if let Some(pos) = name.rfind("::") {
aliased_info.module_path = name[..pos].to_string();
}
if let Some(pos) = name.rfind("::") {
aliased_info.simple_name = name[pos + 2..].to_string();
}
debug!("Created aliased StructInfo: '{}' -> module: '{}', simple: '{}'",
aliased_info.name, aliased_info.module_path, aliased_info.simple_name);
return Ok(aliased_info);
} else {
debug!("Alias resolved but actual type not found: '{}'", actual_path);
}
}
debug!(
"No match found for '{}' (tried exact match and alias resolution)",
name
);
Err(QuarryError::TypeNotFound(format!(
"Type '{}' not found. Please provide the full module path (e.g., 'std::string::String', 'alloc::string::String')",
name
)))
}
fn resolve_std_alias(name: &str) -> Option<String> {
debug!("Resolving std alias for: '{}'", name);
let alias = match name {
"std::alloc::Layout" => Some("core::alloc::layout::Layout"),
"std::alloc::LayoutError" => Some("core::alloc::layout::LayoutError"),
"std::alloc::System" => Some("std::alloc::System"),
"std::any::TypeId" => Some("core::any::TypeId"),
"std::array::IntoIter" => Some("core::array::iter::IntoIter"),
"std::array::TryFromSliceError" => Some("core::array::TryFromSliceError"),
"std::ascii::EscapeDefault" => Some("core::ascii::EscapeDefault"),
"std::backtrace::Backtrace" => Some("std::backtrace::Backtrace"),
"std::boxed::Box" => Some("alloc::boxed::Box"),
"std::cell::BorrowError" => Some("core::cell::BorrowError"),
"std::cell::BorrowMutError" => Some("core::cell::BorrowMutError"),
"std::cell::Cell" => Some("core::cell::Cell"),
"std::cell::LazyCell" => Some("core::cell::lazy::LazyCell"),
"std::cell::OnceCell" => Some("core::cell::once::OnceCell"),
"std::cell::Ref" => Some("core::cell::Ref"),
"std::cell::RefCell" => Some("core::cell::RefCell"),
"std::cell::RefMut" => Some("core::cell::RefMut"),
"std::cell::UnsafeCell" => Some("core::cell::UnsafeCell"),
"std::char::CharTryFromError" => Some("core::char::convert::CharTryFromError"),
"std::char::DecodeUtf16" => Some("core::char::decode::DecodeUtf16"),
"std::char::DecodeUtf16Error" => Some("core::char::decode::DecodeUtf16Error"),
"std::char::EscapeDebug" => Some("core::char::EscapeDebug"),
"std::char::EscapeDefault" => Some("core::char::EscapeDefault"),
"std::char::EscapeUnicode" => Some("core::char::EscapeUnicode"),
"std::char::ParseCharError" => Some("core::char::convert::ParseCharError"),
"std::char::ToLowercase" => Some("core::char::ToLowercase"),
"std::char::ToUppercase" => Some("core::char::ToUppercase"),
"std::char::TryFromCharError" => Some("core::char::TryFromCharError"),
"std::cmp::Reverse" => Some("core::cmp::Reverse"),
"std::collections::BTreeMap" => Some("alloc::collections::btree::map::BTreeMap"),
"std::collections::BTreeSet" => Some("alloc::collections::btree::set::BTreeSet"),
"std::collections::BinaryHeap" => Some("alloc::collections::binary_heap::BinaryHeap"),
"std::collections::HashMap" => Some("std::collections::hash::map::HashMap"),
"std::collections::HashSet" => Some("std::collections::hash::set::HashSet"),
"std::collections::LinkedList" => Some("alloc::collections::linked_list::LinkedList"),
"std::collections::TryReserveError" => Some("alloc::collections::TryReserveError"),
"std::collections::VecDeque" => Some("alloc::collections::vec_deque::VecDeque"),
"std::ffi::CStr" => Some("core::ffi::c_str::CStr"),
"std::ffi::CString" => Some("alloc::ffi::c_str::CString"),
"std::ffi::FromBytesUntilNulError" => Some("core::ffi::c_str::FromBytesUntilNulError"),
"std::ffi::FromVecWithNulError" => Some("alloc::ffi::c_str::FromVecWithNulError"),
"std::ffi::IntoStringError" => Some("alloc::ffi::c_str::IntoStringError"),
"std::ffi::NulError" => Some("alloc::ffi::c_str::NulError"),
"std::ffi::OsStr" => Some("std::ffi::os_str::OsStr"),
"std::ffi::OsString" => Some("std::ffi::os_str::OsString"),
"std::fmt::Arguments" => Some("core::fmt::Arguments"),
"std::fmt::DebugList" => Some("core::fmt::builder::DebugList"),
"std::fmt::DebugMap" => Some("core::fmt::builder::DebugMap"),
"std::fmt::DebugSet" => Some("core::fmt::builder::DebugSet"),
"std::fmt::DebugStruct" => Some("core::fmt::builder::DebugStruct"),
"std::fmt::DebugTuple" => Some("core::fmt::builder::DebugTuple"),
"std::fmt::Error" => Some("core::fmt::Error"),
"std::fmt::Formatter" => Some("core::fmt::Formatter"),
"std::fs::DirBuilder" => Some("std::fs::DirBuilder"), "std::fs::DirEntry" => Some("std::fs::DirEntry"), "std::fs::File" => Some("std::fs::File"), "std::fs::FileTimes" => Some("std::fs::FileTimes"), "std::fs::FileType" => Some("std::fs::FileType"), "std::fs::Metadata" => Some("std::fs::Metadata"), "std::fs::OpenOptions" => Some("std::fs::OpenOptions"), "std::fs::Permissions" => Some("std::fs::Permissions"), "std::fs::ReadDir" => Some("std::fs::ReadDir"),
"std::future::Pending" => Some("core::future::pending::Pending"),
"std::future::PollFn" => Some("core::future::poll_fn::PollFn"),
"std::future::Ready" => Some("core::future::ready::Ready"),
"std::hash::BuildHasherDefault" => Some("core::hash::BuildHasherDefault"),
"std::hash::DefaultHasher" => Some("std::hash::random::DefaultHasher"),
"std::hash::RandomState" => Some("std::hash::random::RandomState"),
"std::io::BufReader" => Some("std::io::buffered::bufreader::BufReader"),
"std::io::BufWriter" => Some("std::io::buffered::bufwriter::BufWriter"),
"std::io::Bytes" => Some("std::io::Bytes"), "std::io::Chain" => Some("std::io::Chain"), "std::io::Cursor" => Some("std::io::cursor::Cursor"),
"std::io::Empty" => Some("std::io::util::Empty"),
"std::io::Error" => Some("std::io::error::Error"),
"std::io::IntoInnerError" => Some("std::io::buffered::IntoInnerError"),
"std::io::IoSlice" => Some("std::io::IoSlice"), "std::io::IoSliceMut" => Some("std::io::IoSliceMut"), "std::io::LineWriter" => Some("std::io::buffered::linewriter::LineWriter"),
"std::io::Lines" => Some("std::io::Lines"), "std::io::PipeReader" => Some("std::io::pipe::PipeReader"),
"std::io::PipeWriter" => Some("std::io::pipe::PipeWriter"),
"std::io::Repeat" => Some("std::io::util::Repeat"),
"std::io::Sink" => Some("std::io::util::Sink"),
"std::io::Split" => Some("std::io::Split"), "std::io::Stderr" => Some("std::io::stdio::Stderr"),
"std::io::StderrLock" => Some("std::io::stdio::StderrLock"),
"std::io::Stdin" => Some("std::io::stdio::Stdin"),
"std::io::StdinLock" => Some("std::io::stdio::StdinLock"),
"std::io::Stdout" => Some("std::io::stdio::Stdout"),
"std::io::StdoutLock" => Some("std::io::StdoutLock"),
"std::io::Take" => Some("std::io::Take"), "std::io::WriterPanicked" => Some("std::io::buffered::bufwriter::WriterPanicked"),
"std::iter::Chain" => Some("core::iter::adapters::chain::Chain"),
"std::iter::Cloned" => Some("core::iter::adapters::cloned::Cloned"),
"std::iter::Copied" => Some("core::iter::adapters::copied::Copied"),
"std::iter::Cycle" => Some("core::iter::adapters::cycle::Cycle"),
"std::iter::Empty" => Some("core::iter::sources::empty::Empty"),
"std::iter::Enumerate" => Some("core::iter::adapters::enumerate::Enumerate"),
"std::iter::Filter" => Some("core::iter::adapters::filter::Filter"),
"std::iter::FilterMap" => Some("core::iter::adapters::filter_map::FilterMap"),
"std::iter::FlatMap" => Some("core::iter::adapters::flatten::FlatMap"),
"std::iter::Flatten" => Some("core::iter::adapters::flatten::Flatten"),
"std::iter::FromFn" => Some("core::iter::sources::from_fn::FromFn"),
"std::iter::Fuse" => Some("core::iter::adapters::fuse::Fuse"),
"std::iter::Inspect" => Some("core::iter::adapters::inspect::Inspect"),
"std::iter::Map" => Some("core::iter::adapters::map::Map"),
"std::iter::MapWhile" => Some("core::iter::adapters::map_while::MapWhile"),
"std::iter::Once" => Some("core::iter::sources::once::Once"),
"std::iter::OnceWith" => Some("core::iter::sources::once_with::OnceWith"),
"std::iter::Peekable" => Some("core::iter::adapters::peekable::Peekable"),
"std::iter::Repeat" => Some("core::iter::sources::repeat::Repeat"),
"std::iter::RepeatN" => Some("core::iter::sources::repeat_n::RepeatN"),
"std::iter::RepeatWith" => Some("core::iter::sources::repeat_with::RepeatWith"),
"std::iter::Rev" => Some("core::iter::adapters::rev::Rev"),
"std::iter::Scan" => Some("core::iter::adapters::scan::Scan"),
"std::iter::Skip" => Some("core::iter::adapters::skip::Skip"),
"std::iter::SkipWhile" => Some("core::iter::adapters::skip_while::SkipWhile"),
"std::iter::StepBy" => Some("core::iter::adapters::step_by::StepBy"),
"std::iter::Successors" => Some("core::iter::sources::successors::Successors"),
"std::iter::Take" => Some("core::iter::adapters::take::Take"),
"std::iter::TakeWhile" => Some("core::iter::adapters::take_while::TakeWhile"),
"std::iter::Zip" => Some("core::iter::adapters::zip::Zip"),
"std::marker::PhantomData" => Some("core::marker::PhantomData"),
"std::marker::PhantomPinned" => Some("core::marker::PhantomPinned"),
"std::mem::Discriminant" => Some("core::mem::Discriminant"),
"std::mem::ManuallyDrop" => Some("core::mem::manually_drop::ManuallyDrop"),
"std::net::AddrParseError" => Some("core::net::parser::AddrParseError"),
"std::net::Incoming" => Some("std::net::tcp::Incoming"),
"std::net::Ipv4Addr" => Some("core::net::ip_addr::Ipv4Addr"),
"std::net::Ipv6Addr" => Some("core::net::ip_addr::Ipv6Addr"),
"std::net::SocketAddrV4" => Some("core::net::socket_addr::SocketAddrV4"),
"std::net::SocketAddrV6" => Some("core::net::socket_addr::SocketAddrV6"),
"std::net::TcpListener" => Some("std::net::tcp::TcpListener"),
"std::net::TcpStream" => Some("std::net::tcp::TcpStream"),
"std::net::UdpSocket" => Some("std::net::udp::UdpSocket"),
"std::num::NonZero" => Some("core::num::nonzero::NonZero"),
"std::num::ParseFloatError" => Some("core::num::dec2flt::ParseFloatError"),
"std::num::ParseIntError" => Some("core::num::error::ParseIntError"),
"std::num::Saturating" => Some("core::num::saturating::Saturating"),
"std::num::TryFromIntError" => Some("core::num::error::TryFromIntError"),
"std::num::Wrapping" => Some("core::num::wrapping::Wrapping"),
"std::ops::Range" => Some("core::ops::range::Range"),
"std::ops::RangeFrom" => Some("core::ops::range::RangeFrom"),
"std::ops::RangeFull" => Some("core::ops::range::RangeFull"),
"std::ops::RangeInclusive" => Some("core::ops::range::RangeInclusive"),
"std::ops::RangeTo" => Some("core::ops::range::RangeTo"),
"std::ops::RangeToInclusive" => Some("core::ops::range::RangeToInclusive"),
"std::option::IntoIter" => Some("core::option::IntoIter"),
"std::option::Iter" => Some("core::option::Iter"),
"std::option::IterMut" => Some("core::option::IterMut"),
"std::os::fd::BorrowedFd" => Some("std::os::fd::owned::BorrowedFd"),
"std::os::fd::OwnedFd" => Some("std::os::fd::owned::OwnedFd"),
"std::panic::AssertUnwindSafe" => Some("core::panic::unwind_safe::AssertUnwindSafe"),
"std::panic::Location" => Some("core::panic::location::Location"),
"std::panic::PanicHookInfo" => Some("std::panic::PanicHookInfo"),
"std::path::Ancestors" => Some("std::path::Ancestors"), "std::path::Components" => Some("std::path::Components"), "std::path::Display" => Some("std::path::Display"), "std::path::Iter" => Some("std::path::Iter"), "std::path::Path" => Some("std::path::Path"), "std::path::PathBuf" => Some("std::path::PathBuf"), "std::path::PrefixComponent" => Some("std::path::PrefixComponent"), "std::path::StripPrefixError" => Some("std::path::StripPrefixError"),
"std::pin::Pin" => Some("core::pin::Pin"),
"std::process::Child" => Some("std::process::Child"), "std::process::ChildStderr" => Some("std::process::ChildStderr"), "std::process::ChildStdin" => Some("std::process::ChildStdin"), "std::process::ChildStdout" => Some("std::process::ChildStdout"), "std::process::Command" => Some("std::process::Command"), "std::process::CommandArgs" => Some("std::process::CommandArgs"), "std::process::CommandEnvs" => Some("std::process::CommandEnvs"), "std::process::ExitCode" => Some("std::process::ExitCode"), "std::process::ExitStatus" => Some("std::process::ExitStatus"), "std::process::Output" => Some("std::process::Output"), "std::process::Stdio" => Some("std::process::Stdio"),
"std::ptr::NonNull" => Some("core::ptr::non_null::NonNull"),
"std::rc::Rc" => Some("alloc::rc::Rc"),
"std::rc::Weak" => Some("alloc::rc::Weak"),
"std::result::IntoIter" => Some("core::result::IntoIter"),
"std::result::Iter" => Some("core::result::Iter"),
"std::result::IterMut" => Some("core::result::IterMut"),
"std::slice::ChunkBy" => Some("core::slice::iter::ChunkBy"),
"std::slice::ChunkByMut" => Some("core::slice::iter::ChunkByMut"),
"std::slice::Chunks" => Some("core::slice::iter::Chunks"),
"std::slice::ChunksExact" => Some("core::slice::iter::ChunksExact"),
"std::slice::ChunksExactMut" => Some("core::slice::iter::ChunksExactMut"),
"std::slice::ChunksMut" => Some("core::slice::iter::ChunksMut"),
"std::slice::EscapeAscii" => Some("core::slice::ascii::EscapeAscii"),
"std::slice::Iter" => Some("core::slice::iter::Iter"),
"std::slice::IterMut" => Some("core::slice::iter::IterMut"),
"std::slice::RChunks" => Some("core::slice::iter::RChunks"),
"std::slice::RChunksExact" => Some("core::slice::iter::RChunksExact"),
"std::slice::RChunksExactMut" => Some("core::slice::iter::RChunksExactMut"),
"std::slice::RChunksMut" => Some("core::slice::iter::RChunksMut"),
"std::slice::RSplit" => Some("core::slice::iter::RSplit"),
"std::slice::RSplitMut" => Some("core::slice::iter::RSplitMut"),
"std::slice::RSplitN" => Some("core::slice::iter::RSplitN"),
"std::slice::RSplitNMut" => Some("core::slice::iter::RSplitNMut"),
"std::slice::Split" => Some("core::slice::iter::Split"),
"std::slice::SplitInclusive" => Some("core::slice::iter::SplitInclusive"),
"std::slice::SplitInclusiveMut" => Some("core::slice::iter::SplitInclusiveMut"),
"std::slice::SplitMut" => Some("core::slice::iter::SplitMut"),
"std::slice::SplitN" => Some("core::slice::iter::SplitN"),
"std::slice::SplitNMut" => Some("core::slice::iter::SplitNMut"),
"std::slice::Windows" => Some("core::slice::iter::Windows"),
"std::str::Bytes" => Some("core::str::iter::Bytes"),
"std::str::CharIndices" => Some("core::str::iter::CharIndices"),
"std::str::Chars" => Some("core::str::iter::Chars"),
"std::str::EncodeUtf16" => Some("core::str::iter::EncodeUtf16"),
"std::str::EscapeDebug" => Some("core::str::iter::EscapeDebug"),
"std::str::EscapeDefault" => Some("core::str::iter::EscapeDefault"),
"std::str::EscapeUnicode" => Some("core::str::iter::EscapeUnicode"),
"std::str::Lines" => Some("core::str::iter::Lines"),
"std::str::MatchIndices" => Some("core::str::iter::MatchIndices"),
"std::str::Matches" => Some("core::str::iter::Matches"),
"std::str::ParseBoolError" => Some("core::str::error::ParseBoolError"),
"std::str::RMatchesIndices" => Some("core::str::iter::RMatchesIndices"),
"std::str::RMatches" => Some("core::str::iter::RMatches"),
"std::str::RSplit" => Some("core::str::iter::RSplit"),
"std::str::RSplitN" => Some("core::str::iter::RSplitN"),
"std::str::RSplitTerminator" => Some("core::str::iter::RSplitTerminator"),
"std::str::Split" => Some("core::str::iter::Split"),
"std::str::SplitAsciiWhitespace" => Some("core::str::iter::SplitAsciiWhitespace"),
"std::str::SplitInclusive" => Some("core::str::iter::SplitInclusive"),
"std::str::SplitN" => Some("core::str::iter::SplitN"),
"std::str::SplitTerminator" => Some("core::str::iter::SplitTerminator"),
"std::str::SplitWhitespace" => Some("core::str::iter::SplitWhitespace"),
"std::str::Utf8Chunk" => Some("core::str::lossy::Utf8Chunk"),
"std::str::Utf8Chunks" => Some("core::str::lossy::Utf8Chunks"),
"std::str::Utf8Error" => Some("core::str::error::Utf8Error"),
"std::string::Drain" => Some("alloc::string::Drain"),
"std::string::FromUtf8Error" => Some("alloc::string::FromUtf8Error"),
"std::string::FromUtf16Error" => Some("alloc::string::FromUtf16Error"),
"std::string::String" => Some("alloc::string::String"),
"std::sync::Arc" => Some("alloc::sync::Arc"),
"std::sync::Barrier" => Some("std::sync::Barrier"), "std::sync::BarrierWaitResult" => Some("std::sync::BarrierWaitResult"), "std::sync::Condvar" => Some("std::sync::poison::condvar::Condvar"),
"std::sync::LazyLock" => Some("std::sync::lazy_lock::LazyLock"),
"std::sync::Mutex" => Some("std::sync::poison::mutex::Mutex"),
"std::sync::MutexGuard" => Some("std::sync::poison::mutex::MutexGuard"),
"std::sync::Once" => Some("std::sync::poison::once::Once"),
"std::sync::OnceLock" => Some("std::sync::once_lock::OnceLock"),
"std::sync::OnceState" => Some("std::sync::poison::once::OnceState"),
"std::sync::PoisonError" => Some("std::sync::poison::PoisonError"),
"std::sync::RwLock" => Some("std::sync::poison::rwlock::RwLock"),
"std::sync::RwLockReadGuard" => Some("std::sync::poison::rwlock::RwLockReadGuard"),
"std::sync::RwLockWriteGuard" => Some("std::sync::poison::rwlock::RwLockWriteGuard"),
"std::sync::WaitTimeoutResult" => Some("std::sync::poison::condvar::WaitTimeoutResult"),
"std::sync::Weak" => Some("alloc::sync::Weak"),
"std::task::RawWakerVTable" => Some("core::task::wake::RawWakerVTable"),
"std::task::Waker" => Some("core::task::wake::Waker"),
"std::task::Context" => Some("core::task::wake::Context"),
"std::task::RawWaker" => Some("core::task::wake::RawWaker"),
"std::thread::AccessError" => Some("std::thread::local::AccessError"),
"std::thread::Builder" => Some("std::thread::Builder"), "std::thread::JoinHandle" => Some("std::thread::JoinHandle"), "std::thread::LocalKey" => Some("std::thread::local::LocalKey"),
"std::thread::Scope" => Some("std::thread::scoped::Scope"),
"std::thread::ScopedJoinHandle" => Some("std::thread::scoped::ScopedJoinHandle"),
"std::thread::Thread" => Some("std::thread::Thread"), "std::thread::ThreadId" => Some("std::thread::ThreadId"),
"std::time::Duration" => Some("core::time::Duration"),
"std::time::Instant" => Some("std::time::Instant"), "std::time::SystemTime" => Some("std::time::SystemTime"), "std::time::SystemTimeError" => Some("std::time::SystemTimeError"), "std::time::TryFromFloatSecsError" => Some("core::time::TryFromFloatSecsError"),
"std::vec::Drain" => Some("alloc::vec::Drain"),
"std::vec::ExtractIf" => Some("alloc::vec::ExtractIf"),
"std::vec::IntoIter" => Some("alloc::vec::IntoIter"),
"std::vec::Splice" => Some("alloc::vec::Splice"),
"std::vec::Vec" => Some("alloc::vec::Vec"),
_ => None,
};
if let Some(resolved) = alias {
debug!("Resolved '{}' to '{}'", name, resolved);
Some(resolved.to_string())
} else {
debug!("No alias found for '{}'", name);
None
}
}
pub(crate) fn list_stdlib_structs() -> Result<Vec<String>> {
debug!("Listing all stdlib structs");
let cache = STDLIB_CACHE.get_or_init(|| Mutex::new(None));
let mut cache_guard = cache.lock().unwrap();
if cache_guard.is_none() {
debug!("Cache not initialized, initializing for struct listing");
match init_stdlib_types() {
Ok(types) => {
debug!("Initialized cache with {} types for listing", types.len());
*cache_guard = Some(types);
}
Err(e) => {
debug!("Failed to initialize cache for listing: {:?}", e);
return Err(e);
}
}
}
let stdlib_types = cache_guard.as_ref().unwrap();
let mut names: Vec<String> = stdlib_types.keys().cloned().collect();
names.sort();
debug!("Found {} stdlib struct names", names.len());
Ok(names)
}
pub(crate) fn is_stdlib_struct(name: &str) -> bool {
debug!("Checking if '{}' is a stdlib struct", name);
let result = mine_stdlib_struct_info(name).is_ok();
debug!("Result for '{}': {}", name, result);
result
}
pub(crate) fn clear_cache() {
debug!("Clearing stdlib cache");
if let Some(cache) = STDLIB_CACHE.get() {
let mut cache_guard = cache.lock().unwrap();
*cache_guard = None;
debug!("Stdlib cache cleared successfully");
} else {
debug!("Stdlib cache was not initialized, nothing to clear");
}
}
pub(crate) fn cache_stats() -> Result<(usize, bool)> {
debug!("Getting cache statistics");
let cache = STDLIB_CACHE.get_or_init(|| Mutex::new(None));
let cache_guard = cache.lock().unwrap();
let stats = match cache_guard.as_ref() {
Some(types) => {
debug!("Cache is initialized with {} types", types.len());
(types.len(), true)
}
None => {
debug!("Cache is not initialized");
(0, false)
}
};
Ok(stats)
}