1use std::collections::HashMap;
7
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct Request {
17 pub id: u64,
19 pub crate_name: String,
21 pub query: Query,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27#[serde(tag = "type", rename_all = "snake_case")]
28pub enum Query {
29 ListItems,
31
32 GetType { path: String },
34
35 GetTraitImpls { type_path: String },
37
38 GetInherentImpls { type_path: String },
40
41 GetFields { type_path: String },
43
44 GetLayout { type_path: String },
46
47 GetTraits,
49
50 GetTrait { path: String },
52
53 FindTypes { pattern: String },
55
56 ResolveAlias { path: String },
58
59 CheckImpl {
61 type_path: String,
62 trait_path: String,
63 },
64
65 GetImplementors { trait_path: String },
67
68 Ping,
70
71 Shutdown,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct Response {
78 pub id: u64,
80 pub result: QueryResult,
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize)]
86#[serde(tag = "status", rename_all = "snake_case")]
87pub enum QueryResult {
88 Success { data: QueryData },
90 Error { message: String },
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
96#[serde(tag = "type", rename_all = "snake_case")]
97pub enum QueryData {
98 Items { items: Vec<ItemInfo> },
100
101 TypeInfo(TypeDetails),
103
104 TraitImpls { impls: Vec<TraitImplDetails> },
106
107 InherentImpls { impls: Vec<InherentImplDetails> },
109
110 Fields { fields: Vec<FieldInfo> },
112
113 Layout(LayoutInfo),
115
116 Traits { traits: Vec<TraitInfo> },
118
119 TraitDetails(TraitDetails),
121
122 Types { types: Vec<TypeSummary> },
124
125 ResolvedType {
127 original: String,
128 resolved: String,
129 chain: Vec<String>,
130 },
131
132 ImplCheck {
134 implements: bool,
135 impl_info: Option<TraitImplDetails>,
136 },
137
138 Implementors { types: Vec<TypeSummary> },
140
141 Pong,
143
144 ShuttingDown,
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize)]
154pub struct ItemInfo {
155 pub name: String,
157 pub path: String,
159 pub kind: ItemKind,
161 pub visibility: Visibility,
163 pub span: Option<SpanInfo>,
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
169#[serde(rename_all = "snake_case")]
170pub enum ItemKind {
171 Struct,
172 Enum,
173 Union,
174 Trait,
175 Function,
176 Const,
177 Static,
178 TypeAlias,
179 Impl,
180 Mod,
181 Use,
182 ExternCrate,
183 Macro,
184 TraitAlias,
185 Other(String),
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
190#[serde(rename_all = "snake_case")]
191pub enum Visibility {
192 Public,
193 Crate,
194 Restricted { path: String },
195 Private,
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct SpanInfo {
201 pub file: String,
202 pub start_line: u32,
203 pub start_col: u32,
204 pub end_line: u32,
205 pub end_col: u32,
206}
207
208#[derive(Debug, Clone, Serialize, Deserialize)]
214pub struct TypeSummary {
215 pub name: String,
216 pub path: String,
217 pub kind: TypeKind,
218 pub generics: Vec<GenericParam>,
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize)]
223pub struct TypeDetails {
224 pub name: String,
225 pub path: String,
226 pub kind: TypeKind,
227 pub visibility: Visibility,
228 pub generics: Vec<GenericParam>,
229 pub where_clause: Option<String>,
230 pub docs: Option<String>,
232 pub attributes: Vec<String>,
234 pub fields: Option<Vec<FieldInfo>>,
236 pub variants: Option<Vec<EnumVariantInfo>>,
238 pub trait_impls: Vec<String>,
240 pub inherent_methods: Vec<MethodSummary>,
242 pub layout: Option<LayoutInfo>,
244 pub source: Option<String>,
246 pub span: Option<SpanInfo>,
247}
248
249#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
251#[serde(rename_all = "snake_case")]
252pub enum TypeKind {
253 Struct,
254 Enum,
255 Union,
256 Trait,
257 TypeAlias,
258 Primitive,
259 Tuple,
260 Array,
261 Slice,
262 Reference,
263 Pointer,
264 Function,
265 Closure,
266 Opaque,
267}
268
269#[derive(Debug, Clone, Serialize, Deserialize)]
271pub struct GenericParam {
272 pub name: String,
273 pub kind: GenericParamKind,
274 pub bounds: Vec<String>,
276 pub default: Option<String>,
278}
279
280#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
281#[serde(rename_all = "snake_case")]
282pub enum GenericParamKind {
283 Lifetime,
284 Type,
285 Const { ty: String },
286}
287
288#[derive(Debug, Clone, Serialize, Deserialize)]
294pub struct FieldInfo {
295 pub name: Option<String>,
297 pub index: usize,
299 pub ty: String,
301 pub resolved_ty: Option<String>,
303 pub visibility: Visibility,
305 pub docs: Option<String>,
307 pub attributes: Vec<String>,
309 pub offset: Option<usize>,
311 pub size: Option<usize>,
313 pub span: Option<SpanInfo>,
314}
315
316#[derive(Debug, Clone, Serialize, Deserialize)]
318pub struct EnumVariantInfo {
319 pub name: String,
320 pub index: usize,
321 pub fields: Vec<FieldInfo>,
323 pub discriminant: Option<String>,
325 pub docs: Option<String>,
327 pub attributes: Vec<String>,
329 pub span: Option<SpanInfo>,
330}
331
332#[derive(Debug, Clone, Serialize, Deserialize)]
338pub struct LayoutInfo {
339 pub size: usize,
341 pub align: usize,
343 pub field_offsets: Option<Vec<FieldLayoutInfo>>,
345 pub variants: Option<Vec<VariantLayoutInfo>>,
347 pub is_sized: bool,
349 pub is_copy: bool,
351 pub is_send: bool,
353 pub is_sync: bool,
355}
356
357#[derive(Debug, Clone, Serialize, Deserialize)]
358pub struct FieldLayoutInfo {
359 pub name: Option<String>,
360 pub index: usize,
361 pub offset: usize,
362 pub size: usize,
363}
364
365#[derive(Debug, Clone, Serialize, Deserialize)]
366pub struct VariantLayoutInfo {
367 pub name: String,
368 pub discriminant: Option<i128>,
369 pub fields: Vec<FieldLayoutInfo>,
370}
371
372#[derive(Debug, Clone, Serialize, Deserialize)]
378pub struct TraitImplDetails {
379 pub self_ty: String,
381 pub trait_path: String,
383 pub generics: Vec<GenericParam>,
385 pub where_clause: Option<String>,
387 pub is_negative: bool,
389 pub is_unsafe: bool,
391 pub methods: Vec<MethodDetails>,
393 pub assoc_types: Vec<AssocTypeInfo>,
395 pub assoc_consts: Vec<AssocConstInfo>,
397 pub source: Option<String>,
399 pub span: Option<SpanInfo>,
400}
401
402#[derive(Debug, Clone, Serialize, Deserialize)]
404pub struct InherentImplDetails {
405 pub self_ty: String,
407 pub generics: Vec<GenericParam>,
409 pub where_clause: Option<String>,
411 pub is_unsafe: bool,
413 pub methods: Vec<MethodDetails>,
415 pub assoc_consts: Vec<AssocConstInfo>,
417 pub assoc_types: Vec<AssocTypeInfo>,
419 pub source: Option<String>,
421 pub span: Option<SpanInfo>,
422}
423
424#[derive(Debug, Clone, Serialize, Deserialize)]
426pub struct MethodSummary {
427 pub name: String,
428 pub path: String,
429 pub signature: String,
430 pub is_unsafe: bool,
431 pub is_const: bool,
432 pub is_async: bool,
433}
434
435#[derive(Debug, Clone, Serialize, Deserialize)]
437pub struct MethodDetails {
438 pub name: String,
439 pub path: String,
440 pub signature: String,
442 pub parsed_signature: FunctionSignature,
444 pub has_body: bool,
446 pub body_source: Option<String>,
448 pub body_tokens: Option<Vec<Token>>,
450 pub is_unsafe: bool,
452 pub is_const: bool,
454 pub is_async: bool,
456 pub docs: Option<String>,
458 pub attributes: Vec<String>,
460 pub span: Option<SpanInfo>,
461}
462
463#[derive(Debug, Clone, Serialize, Deserialize)]
465pub struct FunctionSignature {
466 pub receiver: Option<ReceiverInfo>,
468 pub params: Vec<ParamInfo>,
470 pub return_ty: Option<String>,
472 pub generics: Vec<GenericParam>,
474 pub where_clause: Option<String>,
476}
477
478#[derive(Debug, Clone, Serialize, Deserialize)]
479pub struct ReceiverInfo {
480 pub kind: String,
482 pub is_mut: bool,
484 pub is_ref: bool,
486 pub lifetime: Option<String>,
488}
489
490#[derive(Debug, Clone, Serialize, Deserialize)]
491pub struct ParamInfo {
492 pub name: String,
493 pub ty: String,
494 pub is_mut: bool,
495}
496
497#[derive(Debug, Clone, Serialize, Deserialize)]
499pub struct AssocTypeInfo {
500 pub name: String,
501 pub ty: Option<String>,
503 pub bounds: Vec<String>,
505 pub default: Option<String>,
507 pub docs: Option<String>,
508 pub span: Option<SpanInfo>,
509}
510
511#[derive(Debug, Clone, Serialize, Deserialize)]
513pub struct AssocConstInfo {
514 pub name: String,
515 pub ty: String,
516 pub value: Option<String>,
518 pub docs: Option<String>,
519 pub span: Option<SpanInfo>,
520}
521
522#[derive(Debug, Clone, Serialize, Deserialize)]
528pub struct TraitInfo {
529 pub name: String,
530 pub path: String,
531 pub generics: Vec<GenericParam>,
532 pub required_methods: usize,
534 pub provided_methods: usize,
536 pub supertraits: Vec<String>,
538}
539
540#[derive(Debug, Clone, Serialize, Deserialize)]
542pub struct TraitDetails {
543 pub name: String,
544 pub path: String,
545 pub visibility: Visibility,
546 pub generics: Vec<GenericParam>,
547 pub where_clause: Option<String>,
548 pub is_auto: bool,
550 pub is_unsafe: bool,
552 pub supertraits: Vec<String>,
554 pub methods: Vec<TraitMethodInfo>,
556 pub assoc_types: Vec<AssocTypeInfo>,
558 pub assoc_consts: Vec<AssocConstInfo>,
560 pub docs: Option<String>,
562 pub attributes: Vec<String>,
564 pub source: Option<String>,
566 pub implementors: Vec<String>,
568 pub span: Option<SpanInfo>,
569}
570
571#[derive(Debug, Clone, Serialize, Deserialize)]
573pub struct TraitMethodInfo {
574 pub name: String,
575 pub signature: String,
576 pub parsed_signature: FunctionSignature,
577 pub has_default: bool,
579 pub default_body: Option<String>,
581 pub is_unsafe: bool,
582 pub docs: Option<String>,
583 pub attributes: Vec<String>,
584 pub span: Option<SpanInfo>,
585}
586
587#[derive(Debug, Clone, Serialize, Deserialize)]
593#[serde(tag = "token_type", rename_all = "snake_case")]
594pub enum Token {
595 Ident { name: String },
597 Literal { kind: LiteralKind, value: String },
599 Punct { ch: char },
601 Keyword { name: String },
603 Group {
605 delimiter: Delimiter,
606 tokens: Vec<Token>,
607 },
608 Path { segments: Vec<String> },
610 MethodCall {
612 receiver: Box<Token>,
613 method: String,
614 args: Vec<Token>,
615 },
616 FnCall { path: Vec<String>, args: Vec<Token> },
618 FieldAccess { base: Box<Token>, field: String },
620 BinOp {
622 lhs: Box<Token>,
623 op: String,
624 rhs: Box<Token>,
625 },
626 UnaryOp { op: String, expr: Box<Token> },
628 If {
630 cond: Box<Token>,
631 then_branch: Vec<Token>,
632 else_branch: Option<Vec<Token>>,
633 },
634 Match {
636 expr: Box<Token>,
637 arms: Vec<MatchArm>,
638 },
639 Let {
641 pattern: String,
642 ty: Option<String>,
643 init: Option<Box<Token>>,
644 },
645 Return { expr: Option<Box<Token>> },
647 Block { stmts: Vec<Token> },
649 Closure {
651 params: Vec<String>,
652 body: Box<Token>,
653 },
654 Raw { source: String },
656}
657
658#[derive(Debug, Clone, Serialize, Deserialize)]
659pub struct MatchArm {
660 pub pattern: String,
661 pub guard: Option<String>,
662 pub body: Vec<Token>,
663}
664
665#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
666#[serde(rename_all = "snake_case")]
667pub enum LiteralKind {
668 String,
669 ByteString,
670 Char,
671 Byte,
672 Int,
673 Float,
674 Bool,
675}
676
677#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
678#[serde(rename_all = "snake_case")]
679pub enum Delimiter {
680 Paren,
681 Bracket,
682 Brace,
683 None,
684}
685
686#[derive(Debug, Clone, Default, Serialize, Deserialize)]
693pub struct CrateTypeInfo {
694 pub crate_name: String,
696 pub crate_version: Option<String>,
698
699 pub items: Vec<ItemInfo>,
701
702 pub types: HashMap<String, TypeDetails>,
704
705 pub traits: HashMap<String, TraitDetails>,
707
708 pub trait_impls: HashMap<String, Vec<TraitImplDetails>>,
710
711 pub inherent_impls: HashMap<String, Vec<InherentImplDetails>>,
713
714 pub type_aliases: HashMap<String, TypeAliasInfo>,
716
717 pub layouts: HashMap<String, LayoutInfo>,
719
720 pub modules: HashMap<String, ModuleInfo>,
722}
723
724#[derive(Debug, Clone, Serialize, Deserialize)]
726pub struct TypeAliasInfo {
727 pub name: String,
728 pub path: String,
729 pub generics: Vec<GenericParam>,
730 pub ty: String,
732 pub resolved_ty: String,
734 pub visibility: Visibility,
735 pub docs: Option<String>,
736 pub span: Option<SpanInfo>,
737}
738
739#[derive(Debug, Clone, Serialize, Deserialize)]
741pub struct ModuleInfo {
742 pub name: String,
743 pub path: String,
744 pub visibility: Visibility,
745 pub items: Vec<String>,
747 pub reexports: Vec<ReexportInfo>,
749}
750
751#[derive(Debug, Clone, Serialize, Deserialize)]
752pub struct ReexportInfo {
753 pub name: String,
755 pub original_path: String,
757 pub visibility: Visibility,
758}
759
760pub fn default_socket_path() -> std::path::PathBuf {
766 std::env::temp_dir().join("bronzite.sock")
767}
768
769pub fn socket_path_for_workspace(workspace_root: &std::path::Path) -> std::path::PathBuf {
771 use std::collections::hash_map::DefaultHasher;
772 use std::hash::{Hash, Hasher};
773
774 let mut hasher = DefaultHasher::new();
775 workspace_root.hash(&mut hasher);
776 let hash = hasher.finish();
777
778 std::env::temp_dir().join(format!("bronzite-{:x}.sock", hash))
779}
780
781pub fn path_matches_pattern(path: &str, pattern: &str) -> bool {
792 let pattern = pattern.trim();
793 let path = path.trim();
794
795 if pattern.ends_with("::**") {
797 let prefix = &pattern[..pattern.len() - 4];
798 return path == prefix || path.starts_with(&format!("{}::", prefix));
799 }
800
801 if pattern.ends_with("::*") {
803 let prefix = &pattern[..pattern.len() - 3];
804 if !path.starts_with(&format!("{}::", prefix)) {
805 return false;
806 }
807 let suffix = &path[prefix.len() + 2..];
808 return !suffix.contains("::");
809 }
810
811 if pattern.contains('*') {
813 let parts: Vec<&str> = pattern.split('*').collect();
814 if parts.len() != 2 {
815 return false; }
817 return path.starts_with(parts[0]) && path.ends_with(parts[1]);
818 }
819
820 path == pattern
822}
823
824#[cfg(test)]
825mod tests {
826 use super::*;
827
828 #[test]
829 fn test_path_matching() {
830 assert!(path_matches_pattern("foo::Bar", "foo::Bar"));
832 assert!(!path_matches_pattern("foo::Baz", "foo::Bar"));
833
834 assert!(path_matches_pattern("foo::Bar", "foo::*"));
836 assert!(path_matches_pattern("foo::Baz", "foo::*"));
837 assert!(!path_matches_pattern("foo::bar::Baz", "foo::*"));
838
839 assert!(path_matches_pattern("foo::Bar", "foo::**"));
841 assert!(path_matches_pattern("foo::bar::Baz", "foo::**"));
842 assert!(path_matches_pattern("foo::bar::baz::Qux", "foo::**"));
843 assert!(!path_matches_pattern("bar::Baz", "foo::**"));
844
845 assert!(path_matches_pattern("foo::BarBaz", "foo::Bar*"));
847 assert!(path_matches_pattern("foo::Bar", "foo::Bar*"));
848 assert!(!path_matches_pattern("foo::Baz", "foo::Bar*"));
849 }
850
851 #[test]
852 fn test_query_serialization() {
853 let query = Query::CheckImpl {
854 type_path: "Foo".to_string(),
855 trait_path: "MyTrait".to_string(),
856 };
857 let json = serde_json::to_string(&query).unwrap();
858 let parsed: Query = serde_json::from_str(&json).unwrap();
859
860 match parsed {
861 Query::CheckImpl {
862 type_path,
863 trait_path,
864 } => {
865 assert_eq!(type_path, "Foo");
866 assert_eq!(trait_path, "MyTrait");
867 }
868 _ => panic!("Wrong query type"),
869 }
870 }
871
872 #[test]
873 fn test_response_serialization() {
874 let response = Response {
875 id: 42,
876 result: QueryResult::Success {
877 data: QueryData::ImplCheck {
878 implements: true,
879 impl_info: None,
880 },
881 },
882 };
883 let json = serde_json::to_string(&response).unwrap();
884 let parsed: Response = serde_json::from_str(&json).unwrap();
885
886 assert_eq!(parsed.id, 42);
887 }
888}