use std::fmt::Write as _;
use std::sync::OnceLock;
use crate::agentic_coding::self_ast::ast_census;
use crate::engine::stable_id;
include!(concat!(env!("OUT_DIR"), "/owned_source_files.rs"));
#[must_use]
pub const fn owned_source_files() -> &'static [(&'static str, &'static str)] {
OWNED_SOURCE_FILES
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SourceModuleDigest {
pub path: String,
pub byte_len: usize,
pub content_id: String,
}
impl SourceModuleDigest {
#[must_use]
pub fn of(path: impl Into<String>, source: &str) -> Self {
Self {
path: path.into(),
byte_len: source.len(),
content_id: stable_id("source_module", source),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SourceModuleProjection {
pub path: String,
pub byte_len: usize,
pub content_id: String,
pub total_link_count: usize,
pub named_node_count: usize,
pub faithful: bool,
}
impl SourceModuleProjection {
#[must_use]
pub fn project(path: impl Into<String>, source: &str) -> Self {
let census = ast_census(source);
Self {
path: path.into(),
byte_len: source.len(),
content_id: stable_id("source_module", source),
total_link_count: census.total_link_count,
named_node_count: census.named_node_count,
faithful: census.text_preserved,
}
}
#[must_use]
pub fn digest(&self) -> SourceModuleDigest {
SourceModuleDigest {
path: self.path.clone(),
byte_len: self.byte_len,
content_id: self.content_id.clone(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SourceGraph {
pub modules: Vec<SourceModuleProjection>,
}
impl SourceGraph {
#[must_use]
pub fn compile(files: &[(&str, &str)]) -> Self {
let modules = files
.iter()
.map(|(path, source)| SourceModuleProjection::project(*path, source))
.collect();
Self { modules }
}
#[must_use]
pub fn owned() -> &'static Self {
static GRAPH: OnceLock<SourceGraph> = OnceLock::new();
GRAPH.get_or_init(|| Self::compile(OWNED_SOURCE_FILES))
}
#[must_use]
pub const fn module_count(&self) -> usize {
self.modules.len()
}
#[must_use]
pub fn faithful_count(&self) -> usize {
self.modules.iter().filter(|module| module.faithful).count()
}
#[must_use]
pub fn is_fully_faithful(&self) -> bool {
!self.modules.is_empty() && self.faithful_count() == self.modules.len()
}
#[must_use]
pub fn coverage_permille(&self) -> u32 {
if self.modules.is_empty() {
return 0;
}
let faithful = self.faithful_count() as u64;
let total = self.modules.len() as u64;
u32::try_from(faithful * 1000 / total).unwrap_or(0)
}
#[must_use]
pub fn unfaithful_modules(&self) -> Vec<&SourceModuleProjection> {
self.modules
.iter()
.filter(|module| !module.faithful)
.collect()
}
#[must_use]
pub fn total_link_count(&self) -> usize {
self.modules.iter().map(|m| m.total_link_count).sum()
}
#[must_use]
pub fn total_named_node_count(&self) -> usize {
self.modules.iter().map(|m| m.named_node_count).sum()
}
#[must_use]
pub fn total_byte_len(&self) -> usize {
self.modules.iter().map(|m| m.byte_len).sum()
}
#[must_use]
pub fn summary(&self) -> String {
format!(
"Projected {faithful}/{total} owned source modules losslessly through the meta-language \
links network ({permille}‰ round-trip coverage, {nodes} named AST nodes).",
faithful = self.faithful_count(),
total = self.module_count(),
permille = self.coverage_permille(),
nodes = self.total_named_node_count(),
)
}
#[must_use]
pub fn links_notation(&self) -> String {
let mut out = String::from("source_graph\n");
let _ = writeln!(out, " engine meta_language");
let _ = writeln!(out, " language rust");
let _ = writeln!(out, " module_count {}", self.module_count());
let _ = writeln!(out, " faithful_count {}", self.faithful_count());
let _ = writeln!(out, " coverage_permille {}", self.coverage_permille());
let _ = writeln!(out, " fully_faithful {}", self.is_fully_faithful());
let _ = writeln!(out, " total_link_count {}", self.total_link_count());
let _ = writeln!(
out,
" total_named_node_count {}",
self.total_named_node_count()
);
let _ = writeln!(out, " modules");
for module in &self.modules {
let _ = writeln!(out, " module");
let _ = writeln!(out, " path \"{}\"", quote(&module.path));
let _ = writeln!(out, " byte_len {}", module.byte_len);
let _ = writeln!(out, " content_id \"{}\"", quote(&module.content_id));
let _ = writeln!(out, " total_link_count {}", module.total_link_count);
let _ = writeln!(out, " named_node_count {}", module.named_node_count);
let _ = writeln!(out, " faithful {}", module.faithful);
}
out.trim_end().to_owned()
}
}
#[must_use]
pub fn owned_manifest() -> Vec<SourceModuleDigest> {
OWNED_SOURCE_FILES
.iter()
.map(|(path, source)| SourceModuleDigest::of(*path, source))
.collect()
}
#[must_use]
pub const fn owned_file_count() -> usize {
OWNED_SOURCE_FILES.len()
}
#[must_use]
pub fn owned_total_bytes() -> usize {
OWNED_SOURCE_FILES
.iter()
.map(|(_, source)| source.len())
.sum()
}
#[must_use]
pub fn owned_manifest_content_id() -> String {
stable_id("source_tree", &owned_manifest_notation())
}
#[must_use]
pub fn owned_manifest_notation() -> String {
let manifest = owned_manifest();
let mut out = String::from("source_manifest\n");
let _ = writeln!(out, " engine meta_language");
let _ = writeln!(out, " language rust");
let _ = writeln!(out, " file_count {}", manifest.len());
let _ = writeln!(out, " total_bytes {}", owned_total_bytes());
let _ = writeln!(out, " files");
for digest in &manifest {
let _ = writeln!(out, " file");
let _ = writeln!(out, " path \"{}\"", quote(&digest.path));
let _ = writeln!(out, " byte_len {}", digest.byte_len);
let _ = writeln!(out, " content_id \"{}\"", quote(&digest.content_id));
}
out.trim_end().to_owned()
}
fn quote(value: &str) -> String {
value
.replace('\\', "\\\\")
.replace('"', "'")
.replace('\n', "\\n")
.replace('\r', "\\r")
.replace('\t', "\\t")
}