type_sitter_lib/query/matches.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
use crate::query::match_captures::QueryMatchCaptures;
use crate::{raw, Query};
use std::fmt::Debug;
use streaming_iterator::StreamingIterator;
#[cfg(not(feature = "yak-sitter"))]
use tree_sitter::Point;
#[cfg(feature = "yak-sitter")]
use yak_sitter::PointRange;
/// Iterate a typed query's matches (see [tree-sitter's `QueryMatches`](raw::QueryMatches)).
///
/// `QueryMatches` (in both this crate and tree-sitter) is NOT a real iterator, it's a
/// [`StreamingIterator`] (see <https://github.com/tree-sitter/tree-sitter/issues/608>).
/// Therefore this doesn't implement [`Iterator`].
#[cfg(feature = "yak-sitter")]
pub struct QueryMatches<'query, 'tree: 'query, Query: crate::Query> {
typed_query: &'query Query,
untyped_matches: raw::QueryMatches<'query, 'tree>,
current_match: Option<*const Query::Match<'query, 'tree>>,
}
/// Iterate a typed query's matches (see [tree-sitter's `QueryMatches`](raw::QueryMatches)).
///
/// `QueryMatches` (in both this crate and tree-sitter) is NOT a real iterator, it's a
/// [`StreamingIterator`] (see <https://github.com/tree-sitter/tree-sitter/issues/608>).
/// Therefore this doesn't implement [`Iterator`].
#[cfg(not(feature = "yak-sitter"))]
pub struct QueryMatches<'query, 'tree: 'query, Query: crate::Query + 'tree, Text: raw::TextProvider<I>, I: AsRef<[u8]>> {
typed_query: &'query Query,
untyped_matches: raw::QueryMatches<'query, 'tree, Text, I>,
current_match: Option<*const Query::Match<'query, 'tree>>,
}
/// A match from a [Query] with [typed nodes](Node)
pub trait QueryMatch<'query, 'tree: 'query>: Debug {
/// The type of query this match came from
type Query: Query<Match<'query, 'tree> = Self>;
/// The query this match came from
fn query(&self) -> &'query Self::Query;
/// The tree this match came from
#[cfg(feature = "yak-sitter")]
fn tree(&self) -> &'tree raw::Tree;
/// The underlying tree-sitter [`QueryMatch`]
fn raw(&self) -> &raw::QueryMatch<'query, 'tree>;
/// Destruct into the underlying tree-sitter [`QueryMatch`]
fn into_raw(self) -> raw::QueryMatch<'query, 'tree>;
/// See [tree-sitter's `QueryMatch::captures`](raw::QueryMatch::captures)
#[cfg(feature = "yak-sitter")]
#[inline]
fn captures(&self) -> QueryMatchCaptures<'query, 'tree, Self::Query> {
// SAFETY: Captures come from the same query
unsafe { QueryMatchCaptures::new(
self.query(),
self.raw().as_inner().captures,
self.tree()
) }
}
/// See [tree-sitter's `QueryMatch::captures`](raw::QueryMatch::captures)
#[cfg(not(feature = "yak-sitter"))]
#[inline]
fn captures(&self) -> QueryMatchCaptures<'query, 'tree, Self::Query> {
// SAFETY: Captures come from the same query
unsafe { QueryMatchCaptures::new(self.query(), self.raw().captures) }
}
/// Remove the match (honestly I don't know what this does because it's not documented)
// I don't know why `tree: 'query` is required, since it's not in any bounds from anything in
// the function body.
#[inline]
fn remove(self) where Self: Sized, 'tree: 'query {
self.into_raw().remove()
}
}
#[cfg(feature = "yak-sitter")]
impl<'query, 'tree: 'query, Query: crate::Query + 'tree> QueryMatches<'query, 'tree, Query> {
/// Wrap untyped matches along with the query.
///
/// # Safety
/// The matches must have come from the same query.
#[inline]
pub(super) unsafe fn from_raw(
typed_query: &'query Query,
untyped_matches: raw::QueryMatches<'query, 'tree>
) -> Self {
Self {
typed_query,
untyped_matches,
current_match: None
}
}
/// Limit matches to a byte range
#[inline]
pub fn set_byte_range(&mut self, range: std::ops::Range<usize>) {
self.untyped_matches.set_byte_range(range)
}
/// Limit matches to a point range
#[inline]
#[cfg(feature = "yak-sitter")]
pub fn set_point_range(&mut self, range: PointRange) {
self.untyped_matches.set_point_range(range)
}
}
#[cfg(not(feature = "yak-sitter"))]
impl<'query, 'tree: 'query, Query: crate::Query + 'tree, Text: raw::TextProvider<I>, I: AsRef<[u8]>> QueryMatches<'query, 'tree, Query, Text, I> {
/// Wrap untyped matches along with the query.
///
/// # Safety
/// The matches must have come from the same query.
#[inline]
pub(super) unsafe fn from_raw(
typed_query: &'query Query,
untyped_matches: raw::QueryMatches<'query, 'tree, Text, I>
) -> Self {
Self {
typed_query,
untyped_matches,
current_match: None
}
}
/// Limit matches to a byte range
#[inline]
pub fn set_byte_range(&mut self, range: std::ops::Range<usize>) {
self.untyped_matches.set_byte_range(range)
}
/// Limit matches to a point range
#[inline]
pub fn set_point_range(&mut self, range: std::ops::Range<Point>) {
self.untyped_matches.set_point_range(range)
}
}
//noinspection DuplicatedCode
#[cfg(feature = "yak-sitter")]
impl<'query, 'tree: 'query, Query: crate::Query + 'tree> StreamingIterator for QueryMatches<'query, 'tree, Query> {
type Item = Query::Match<'query, 'tree>;
#[inline]
fn advance(&mut self) {
self.untyped_matches.advance();
// SAFETY: Matches come from the same query and tree.
self.current_match = unsafe {
self.untyped_matches.get().map(|m|
self.typed_query.wrap_match_ref(m) as *const _)
}
}
#[inline]
fn get(&self) -> Option<&Self::Item> {
// SAFETY: `m` is still live, because it's only invalidated when this `untyped_matches` is
// dropped (which only happens when `self` is dropped, which can't have happened here) or
// `untyped_matches.advance` is called (which can only happen when `self.advance` is called,
// which replaces `current_match` with another value where, if `Some`, `m` is live).
self.current_match.map(|m| unsafe { &*m })
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.untyped_matches.size_hint()
}
}
//noinspection DuplicatedCode
#[cfg(not(feature = "yak-sitter"))]
impl<'query, 'tree: 'query, Query: crate::Query + 'tree, Text: raw::TextProvider<I>, I: AsRef<[u8]>> StreamingIterator for QueryMatches<'query, 'tree, Query, Text, I> {
type Item = Query::Match<'query, 'tree>;
#[inline]
fn advance(&mut self) {
self.untyped_matches.advance();
// SAFETY: Matches come from the same query and tree.
self.current_match = unsafe {
self.untyped_matches.get().map(|m|
self.typed_query.wrap_match_ref(m) as *const _)
}
}
#[inline]
fn get(&self) -> Option<&Self::Item> {
// SAFETY: `m` is still live, because it's only invalidated when this `untyped_matches` is
// dropped (which only happens when `self` is dropped, which can't have happened here) or
// `untyped_matches.advance` is called (which can only happen when `self.advance` is called,
// which replaces `current_match` with another value where, if `Some`, `m` is live).
self.current_match.map(|m| unsafe { &*m })
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.untyped_matches.size_hint()
}
}