tree_sitter_utils/constructors.rs
1//! Free-function handler constructors.
2
3use crate::handler::{Handler, HandlerResult};
4use crate::input::Input;
5
6// ---------------------------------------------------------------------------
7// handler_fn
8// ---------------------------------------------------------------------------
9
10/// Wrap an infallible function as a [`Handler`] that always returns `Some`.
11///
12/// Use this when your mapping function cannot fail.
13///
14/// # Example
15///
16/// ```rust
17/// use tree_sitter_utils::{handler_fn, Handler, Input};
18///
19/// let h = handler_fn(|input: Input<()>| input.node.kind().to_owned());
20/// let _ = h;
21/// ```
22pub fn handler_fn<Ctx, R, F>(f: F) -> HandlerFn<F>
23where
24 F: Fn(Input<'_, Ctx>) -> R + Send + Sync,
25{
26 HandlerFn(f)
27}
28
29/// Handler produced by [`handler_fn`].
30///
31/// # Example
32///
33/// ```rust
34/// use tree_sitter_utils::{handler_fn, Input};
35/// let h = handler_fn(|_: Input<()>| 42u32);
36/// let _ = h;
37/// ```
38pub struct HandlerFn<F>(F);
39
40impl<Ctx, R, F> Handler<Ctx, R> for HandlerFn<F>
41where
42 F: Fn(Input<'_, Ctx>) -> R + Send + Sync,
43 Ctx: Copy,
44{
45 #[inline]
46 fn handle<'tree>(&self, input: Input<'tree, Ctx>) -> HandlerResult<R> {
47 Some((self.0)(input))
48 }
49}
50
51// ---------------------------------------------------------------------------
52// never / always
53// ---------------------------------------------------------------------------
54
55/// A handler that always returns `None`.
56///
57/// # Example
58///
59/// ```rust
60/// use tree_sitter_utils::{never, HandlerExt, handler_fn, Input};
61///
62/// let h = never::<(), String>()
63/// .or(handler_fn(|_: Input<()>| "fallback".to_owned()));
64/// let _ = h;
65/// ```
66pub fn never<Ctx, R>() -> Never<Ctx, R> {
67 Never(std::marker::PhantomData)
68}
69
70/// Handler produced by [`never()`].
71///
72/// # Example
73///
74/// ```rust
75/// use tree_sitter_utils::never;
76/// let h = never::<(), u32>();
77/// let _ = h;
78/// ```
79pub struct Never<Ctx, R>(std::marker::PhantomData<fn(Ctx) -> R>);
80
81impl<Ctx, R> Handler<Ctx, R> for Never<Ctx, R> {
82 #[inline]
83 fn handle<'tree>(&self, _input: Input<'tree, Ctx>) -> HandlerResult<R> {
84 None
85 }
86}
87
88/// A handler that always returns `Some(value.clone())`.
89///
90/// # Example
91///
92/// ```rust
93/// use tree_sitter_utils::always;
94/// let h = always::<(), _>("hello".to_owned());
95/// let _ = h;
96/// ```
97pub fn always<Ctx, R: Clone + Send + Sync>(value: R) -> Always<R> {
98 Always(value)
99}
100
101/// Handler produced by [`always`].
102///
103/// # Example
104///
105/// ```rust
106/// use tree_sitter_utils::always;
107/// let h = always::<(), u32>(42);
108/// let _ = h;
109/// ```
110pub struct Always<R>(pub R);
111
112impl<R> Always<R> {
113 /// Construct an [`Always`] handler in a `const` / `static` context.
114 ///
115 /// # Example
116 ///
117 /// ```rust
118 /// use tree_sitter_utils::constructors::Always;
119 /// static H: Always<u32> = Always::new_const(42u32);
120 /// ```
121 pub const fn new_const(value: R) -> Self {
122 Always(value)
123 }
124}
125
126impl<Ctx, R: Clone + Send + Sync> Handler<Ctx, R> for Always<R> {
127 #[inline]
128 fn handle<'tree>(&self, _input: Input<'tree, Ctx>) -> HandlerResult<R> {
129 Some(self.0.clone())
130 }
131}
132
133// ---------------------------------------------------------------------------
134// dispatch_on_kind
135// ---------------------------------------------------------------------------
136
137/// Build a handler that dispatches on `node.kind()` via a static lookup table.
138///
139/// Entries are tried in order; the first matching kind wins.
140///
141/// # Example
142///
143/// ```rust
144/// use tree_sitter_utils::dispatch_on_kind;
145/// // let h = dispatch_on_kind(&[("identifier", &my_handler)]);
146/// let _ = dispatch_on_kind::<(), u32>(&[]);
147/// ```
148pub fn dispatch_on_kind<Ctx: 'static, R: 'static>(
149 table: &'static [(&'static str, &'static dyn Handler<Ctx, R>)],
150) -> DispatchOnKind<Ctx, R> {
151 DispatchOnKind { table }
152}
153
154/// Handler produced by [`dispatch_on_kind`].
155///
156/// # Example
157///
158/// ```rust
159/// use tree_sitter_utils::dispatch_on_kind;
160/// let h = dispatch_on_kind::<(), u32>(&[]);
161/// let _ = h;
162/// ```
163pub struct DispatchOnKind<Ctx: 'static, R: 'static> {
164 /// The static dispatch table.
165 pub table: &'static [(&'static str, &'static dyn Handler<Ctx, R>)],
166}
167
168impl<Ctx, R> Handler<Ctx, R> for DispatchOnKind<Ctx, R>
169where
170 Ctx: Copy + 'static,
171 R: 'static,
172{
173 fn handle<'tree>(&self, input: Input<'tree, Ctx>) -> HandlerResult<R> {
174 let kind = input.node.kind();
175 for (k, h) in self.table {
176 if *k == kind {
177 return h.handle(input);
178 }
179 }
180 None
181 }
182}
183
184// ---------------------------------------------------------------------------
185// first_of
186// ---------------------------------------------------------------------------
187
188/// Try a slice of boxed handlers in order; return the first `Some` result.
189///
190/// # Example
191///
192/// ```rust
193/// use tree_sitter_utils::{first_of, always, never, BoxedHandler, HandlerExt};
194///
195/// let handlers: Vec<BoxedHandler<(), u32>> = vec![
196/// never::<(), u32>().boxed(),
197/// always::<(), u32>(1).boxed(),
198/// ];
199/// let h = first_of(handlers);
200/// let _ = h;
201/// ```
202pub fn first_of<Ctx, R>(
203 handlers: Vec<crate::combinators::boxed::BoxedHandler<Ctx, R>>,
204) -> FirstOf<Ctx, R> {
205 FirstOf { handlers }
206}
207
208/// Handler produced by [`first_of`].
209///
210/// # Example
211///
212/// ```rust
213/// use tree_sitter_utils::first_of;
214/// let h = first_of::<(), u32>(vec![]);
215/// let _ = h;
216/// ```
217pub struct FirstOf<Ctx, R> {
218 handlers: Vec<crate::combinators::boxed::BoxedHandler<Ctx, R>>,
219}
220
221impl<Ctx, R> Handler<Ctx, R> for FirstOf<Ctx, R>
222where
223 Ctx: Copy,
224{
225 fn handle<'tree>(&self, input: Input<'tree, Ctx>) -> HandlerResult<R> {
226 for h in &self.handlers {
227 let result = h.handle(input);
228 if result.is_some() {
229 return result;
230 }
231 }
232 None
233 }
234}