type_sitter_lib/node/
wrappers.rs

1use crate::raw;
2use crate::{IncorrectKind, Node, NodeResult};
3use std::fmt::Debug;
4
5macro_rules! define_simple_wrapper {
6    ($comment:literal, $Type:ident, $method:ident, $name:literal) => {
7        #[doc = $comment]
8        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9        #[repr(transparent)]
10        pub struct $Type<'tree>(raw::Node<'tree>);
11
12        impl<'tree> Node<'tree> for $Type<'tree> {
13            type WithLifetime<'a> = $Type<'a>;
14
15            const KIND: &'static str = concat!("{", $name, "}");
16
17            fn try_from_raw(node: raw::Node<'tree>) -> NodeResult<'tree, Self> {
18                if node.$method() {
19                    Ok($Type(node))
20                } else {
21                    Err(IncorrectKind::new::<Self>(node))
22                }
23            }
24
25            #[inline]
26            unsafe fn from_raw_unchecked(node: raw::Node<'tree>) -> Self {
27                debug_assert!(node.$method());
28                $Type(node)
29            }
30
31            #[inline]
32            fn raw(&self) -> &raw::Node<'tree> {
33                &self.0
34            }
35
36            #[inline]
37            fn raw_mut(&mut self) -> &mut raw::Node<'tree> {
38                &mut self.0
39            }
40
41            #[inline]
42            fn into_raw(self) -> raw::Node<'tree> {
43                self.0
44            }
45        }
46    };
47}
48
49define_simple_wrapper! {
50    "A node that can annotate any other node, e.g. a comment.",
51    Extra,
52    is_extra,
53    "extra"
54}
55
56define_simple_wrapper! {
57    "A stub node that indicates a localized parse error.",
58    Error,
59    is_error,
60    "error"
61}
62
63define_simple_wrapper! {
64    "A stub node that indicates another node was expected.",
65    Missing,
66    is_missing,
67    "missing"
68}
69
70define_simple_wrapper! {
71    "A node that is untyped other than being named.",
72    UntypedNamedNode,
73    is_named,
74    "untyped named"
75}
76
77/// A node that is untyped, but implements [`Node`] anyways.
78///
79/// It's purpose is normalization: e.g. a method might take a [`Node`] parameter, so you can
80/// pass any kind of typed node, and you may want to just pass a regular node.
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
82#[repr(transparent)]
83pub struct UntypedNode<'tree>(raw::Node<'tree>);
84
85impl<'tree> UntypedNode<'tree> {
86    /// Wrap the tree-sitter node so that it can be used wherever a [`Node`] can, but provides no
87    /// type guarantees.
88    #[inline]
89    pub fn new(node: raw::Node<'tree>) -> Self {
90        Self(node)
91    }
92
93    /// Convert a reference to a tree-sitter node into one of an untyped node.
94    ///
95    /// This is a transmute, but safe since they have the same representation.
96    #[inline]
97    pub fn r#ref<'a>(node: &'a raw::Node<'tree>) -> &'a Self {
98        unsafe { &*(node as *const raw::Node<'tree> as *const Self) }
99    }
100
101    /// Convert a mutable reference to a tree-sitter node into one of an untyped node.
102    ///
103    /// This is a transmute, but safe since they have the same representation.
104    #[inline]
105    pub fn r#mut<'a>(node: &'a mut raw::Node<'tree>) -> &'a mut Self {
106        unsafe { &mut *(node as *mut raw::Node<'tree> as *mut Self) }
107    }
108
109    /// Is this an error node?
110    #[inline]
111    pub fn is_error(&self) -> bool {
112        self.raw().is_error()
113    }
114
115    /// Is this a missing node?
116    #[inline]
117    pub fn is_missing(&self) -> bool {
118        self.raw().is_missing()
119    }
120
121    /// Is this an extra node?
122    #[inline]
123    pub fn is_extra(&self) -> bool {
124        self.raw().is_extra()
125    }
126
127    /// Try to downcast to the given type.
128    ///
129    /// See [`Node::try_from_raw`].
130    #[inline]
131    pub fn downcast<Type: Node<'tree>>(&self) -> NodeResult<'_, Type> {
132        Type::try_from_raw(self.0)
133    }
134}
135
136impl<'tree> From<raw::Node<'tree>> for UntypedNode<'tree> {
137    fn from(value: raw::Node<'tree>) -> Self {
138        Self(value)
139    }
140}
141
142impl<'tree> Node<'tree> for UntypedNode<'tree> {
143    type WithLifetime<'a> = UntypedNode<'a>;
144
145    const KIND: &'static str = "{untyped}";
146
147    fn try_from_raw(node: raw::Node<'tree>) -> NodeResult<'tree, Self> {
148        Ok(UntypedNode(node))
149    }
150
151    #[inline]
152    unsafe fn from_raw_unchecked(node: raw::Node<'tree>) -> Self {
153        UntypedNode(node)
154    }
155
156    #[inline]
157    fn raw(&self) -> &raw::Node<'tree> {
158        &self.0
159    }
160
161    #[inline]
162    fn raw_mut(&mut self) -> &mut raw::Node<'tree> {
163        &mut self.0
164    }
165
166    #[inline]
167    fn into_raw(self) -> raw::Node<'tree> {
168        self.0
169    }
170}
171
172impl<'tree> UntypedNamedNode<'tree> {
173    /// Try to downcast to the given type.
174    ///
175    /// See [`Node::try_from_raw`].
176    #[inline]
177    pub fn downcast<Type: Node<'tree>>(&self) -> NodeResult<'_, Type> {
178        Type::try_from_raw(self.0)
179    }
180}