mod symbol_counter;
pub use symbol_counter::SymbolCounter;
use serde::{Deserialize, Serialize};
use std::str::FromStr;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct SymbolId(pub u32);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct FileId(pub u32);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IndexingResult {
Indexed(FileId),
Cached(FileId),
}
impl IndexingResult {
pub fn file_id(&self) -> FileId {
match self {
IndexingResult::Indexed(id) => *id,
IndexingResult::Cached(id) => *id,
}
}
pub fn is_cached(&self) -> bool {
matches!(self, IndexingResult::Cached(_))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Range {
pub start_line: u32,
pub start_column: u16,
pub end_line: u32,
pub end_column: u16,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum SymbolKind {
Function,
Method,
Struct,
Enum,
Trait,
Interface,
Class,
Module,
Variable,
Constant,
Field,
Parameter,
TypeAlias,
Macro,
}
impl SymbolId {
pub fn new(value: u32) -> Option<Self> {
if value == 0 { None } else { Some(Self(value)) }
}
pub fn value(&self) -> u32 {
self.0
}
pub fn to_u32(self) -> u32 {
self.0
}
}
impl FileId {
pub fn new(value: u32) -> Option<Self> {
if value == 0 { None } else { Some(Self(value)) }
}
pub fn value(&self) -> u32 {
self.0
}
pub fn to_u32(self) -> u32 {
self.0
}
}
impl Range {
pub fn new(start_line: u32, start_column: u16, end_line: u32, end_column: u16) -> Self {
Self {
start_line,
start_column,
end_line,
end_column,
}
}
pub fn contains(&self, line: u32, column: u16) -> bool {
if line < self.start_line || line > self.end_line {
return false;
}
if line == self.start_line && column < self.start_column {
return false;
}
if line == self.end_line && column > self.end_column {
return false;
}
true
}
}
impl FromStr for SymbolKind {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Function" => Ok(SymbolKind::Function),
"Method" => Ok(SymbolKind::Method),
"Struct" => Ok(SymbolKind::Struct),
"Enum" => Ok(SymbolKind::Enum),
"Trait" => Ok(SymbolKind::Trait),
"Interface" => Ok(SymbolKind::Interface),
"Class" => Ok(SymbolKind::Class),
"Module" => Ok(SymbolKind::Module),
"Variable" => Ok(SymbolKind::Variable),
"Constant" => Ok(SymbolKind::Constant),
"Field" => Ok(SymbolKind::Field),
"Parameter" => Ok(SymbolKind::Parameter),
"TypeAlias" => Ok(SymbolKind::TypeAlias),
"Macro" => Ok(SymbolKind::Macro),
_ => Err("Unknown symbol kind"),
}
}
}
impl SymbolKind {
pub fn from_str_with_default(s: &str) -> Self {
s.parse().unwrap_or(SymbolKind::Function)
}
}
pub type CompactString = Box<str>;
pub fn compact_string(s: &str) -> CompactString {
s.into()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_symbol_id_creation() {
assert!(SymbolId::new(0).is_none());
let id = SymbolId::new(42).unwrap();
assert_eq!(id.value(), 42);
}
#[test]
fn test_file_id_creation() {
assert!(FileId::new(0).is_none());
let id = FileId::new(100).unwrap();
assert_eq!(id.value(), 100);
}
#[test]
fn test_range_creation() {
let range = Range::new(10, 5, 15, 20);
assert_eq!(range.start_line, 10);
assert_eq!(range.start_column, 5);
assert_eq!(range.end_line, 15);
assert_eq!(range.end_column, 20);
}
#[test]
fn test_range_contains() {
let range = Range::new(10, 5, 15, 20);
assert!(range.contains(12, 10));
assert!(range.contains(10, 5)); assert!(range.contains(15, 20));
assert!(!range.contains(9, 10)); assert!(!range.contains(16, 10)); assert!(!range.contains(10, 4)); assert!(!range.contains(15, 21)); }
#[test]
fn test_symbol_kind_variants() {
let kinds = [
SymbolKind::Function,
SymbolKind::Method,
SymbolKind::Struct,
SymbolKind::Enum,
SymbolKind::Trait,
SymbolKind::Interface,
SymbolKind::Class,
SymbolKind::Module,
SymbolKind::Variable,
SymbolKind::Constant,
SymbolKind::Field,
SymbolKind::Parameter,
SymbolKind::TypeAlias,
SymbolKind::Macro,
];
assert_eq!(kinds.len(), 14);
}
#[test]
fn test_compact_string() {
let s = compact_string("hello world");
assert_eq!(&*s, "hello world");
}
#[test]
fn test_id_equality_and_hash() {
let id1 = SymbolId::new(42).unwrap();
let id2 = SymbolId::new(42).unwrap();
let id3 = SymbolId::new(43).unwrap();
assert_eq!(id1, id2);
assert_ne!(id1, id3);
use std::collections::HashSet;
let mut set = HashSet::new();
set.insert(id1);
assert!(set.contains(&id2));
assert!(!set.contains(&id3));
}
}