Skip to main content

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    /// Is this downcastable to `Type`?
136    ///
137    /// See [`Node::try_from_raw`]
138    #[inline]
139    pub fn is<Type: Node<'tree>>(&self) -> bool {
140        self.downcast::<Type>().is_ok()
141    }
142}
143
144impl<'tree> From<raw::Node<'tree>> for UntypedNode<'tree> {
145    fn from(value: raw::Node<'tree>) -> Self {
146        Self(value)
147    }
148}
149
150impl<'tree> Node<'tree> for UntypedNode<'tree> {
151    type WithLifetime<'a> = UntypedNode<'a>;
152
153    const KIND: &'static str = "{untyped}";
154
155    fn try_from_raw(node: raw::Node<'tree>) -> NodeResult<'tree, Self> {
156        Ok(UntypedNode(node))
157    }
158
159    #[inline]
160    unsafe fn from_raw_unchecked(node: raw::Node<'tree>) -> Self {
161        UntypedNode(node)
162    }
163
164    #[inline]
165    fn raw(&self) -> &raw::Node<'tree> {
166        &self.0
167    }
168
169    #[inline]
170    fn raw_mut(&mut self) -> &mut raw::Node<'tree> {
171        &mut self.0
172    }
173
174    #[inline]
175    fn into_raw(self) -> raw::Node<'tree> {
176        self.0
177    }
178}
179
180impl<'tree> UntypedNamedNode<'tree> {
181    /// Try to downcast to the given type.
182    ///
183    /// See [`Node::try_from_raw`].
184    #[inline]
185    pub fn downcast<Type: Node<'tree>>(&self) -> NodeResult<'_, Type> {
186        Type::try_from_raw(self.0)
187    }
188}