#[derive(
Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
)]
pub struct SymbolId {
pub kind: SymbolKind,
pub path: Vec<String>,
pub disambiguator: u32,
}
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
)]
pub enum SymbolKind {
Struct,
Enum,
TypeAlias,
Endpoint,
Variant,
Field,
Primitive,
}
pub const STDLIB_TYPES: &[(&str, SymbolKind)] = &[
("std::option::Option", SymbolKind::Enum),
("std::vec::Vec", SymbolKind::Primitive),
("std::collections::HashMap", SymbolKind::Primitive),
("std::collections::BTreeMap", SymbolKind::Primitive),
("std::string::String", SymbolKind::Primitive),
("std::tuple::Tuple0", SymbolKind::Primitive),
("std::boxed::Box", SymbolKind::Primitive),
("std::rc::Rc", SymbolKind::Primitive),
("std::sync::Arc", SymbolKind::Primitive),
("i32", SymbolKind::Primitive),
("u32", SymbolKind::Primitive),
("i64", SymbolKind::Primitive),
("u64", SymbolKind::Primitive),
("f32", SymbolKind::Primitive),
("f64", SymbolKind::Primitive),
("bool", SymbolKind::Primitive),
("u8", SymbolKind::Primitive),
("i8", SymbolKind::Primitive),
("chrono::Utc", SymbolKind::Primitive),
("chrono::FixedOffset", SymbolKind::Primitive),
("chrono::DateTime", SymbolKind::Primitive),
("uuid::Uuid", SymbolKind::Primitive),
("url::Url", SymbolKind::Primitive),
("serde_json::Value", SymbolKind::Primitive),
];
pub const STDLIB_TYPE_PREFIXES: &[&str] = &["std::", "chrono::", "uuid::"];
impl Default for SymbolId {
fn default() -> Self {
Self {
kind: SymbolKind::Struct,
path: vec!["unknown".to_string()],
disambiguator: 0,
}
}
}
impl SymbolId {
pub fn new(kind: SymbolKind, path: Vec<String>) -> Self {
Self {
kind,
path,
disambiguator: 0,
}
}
pub fn with_disambiguator(kind: SymbolKind, path: Vec<String>, disambiguator: u32) -> Self {
Self {
kind,
path,
disambiguator,
}
}
pub fn is_unknown(&self) -> bool {
self.path.len() == 1 && self.path[0] == "unknown"
}
pub fn struct_id(path: Vec<String>) -> Self {
Self::new(SymbolKind::Struct, path)
}
pub fn enum_id(path: Vec<String>) -> Self {
Self::new(SymbolKind::Enum, path)
}
pub fn endpoint_id(path: Vec<String>) -> Self {
Self::new(SymbolKind::Endpoint, path)
}
pub fn variant_id(enum_path: Vec<String>, variant_name: String) -> Self {
let mut path = enum_path;
path.push(variant_name);
Self::new(SymbolKind::Variant, path)
}
pub fn field_id(parent_path: Vec<String>, field_name: String) -> Self {
let mut path = parent_path;
path.push(field_name);
Self::new(SymbolKind::Field, path)
}
pub fn name(&self) -> Option<&str> {
self.path.last().map(|s| s.as_str())
}
pub fn qualified_name(&self) -> String {
self.path.join("::")
}
pub fn same_symbol(&self, other: &SymbolId) -> bool {
self.kind == other.kind && self.path == other.path
}
}
impl std::fmt::Display for SymbolId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}({})", self.kind, self.qualified_name())?;
if self.disambiguator > 0 {
write!(f, "#{}", self.disambiguator)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_symbol_id_creation() {
let struct_id = SymbolId::struct_id(vec!["api".to_string(), "User".to_string()]);
assert_eq!(struct_id.kind, SymbolKind::Struct);
assert_eq!(struct_id.path, vec!["api", "User"]);
assert_eq!(struct_id.disambiguator, 0);
assert_eq!(struct_id.name(), Some("User"));
assert_eq!(struct_id.qualified_name(), "api::User");
}
#[test]
fn test_symbol_id_display() {
let struct_id = SymbolId::struct_id(vec!["api".to_string(), "User".to_string()]);
assert_eq!(format!("{struct_id}"), "Struct(api::User)");
let disambiguated = SymbolId::with_disambiguator(
SymbolKind::Struct,
vec!["api".to_string(), "User".to_string()],
1,
);
assert_eq!(format!("{disambiguated}"), "Struct(api::User)#1");
}
#[test]
fn test_same_symbol() {
let id1 = SymbolId::struct_id(vec!["api".to_string(), "User".to_string()]);
let id2 = SymbolId::with_disambiguator(
SymbolKind::Struct,
vec!["api".to_string(), "User".to_string()],
1,
);
assert!(id1.same_symbol(&id2));
}
}