1use std::{
13 hash::{Hash, Hasher},
14 marker::PhantomData,
15};
16
17use rowan::TextRange;
18
19use crate::{AstNode, SyntaxNode, syntax_node::RustLanguage};
20
21pub type SyntaxNodePtr = rowan::ast::SyntaxNodePtr<RustLanguage>;
23
24pub struct AstPtr<N: AstNode> {
26 raw: SyntaxNodePtr,
27 _ty: PhantomData<fn() -> N>,
28}
29
30impl<N: AstNode> std::fmt::Debug for AstPtr<N> {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 f.debug_tuple("AstPtr").field(&self.raw).finish()
33 }
34}
35
36impl<N: AstNode> Copy for AstPtr<N> {}
37impl<N: AstNode> Clone for AstPtr<N> {
38 fn clone(&self) -> AstPtr<N> {
39 *self
40 }
41}
42
43impl<N: AstNode> Eq for AstPtr<N> {}
44
45impl<N: AstNode> PartialEq for AstPtr<N> {
46 fn eq(&self, other: &AstPtr<N>) -> bool {
47 self.raw == other.raw
48 }
49}
50
51impl<N: AstNode> Hash for AstPtr<N> {
52 fn hash<H: Hasher>(&self, state: &mut H) {
53 self.raw.hash(state);
54 }
55}
56
57impl<N: AstNode> AstPtr<N> {
58 pub fn new(node: &N) -> AstPtr<N> {
59 AstPtr { raw: SyntaxNodePtr::new(node.syntax()), _ty: PhantomData }
60 }
61
62 pub fn to_node(&self, root: &SyntaxNode) -> N {
63 let syntax_node = self.raw.to_node(root);
64 N::cast(syntax_node).unwrap()
65 }
66
67 pub fn syntax_node_ptr(&self) -> SyntaxNodePtr {
68 self.raw
69 }
70
71 pub fn text_range(&self) -> TextRange {
72 self.raw.text_range()
73 }
74
75 pub fn cast<U: AstNode>(self) -> Option<AstPtr<U>> {
76 if !U::can_cast(self.raw.kind()) {
77 return None;
78 }
79 Some(AstPtr { raw: self.raw, _ty: PhantomData })
80 }
81
82 pub fn kind(&self) -> parser::SyntaxKind {
83 self.raw.kind()
84 }
85
86 pub fn upcast<M: AstNode>(self) -> AstPtr<M>
87 where
88 N: Into<M>,
89 {
90 AstPtr { raw: self.raw, _ty: PhantomData }
91 }
92
93 pub fn try_from_raw(raw: SyntaxNodePtr) -> Option<AstPtr<N>> {
95 N::can_cast(raw.kind()).then_some(AstPtr { raw, _ty: PhantomData })
96 }
97
98 pub fn wrap_left<R>(self) -> AstPtr<either::Either<N, R>>
99 where
100 either::Either<N, R>: AstNode,
101 {
102 AstPtr { raw: self.raw, _ty: PhantomData }
103 }
104
105 pub fn wrap_right<L>(self) -> AstPtr<either::Either<L, N>>
106 where
107 either::Either<L, N>: AstNode,
108 {
109 AstPtr { raw: self.raw, _ty: PhantomData }
110 }
111}
112
113impl<N: AstNode> From<AstPtr<N>> for SyntaxNodePtr {
114 fn from(ptr: AstPtr<N>) -> SyntaxNodePtr {
115 ptr.raw
116 }
117}
118
119#[test]
120fn test_local_syntax_ptr() {
121 use crate::{AstNode, SourceFile, ast};
122
123 let file = SourceFile::parse("struct Foo { f: u32, }", parser::Edition::CURRENT).ok().unwrap();
124 let field = file.syntax().descendants().find_map(ast::RecordField::cast).unwrap();
125 let ptr = SyntaxNodePtr::new(field.syntax());
126 let field_syntax = ptr.to_node(file.syntax());
127 assert_eq!(field.syntax(), &field_syntax);
128}