1use std::collections::BTreeMap;
4
5use sealmap_model::{Codebase, CodebaseStats, Confidence, ContentHash, Fingerprint, SourcePath, Span, SymbolId};
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case")]
11pub enum FragmentKind {
12 Structure,
14 Sequence,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
20pub struct CallRef {
21 pub target: SymbolId,
23 pub confidence: Confidence,
25 pub line: u32,
27 #[serde(skip_serializing_if = "Option::is_none")]
31 pub expands: Option<String>,
32}
33
34#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
36pub struct FragmentEntry {
37 pub id: String,
40 pub kind: FragmentKind,
42 pub document: SourcePath,
44 pub symbol: SymbolId,
46 pub span: Span,
48 pub sig_hash: Fingerprint,
50 pub body_hash: Fingerprint,
52 pub participants: Vec<SymbolId>,
54 #[serde(default, skip_serializing_if = "Vec::is_empty")]
56 pub calls: Vec<CallRef>,
57 #[serde(default, skip_serializing_if = "is_zero")]
59 pub truncated: usize,
60 pub hash: ContentHash,
62}
63
64fn is_zero(n: &usize) -> bool {
65 *n == 0
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
70pub struct DocumentEntry {
71 pub source: SourcePath,
73 pub document: SourcePath,
75 pub module: SymbolId,
77 pub source_hash: ContentHash,
79 pub document_hash: ContentHash,
81 pub fragments: Vec<FragmentEntry>,
83}
84
85#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
87pub struct Index {
88 pub schema_version: u32,
90 pub generator: String,
92 pub codebase: String,
94 pub stats: CodebaseStats,
96 pub documents: Vec<DocumentEntry>,
98}
99
100impl Index {
101 pub(crate) fn new(cb: &Codebase) -> Self {
102 Self {
103 schema_version: crate::CORPUS_SCHEMA_VERSION,
104 generator: format!("sealmap-corpus {}", env!("CARGO_PKG_VERSION")),
105 codebase: cb.name.clone(),
106 stats: cb.stats(),
107 documents: Vec::new(),
108 }
109 }
110
111 pub(crate) fn link_expansions(&mut self) {
113 let seqs: BTreeMap<String, ()> =
114 self.fragments().filter(|f| f.kind == FragmentKind::Sequence).map(|f| (f.id.clone(), ())).collect();
115 for doc in &mut self.documents {
116 for frag in &mut doc.fragments {
117 for call in &mut frag.calls {
118 let target = call.target.to_string();
119 if seqs.contains_key(&target) {
120 call.expands = Some(target);
121 }
122 }
123 }
124 }
125 }
126
127 pub fn fragments(&self) -> impl Iterator<Item = &FragmentEntry> {
129 self.documents.iter().flat_map(|d| d.fragments.iter())
130 }
131
132 pub fn fragment(&self, id: &str) -> Option<&FragmentEntry> {
134 self.fragments().find(|f| f.id == id)
135 }
136}