1#[derive(
3 Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
4)]
5pub struct SymbolId {
6 pub kind: SymbolKind,
7 pub path: Vec<String>,
8 pub disambiguator: u32,
9}
10
11#[derive(
12 Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
13)]
14pub enum SymbolKind {
15 Struct,
16 Enum,
17 TypeAlias,
18 Endpoint,
19 Variant,
20 Field,
21 Primitive,
22}
23
24pub const STDLIB_TYPES: &[(&str, SymbolKind)] = &[
27 ("std::option::Option", SymbolKind::Enum),
28 ("std::vec::Vec", SymbolKind::Primitive),
29 ("std::collections::HashMap", SymbolKind::Primitive),
30 ("std::collections::BTreeMap", SymbolKind::Primitive),
31 ("std::string::String", SymbolKind::Primitive),
32 ("std::tuple::Tuple0", SymbolKind::Primitive),
33 ("std::boxed::Box", SymbolKind::Primitive),
34 ("std::rc::Rc", SymbolKind::Primitive),
35 ("std::sync::Arc", SymbolKind::Primitive),
36 ("i32", SymbolKind::Primitive),
37 ("u32", SymbolKind::Primitive),
38 ("i64", SymbolKind::Primitive),
39 ("u64", SymbolKind::Primitive),
40 ("f32", SymbolKind::Primitive),
41 ("f64", SymbolKind::Primitive),
42 ("bool", SymbolKind::Primitive),
43 ("u8", SymbolKind::Primitive),
44 ("i8", SymbolKind::Primitive),
45 ("chrono::Utc", SymbolKind::Primitive),
46 ("chrono::FixedOffset", SymbolKind::Primitive),
47 ("chrono::DateTime", SymbolKind::Primitive),
48 ("uuid::Uuid", SymbolKind::Primitive),
49 ("url::Url", SymbolKind::Primitive),
50 ("serde_json::Value", SymbolKind::Primitive),
51];
52
53pub const STDLIB_TYPE_PREFIXES: &[&str] = &["std::", "chrono::", "uuid::"];
57
58impl Default for SymbolId {
59 fn default() -> Self {
60 Self {
61 kind: SymbolKind::Struct,
62 path: vec!["unknown".to_string()],
63 disambiguator: 0,
64 }
65 }
66}
67
68impl SymbolId {
69 pub fn new(kind: SymbolKind, path: Vec<String>) -> Self {
71 Self {
72 kind,
73 path,
74 disambiguator: 0,
75 }
76 }
77
78 pub fn with_disambiguator(kind: SymbolKind, path: Vec<String>, disambiguator: u32) -> Self {
80 Self {
81 kind,
82 path,
83 disambiguator,
84 }
85 }
86
87 pub fn is_unknown(&self) -> bool {
89 self.path.len() == 1 && self.path[0] == "unknown"
90 }
91
92 pub fn struct_id(path: Vec<String>) -> Self {
94 Self::new(SymbolKind::Struct, path)
95 }
96
97 pub fn enum_id(path: Vec<String>) -> Self {
99 Self::new(SymbolKind::Enum, path)
100 }
101
102 pub fn endpoint_id(path: Vec<String>) -> Self {
104 Self::new(SymbolKind::Endpoint, path)
105 }
106
107 pub fn variant_id(enum_path: Vec<String>, variant_name: String) -> Self {
109 let mut path = enum_path;
110 path.push(variant_name);
111 Self::new(SymbolKind::Variant, path)
112 }
113
114 pub fn field_id(parent_path: Vec<String>, field_name: String) -> Self {
116 let mut path = parent_path;
117 path.push(field_name);
118 Self::new(SymbolKind::Field, path)
119 }
120
121 pub fn name(&self) -> Option<&str> {
123 self.path.last().map(|s| s.as_str())
124 }
125
126 pub fn qualified_name(&self) -> String {
128 self.path.join("::")
129 }
130
131 pub fn same_symbol(&self, other: &SymbolId) -> bool {
133 self.kind == other.kind && self.path == other.path
134 }
135}
136
137impl std::fmt::Display for SymbolId {
138 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139 write!(f, "{:?}({})", self.kind, self.qualified_name())?;
140 if self.disambiguator > 0 {
141 write!(f, "#{}", self.disambiguator)?;
142 }
143 Ok(())
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn test_symbol_id_creation() {
153 let struct_id = SymbolId::struct_id(vec!["api".to_string(), "User".to_string()]);
154 assert_eq!(struct_id.kind, SymbolKind::Struct);
155 assert_eq!(struct_id.path, vec!["api", "User"]);
156 assert_eq!(struct_id.disambiguator, 0);
157 assert_eq!(struct_id.name(), Some("User"));
158 assert_eq!(struct_id.qualified_name(), "api::User");
159 }
160
161 #[test]
162 fn test_symbol_id_display() {
163 let struct_id = SymbolId::struct_id(vec!["api".to_string(), "User".to_string()]);
164 assert_eq!(format!("{struct_id}"), "Struct(api::User)");
165
166 let disambiguated = SymbolId::with_disambiguator(
167 SymbolKind::Struct,
168 vec!["api".to_string(), "User".to_string()],
169 1,
170 );
171 assert_eq!(format!("{disambiguated}"), "Struct(api::User)#1");
172 }
173
174 #[test]
175 fn test_same_symbol() {
176 let id1 = SymbolId::struct_id(vec!["api".to_string(), "User".to_string()]);
177 let id2 = SymbolId::with_disambiguator(
178 SymbolKind::Struct,
179 vec!["api".to_string(), "User".to_string()],
180 1,
181 );
182 assert!(id1.same_symbol(&id2));
183 }
184}