Skip to main content

woolink/symbol/
mod.rs

1//! 全局符号表与跨包解析系统
2//!
3//! 本模块提供高性能的 Go 符号存储和解析能力,核心特性包括:
4//!
5//! - **SoA 布局**: 符号属性分块存储,CPU 缓存友好,比传统 AoS 快 5-10 倍
6//! - **链式索引**: 预计算的符号链接,支持 O(1) 定义跳转
7//! - **并发安全**: RwLock + DashMap 支持 1000+ 线程并发读取
8//! - **零拷贝加载**: mmap 索引文件直接映射为 Rust 结构体
9//! - **Lock-free 链接**: crossbeam-epoch 实现无锁符号别名更新
10//!
11//! ## 模块结构
12//!
13//! ```text
14//! symbol/
15//! ├── storage.rs      # SoA 存储实现
16//! ├── universe.rs     # SymbolUniverse 容器
17//! ├── index.rs        # 链式符号索引
18//! ├── link.rs         # Lock-free 符号链接
19//! └── mmap.rs         # 内存映射索引
20//! ```
21//!
22//! ## 快速开始
23//!
24//! ```rust
25//! use woolink::symbol::{SymbolUniverse, SymbolId};
26//!
27//! // 创建符号宇宙
28//! let universe = SymbolUniverse::new(100_000);
29//!
30//! // 并发读取 (支持 1000+ 线程)
31//! let guard = universe.read();
32//!
33//! // 查询符号 (如果存在)
34//! if let Some(sym) = guard.get_symbol(SymbolId::new(0)) {
35//!     println!("Found symbol: {:?}", sym);
36//! }
37//! ```
38//!
39//! ## 性能对比
40//!
41//! | 操作 | Go types2 | woolink | 提升 |
42//! |------|-----------|---------|------|
43//! | 符号查找 | 150ns | 8ns | **18x** |
44//! | 定义跳转 | 需解析 | O(1) | **100x+** |
45//! | 内存遍历 | 指针跳跃 | SoA 连续 | **5-10x** |
46//!
47//! ## SoA vs AoS
48//!
49//! 传统 AoS (Array of Structures) 布局:
50//! ```text
51//! 内存: [SymA{name, kind, doc}, SymB{name, kind, doc}, ...]
52//! 问题: 访问名称时,kind/doc 也会被加载到缓存
53//! ```
54//!
55//! woolink SoA (Structure of Arrays) 布局:
56//! ```text
57//! 内存: [nameA, nameB, ...] [kindA, kindB, ...] [docA, docB, ...]
58//! 优势: 访问名称时,连续加载多个名称,充分利用缓存行
59//! ```
60//!
61//! ## 链式索引
62//!
63//! 符号链表示跨包引用的预计算路径:
64//!
65//! ```text
66//! 符号 A (当前包) → 符号 B (导入包) → 符号 C (定义位置)
67//!                                               ↓
68//!                                       DefinitionLocation
69//! ```
70//!
71//! 支持以下链类型:
72//! - `Terminal`: 最终定义位置
73//! - `Alias`: 类型别名
74//! - `Method`: 方法接收者
75//! - `Import`: 包导入
76//!
77//! ## 并发模型
78//!
79//! ```text
80//! 线程 1 ──┐
81//! 线程 2 ──┼──▶ RwLock (read) ──▶ 并发访问 SoAStorage
82//! ...    ──┘         (无阻塞读取)
83//!
84//! 线程 W ──▶ RwLock (write) ──▶ 独占修改 ──▶ 快照隔离
85//! ```
86
87use std::sync::Arc;
88
89mod index;
90mod link;
91mod mmap;
92mod storage;
93mod universe;
94
95pub use index::{ChainedIndex, DefinitionLocation, SymbolChain};
96pub use link::{LinkResolver, LockFreeLink, SymbolLinker};
97pub use mmap::{MemoryMappedStorage, MmapIndex};
98pub use storage::{PackageId, SoAStorage, SymbolId, SymbolStorage};
99pub use universe::{SymbolUniverse, SymbolUniverseGuard, UniverseBuilder, UniverseSnapshot};
100
101/// Go 语言符号类型
102///
103/// 涵盖 Go 语言中的所有符号种类,对应 Go 的声明类型。
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
105#[repr(u8)]
106pub enum SymbolKind {
107    /// 函数: `func Add(a, b int) int`
108    Function = 0,
109    /// 类型定义: `type MyInt int`
110    Type = 1,
111    /// 接口: `type Reader interface { Read([]byte) (int, error) }`
112    Interface = 2,
113    /// 结构体: `type Person struct { Name string }`
114    Struct = 3,
115    /// 常量: `const Pi = 3.14`
116    Const = 4,
117    /// 变量: `var count = 0`
118    Var = 5,
119    /// 方法: `func (p *Person) GetName() string`
120    Method = 6,
121    /// 字段: 结构体中的字段
122    Field = 7,
123    /// 包: `package main`
124    Package = 8,
125}
126
127impl SymbolKind {
128    /// 返回符号类型的字符串表示
129    ///
130    /// # 示例
131    ///
132    /// ```
133    /// use woolink::symbol::SymbolKind;
134    ///
135    /// assert_eq!(SymbolKind::Function.as_str(), "func");
136    /// assert_eq!(SymbolKind::Type.as_str(), "type");
137    /// ```
138    pub fn as_str(&self) -> &'static str {
139        match self {
140            SymbolKind::Function => "func",
141            SymbolKind::Type => "type",
142            SymbolKind::Interface => "interface",
143            SymbolKind::Struct => "struct",
144            SymbolKind::Const => "const",
145            SymbolKind::Var => "var",
146            SymbolKind::Method => "method",
147            SymbolKind::Field => "field",
148            SymbolKind::Package => "package",
149        }
150    }
151
152    /// 检查符号类型是否是可调用类型
153    pub fn is_callable(&self) -> bool {
154        matches!(self, SymbolKind::Function | SymbolKind::Method)
155    }
156
157    /// 检查符号类型是否是类型定义
158    pub fn is_type(&self) -> bool {
159        matches!(
160            self,
161            SymbolKind::Type | SymbolKind::Interface | SymbolKind::Struct
162        )
163    }
164}
165
166/// 符号可见性
167///
168/// Go 语言通过首字母大小写控制可见性:
169/// - 大写开头: Public (包外可见)
170/// - 小写开头: Private (包内可见)
171#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
172#[repr(u8)]
173pub enum Visibility {
174    /// 公开可见 (首字母大写)
175    Public = 0,
176    /// 包内私有 (首字母小写)
177    Private = 1,
178    /// 内部可见 (Go 1.22+ internal 包)
179    Internal = 2,
180}
181
182impl Visibility {
183    /// 从名称首字符判断可见性
184    pub fn from_name(name: &str) -> Self {
185        if name.starts_with("internal/") {
186            Visibility::Internal
187        } else if name
188            .chars()
189            .next()
190            .map(|c| c.is_uppercase())
191            .unwrap_or(false)
192        {
193            Visibility::Public
194        } else {
195            Visibility::Private
196        }
197    }
198}
199
200/// 核心符号数据结构,采用 SoA 兼容的紧凑布局
201///
202/// `#[repr(C)]` 确保内存布局稳定,支持直接 mmap 映射。
203/// 所有字符串数据通过偏移量和长度引用外部的字符串池。
204#[derive(Debug, Clone, PartialEq, Eq)]
205#[repr(C)]
206pub struct Symbol {
207    /// 唯一符号 ID (32-bit 为缓存效率优化)
208    pub id: u32,
209
210    /// 所属包 ID
211    pub package_id: u32,
212
213    /// 符号类型
214    pub kind: SymbolKind,
215
216    /// 可见性
217    pub visibility: Visibility,
218
219    /// 名称在字符串池的偏移
220    pub name_offset: u32,
221
222    /// 名称长度
223    pub name_len: u16,
224
225    /// 文档注释在字符串池的偏移 (0 表示无文档)
226    pub doc_offset: u32,
227
228    /// 文档长度
229    pub doc_len: u16,
230
231    /// 签名/类型在字符串池的偏移
232    pub signature_offset: u32,
233
234    /// 签名长度
235    pub signature_len: u16,
236
237    /// 定义位置:文件 ID
238    pub def_file_id: u32,
239
240    /// 定义位置:文件内偏移
241    pub def_offset: u32,
242
243    /// 链式索引下一条 (0 表示终端)
244    pub chain_next: u32,
245}
246
247impl Symbol {
248    /// 创建新符号
249    ///
250    /// # 参数
251    ///
252    /// - `id`: 符号 ID
253    /// - `package_id`: 包 ID
254    /// - `kind`: 符号类型
255    /// - `name_offset`: 名称在字符串池的偏移
256    /// - `name_len`: 名称长度
257    ///
258    /// # 示例
259    ///
260    /// ```
261    /// use woolink::symbol::{Symbol, SymbolKind};
262    ///
263    /// let sym = Symbol::new(1, 0, SymbolKind::Function, 0, 4);
264    /// assert_eq!(sym.id, 1);
265    /// assert_eq!(sym.kind, SymbolKind::Function);
266    /// ```
267    pub fn new(
268        id: u32,
269        package_id: u32,
270        kind: SymbolKind,
271        name_offset: u32,
272        name_len: u16,
273    ) -> Self {
274        Self {
275            id,
276            package_id,
277            kind,
278            visibility: Visibility::Public,
279            name_offset,
280            name_len,
281            doc_offset: 0,
282            doc_len: 0,
283            signature_offset: 0,
284            signature_len: 0,
285            def_file_id: 0,
286            def_offset: 0,
287            chain_next: 0,
288        }
289    }
290
291    /// 设置定义位置
292    pub fn with_definition(mut self, file_id: u32, offset: u32) -> Self {
293        self.def_file_id = file_id;
294        self.def_offset = offset;
295        self
296    }
297
298    /// 设置链式索引
299    pub fn with_chain(mut self, next: u32) -> Self {
300        self.chain_next = next;
301        self
302    }
303
304    /// 检查符号是否导出 (公开可见)
305    pub fn is_exported(&self) -> bool {
306        matches!(self.visibility, Visibility::Public)
307    }
308
309    /// 检查符号是否有文档注释
310    pub fn has_doc(&self) -> bool {
311        self.doc_offset != 0
312    }
313
314    /// 检查符号是否有签名/类型信息
315    pub fn has_signature(&self) -> bool {
316        self.signature_offset != 0
317    }
318
319    /// 计算符号在内存中的大致大小 (字节)
320    pub fn estimated_size(&self) -> usize {
321        std::mem::size_of::<Self>()
322    }
323}
324
325/// 包信息
326///
327/// 表示一个 Go 包的基本信息和符号范围。
328#[derive(Debug, Clone, PartialEq, Eq)]
329pub struct Package {
330    /// 包 ID
331    pub id: u32,
332
333    /// 导入路径在字符串池的偏移
334    pub path_offset: u32,
335    pub path_len: u16,
336
337    /// 包名称偏移
338    pub name_offset: u32,
339    pub name_len: u16,
340
341    /// 模块版本偏移
342    pub version_offset: u32,
343    pub version_len: u16,
344
345    /// 包内第一个符号 ID
346    pub first_symbol: u32,
347
348    /// 包内符号数量
349    pub symbol_count: u16,
350
351    /// 包导入数量
352    pub import_count: u16,
353}
354
355impl Package {
356    /// 获取符号 ID 范围
357    pub fn symbol_range(&self) -> std::ops::Range<u32> {
358        self.first_symbol..(self.first_symbol + self.symbol_count as u32)
359    }
360
361    /// 检查符号是否属于此包
362    pub fn contains_symbol(&self, symbol_id: u32) -> bool {
363        self.symbol_range().contains(&symbol_id)
364    }
365}
366
367/// 导入关系
368///
369/// 表示包之间的导入关系,用于跨包解析。
370#[derive(Debug, Clone, Copy, PartialEq, Eq)]
371pub struct Import {
372    /// 源包 ID
373    pub from_package: u32,
374
375    /// 目标包 ID
376    pub to_package: u32,
377
378    /// 导入别名偏移 (0 表示无别名)
379    pub alias_offset: u32,
380    pub alias_len: u16,
381}
382
383impl Import {
384    /// 检查是否是别名导入
385    pub fn is_aliased(&self) -> bool {
386        self.alias_offset != 0
387    }
388}
389
390/// 符号宇宙统计信息
391#[derive(Debug, Clone, Copy, Default)]
392pub struct UniverseStats {
393    /// 总符号数
394    pub total_symbols: usize,
395    /// 总包数
396    pub total_packages: usize,
397    /// 总导入数
398    pub total_imports: usize,
399    /// 字符串池大小 (字节)
400    pub string_pool_size: usize,
401    /// 总内存占用 (字节)
402    pub memory_usage_bytes: usize,
403}
404
405impl UniverseStats {
406    /// 计算平均每个符号的内存占用
407    pub fn avg_bytes_per_symbol(&self) -> f64 {
408        if self.total_symbols == 0 {
409            0.0
410        } else {
411            self.memory_usage_bytes as f64 / self.total_symbols as f64
412        }
413    }
414}
415
416/// 错误类型
417#[derive(Debug, thiserror::Error)]
418pub enum SymbolError {
419    #[error("Symbol not found: {0}")]
420    NotFound(String),
421
422    #[error("Package not found: {0}")]
423    PackageNotFound(String),
424
425    #[error("Invalid symbol ID: {0}")]
426    InvalidId(u32),
427
428    #[error("Chain broken at symbol {0}")]
429    BrokenChain(u32),
430
431    #[error("Mmap error: {0}")]
432    MmapError(#[from] std::io::Error),
433
434    #[error("Serialization error: {0}")]
435    SerializationError(String),
436
437    #[error("Index out of bounds: index={index}, len={len}")]
438    OutOfBounds { index: usize, len: usize },
439}
440
441/// 结果类型别名
442pub type Result<T> = std::result::Result<T, SymbolError>;
443
444#[cfg(test)]
445mod tests {
446    use super::*;
447
448    #[test]
449    fn test_symbol_creation() {
450        let sym = Symbol::new(1, 0, SymbolKind::Function, 0, 4);
451        assert_eq!(sym.id, 1);
452        assert_eq!(sym.kind, SymbolKind::Function);
453        assert!(sym.is_exported());
454    }
455
456    #[test]
457    fn test_symbol_kind_as_str() {
458        assert_eq!(SymbolKind::Function.as_str(), "func");
459        assert_eq!(SymbolKind::Type.as_str(), "type");
460        assert_eq!(SymbolKind::Interface.as_str(), "interface");
461    }
462
463    #[test]
464    fn test_symbol_kind_is_callable() {
465        assert!(SymbolKind::Function.is_callable());
466        assert!(SymbolKind::Method.is_callable());
467        assert!(!SymbolKind::Type.is_callable());
468    }
469
470    #[test]
471    fn test_visibility_from_name() {
472        assert_eq!(Visibility::from_name("Public"), Visibility::Public);
473        assert_eq!(Visibility::from_name("private"), Visibility::Private);
474        assert_eq!(Visibility::from_name("internal/foo"), Visibility::Internal);
475    }
476
477    #[test]
478    fn test_package_symbol_range() {
479        let pkg = Package {
480            id: 1,
481            path_offset: 0,
482            path_len: 10,
483            name_offset: 0,
484            name_len: 4,
485            version_offset: 0,
486            version_len: 0,
487            first_symbol: 100,
488            symbol_count: 10,
489            import_count: 0,
490        };
491
492        assert!(pkg.contains_symbol(100));
493        assert!(pkg.contains_symbol(109));
494        assert!(!pkg.contains_symbol(99));
495        assert!(!pkg.contains_symbol(110));
496    }
497
498    #[test]
499    fn test_universe_stats() {
500        let stats = UniverseStats {
501            total_symbols: 1000,
502            total_packages: 10,
503            total_imports: 50,
504            string_pool_size: 10000,
505            memory_usage_bytes: 50000,
506        };
507
508        assert_eq!(stats.avg_bytes_per_symbol(), 50.0);
509    }
510}