#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct FileManifest {
pub files: HashMap<PathBuf, FileEntry>,
pub coverage_required: Vec<PathBuf>,
pub manifest_hash: String,
}
impl FileManifest {
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn build(project_path: &Path) -> Result<Self> {
let mut files = HashMap::new();
let mut coverage_required = Vec::new();
for entry in walkdir::WalkDir::new(project_path)
.follow_links(false)
.into_iter()
.filter_entry(|e| !Self::is_excluded(e.path()))
.filter_map(|e| e.ok())
{
let path = entry.path();
if path.is_file() {
if let Some(file_entry) = FileEntry::from_path(path)? {
let rel_path = path
.strip_prefix(project_path)
.unwrap_or(path)
.to_path_buf();
if matches!(
file_entry.category,
FileCategory::CudaKernel | FileCategory::SimdAvx | FileCategory::RustSource
) {
coverage_required.push(rel_path.clone());
}
files.insert(rel_path, file_entry);
}
}
}
let mut hasher = Sha256::new();
let mut sorted_paths: Vec<_> = files.keys().collect();
sorted_paths.sort();
for path in sorted_paths {
hasher.update(path.to_string_lossy().as_bytes());
if let Some(entry) = files.get(path) {
hasher.update(entry.content_hash.as_bytes());
}
}
let manifest_hash = format!("{:x}", hasher.finalize());
Ok(Self {
files,
coverage_required,
manifest_hash,
})
}
fn is_excluded(path: &Path) -> bool {
let path_str = path.to_string_lossy();
path_str.contains("/target/")
|| path_str.contains("/.git/")
|| path_str.contains("/node_modules/")
|| path_str.contains("/.pmat-")
|| path_str.ends_with(".lock")
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn verify_integrity(&self, project_path: &Path) -> Vec<PathBuf> {
let mut missing = Vec::new();
for rel_path in self.files.keys() {
let full_path = project_path.join(rel_path);
if !full_path.exists() {
missing.push(rel_path.clone());
}
}
missing
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileEntry {
pub content_hash: String,
pub lines: usize,
pub functions: usize,
pub max_complexity: u32,
pub category: FileCategory,
}
impl FileEntry {
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn from_path(path: &Path) -> Result<Option<Self>> {
let extension = path.extension().and_then(|e| e.to_str());
let category = match extension {
Some("rs") => Self::categorize_rust_file(path)?,
Some("cu" | "cuh") => FileCategory::CudaKernel,
Some("c" | "cpp" | "cc" | "h" | "hpp") => FileCategory::CSource,
Some("py") => FileCategory::PythonSource,
Some("ts" | "tsx" | "js" | "jsx") => FileCategory::TypeScriptSource,
Some("go") => FileCategory::GoSource,
Some("lean") => FileCategory::LeanSource,
_ => return Ok(None),
};
let content = std::fs::read_to_string(path)?;
let lines = content.lines().count();
let mut hasher = Sha256::new();
hasher.update(content.as_bytes());
let content_hash = format!("{:x}", hasher.finalize());
let functions = Self::count_functions(&content, &category);
Ok(Some(Self {
content_hash,
lines,
functions,
max_complexity: 0, category,
}))
}
fn categorize_rust_file(path: &Path) -> Result<FileCategory> {
let content = std::fs::read_to_string(path)?;
let path_str = path.to_string_lossy();
if path_str.contains("/tests/")
|| path_str.contains("_test.rs")
|| path_str.ends_with("tests.rs")
{
return Ok(FileCategory::TestCode);
}
if path_str.ends_with("build.rs") {
return Ok(FileCategory::BuildScript);
}
if Self::contains_simd_patterns(&content) {
return Ok(FileCategory::SimdAvx);
}
Ok(FileCategory::RustSource)
}
fn contains_simd_patterns(content: &str) -> bool {
let patterns = [
"#[target_feature(enable",
"std::arch::x86_64",
"std::arch::aarch64",
concat!("_mm", "256_"),
concat!("_mm", "512_"),
concat!("_mm", "_"),
concat!("vld", "1q_"),
concat!("vst", "1q_"),
"is_x86_feature_detected!",
"core::arch::",
];
patterns.iter().any(|p| content.contains(p))
}
fn count_functions(content: &str, category: &FileCategory) -> usize {
match category {
FileCategory::RustSource | FileCategory::SimdAvx => {
content.matches("fn ").count()
}
FileCategory::CudaKernel => {
content.matches("__global__").count() + content.matches("__device__").count()
}
FileCategory::PythonSource => content.matches("def ").count(),
FileCategory::TypeScriptSource => {
content.matches("function ").count() + content.matches("=> {").count()
}
FileCategory::GoSource => content.matches("func ").count(),
FileCategory::LeanSource => {
content.matches("def ").count()
+ content.matches("theorem ").count()
+ content.matches("lemma ").count()
}
_ => 0,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum FileCategory {
RustSource,
CudaKernel,
SimdAvx,
CSource,
PythonSource,
TypeScriptSource,
GoSource,
LeanSource,
TestCode,
BuildScript,
Generated,
}