use serde::{Deserialize, Serialize};
use crate::flow::Flow;
use crate::hash::Fingerprint;
use crate::path::SourcePath;
use crate::sym::{Descriptor, SymbolId};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SymbolKind {
Module,
Struct,
Enum,
Union,
Trait,
TypeAlias,
Function,
Method,
Const,
Static,
Macro,
}
impl SymbolKind {
pub fn is_type(self) -> bool {
matches!(self, Self::Struct | Self::Enum | Self::Union | Self::Trait | Self::TypeAlias)
}
pub fn is_callable(self) -> bool {
matches!(self, Self::Function | Self::Method)
}
pub fn descriptor(self, name: impl Into<String>) -> Descriptor {
match self {
Self::Module => Descriptor::namespace(name),
Self::Struct | Self::Enum | Self::Union | Self::Trait | Self::TypeAlias => Descriptor::r#type(name),
Self::Function | Self::Method => Descriptor::method(name),
Self::Const | Self::Static => Descriptor::term(name),
Self::Macro => Descriptor::r#macro(name),
}
}
pub fn keyword(self) -> &'static str {
match self {
Self::Module => "mod",
Self::Struct => "struct",
Self::Enum => "enum",
Self::Union => "union",
Self::Trait => "trait",
Self::TypeAlias => "type",
Self::Function => "fn",
Self::Method => "method",
Self::Const => "const",
Self::Static => "static",
Self::Macro => "macro",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Visibility {
Public,
Crate,
Restricted(String),
Private,
}
impl Visibility {
pub fn uml_marker(&self) -> char {
match self {
Self::Public => '+',
Self::Crate => '~',
Self::Restricted(_) => '#',
Self::Private => '-',
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize)]
pub struct Span {
pub start_line: u32,
pub start_col: u32,
pub end_line: u32,
pub end_col: u32,
}
impl Span {
pub fn new(start_line: u32, start_col: u32, end_line: u32, end_col: u32) -> Self {
Self { start_line, start_col, end_line, end_col }
}
pub fn compact(&self) -> String {
if self.start_line == self.end_line {
format!("L{}", self.start_line)
} else {
format!("L{}-L{}", self.start_line, self.end_line)
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum MemberKind {
Field,
Variant,
AssocConst,
AssocType,
RequiredMethod,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Member {
pub name: String,
pub kind: MemberKind,
pub ty: Option<String>,
pub visibility: Visibility,
pub span: Span,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub refs: Vec<SymbolId>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Symbol {
pub id: SymbolId,
pub name: String,
pub kind: SymbolKind,
pub visibility: Visibility,
pub file: SourcePath,
pub span: Span,
pub sig_hash: Fingerprint,
pub body_hash: Fingerprint,
pub parent: Option<SymbolId>,
pub signature: Option<String>,
pub doc: Option<String>,
pub generics: Vec<String>,
pub tags: Vec<String>,
pub members: Vec<Member>,
pub flow: Option<Flow>,
}
impl Symbol {
pub fn new(id: SymbolId, name: impl Into<String>, kind: SymbolKind, file: SourcePath) -> Self {
Self {
parent: id.parent(),
id,
name: name.into(),
kind,
visibility: Visibility::Private,
file,
span: Span::default(),
sig_hash: Fingerprint::default(),
body_hash: Fingerprint::default(),
signature: None,
doc: None,
generics: Vec::new(),
tags: Vec::new(),
members: Vec::new(),
flow: None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RelationKind {
Contains,
Implements,
Extends,
FieldType,
Uses,
Imports,
Calls,
}
impl RelationKind {
pub fn label(self) -> &'static str {
match self {
Self::Contains => "contains",
Self::Implements => "implements",
Self::Extends => "extends",
Self::FieldType => "field",
Self::Uses => "uses",
Self::Imports => "imports",
Self::Calls => "calls",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Confidence {
Exact,
Inferred,
External,
}
impl Confidence {
pub fn marker(self) -> char {
match self {
Self::Exact => '=',
Self::Inferred => '~',
Self::External => '?',
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Relation {
pub from: SymbolId,
pub to: SymbolId,
pub kind: RelationKind,
pub confidence: Confidence,
}
impl Relation {
pub fn new(from: SymbolId, to: SymbolId, kind: RelationKind, confidence: Confidence) -> Self {
Self { from, to, kind, confidence }
}
}
pub const PARSE_ERROR_TAG: &str = "parse_error";
impl Symbol {
pub fn is_unparsable(&self) -> bool {
self.tags.iter().any(|t| t == PARSE_ERROR_TAG)
}
}