ref(rust_bindings): add from_raw() functions

This commit is contained in:
Vhyrro 2023-03-14 21:32:48 +01:00 committed by Andrew Hlynskyi
parent 6c2957c8d3
commit e5357dc5ad
2 changed files with 282 additions and 214 deletions

View file

@ -8,10 +8,22 @@ extern "C" {
pub(crate) fn dup(fd: std::os::raw::c_int) -> std::os::raw::c_int;
}
use crate::{Language, Node, Parser, Query, QueryCursor, Tree, TreeCursor};
use std::mem::ManuallyDrop;
use crate::{
predicate_error, Language, Node, Parser, Query, QueryCursor, QueryError, QueryPredicate,
QueryPredicateArg, TextPredicate, Tree, TreeCursor,
};
use std::{marker::PhantomData, mem::ManuallyDrop, ptr::NonNull, slice, str};
impl Language {
/// Reconstructs a [Language] from a raw pointer.
///
/// # Safety
///
/// `ptr` must be non-null.
pub unsafe fn from_raw(ptr: *mut TSLanguage) -> Language {
Language(ptr)
}
/// Consumes the [Language], returning a raw pointer to the underlying C structure.
pub fn into_raw(self) -> *const TSLanguage {
ManuallyDrop::new(self).0
@ -19,6 +31,15 @@ impl Language {
}
impl Parser {
/// Reconstructs a [Parser] from a raw pointer.
///
/// # Safety
///
/// `ptr` must be non-null.
pub unsafe fn from_raw(ptr: *mut TSParser) -> Parser {
Parser(NonNull::new_unchecked(ptr))
}
/// Consumes the [Parser], returning a raw pointer to the underlying C structure.
pub fn into_raw(mut self) -> *mut TSParser {
self.stop_printing_dot_graphs();
@ -29,6 +50,15 @@ impl Parser {
}
impl Tree {
/// Reconstructs a [Tree] from a raw pointer.
///
/// # Safety
///
/// `ptr` must be non-null.
pub unsafe fn from_raw(ptr: *mut TSTree) -> Tree {
Tree(NonNull::new_unchecked(ptr))
}
/// Consumes the [Tree], returning a raw pointer to the underlying C structure.
pub fn into_raw(self) -> *mut TSTree {
ManuallyDrop::new(self).0.as_ptr()
@ -36,6 +66,15 @@ impl Tree {
}
impl<'tree> Node<'tree> {
/// Reconstructs a [Node] from a raw pointer.
///
/// # Safety
///
/// `ptr` must be non-null.
pub unsafe fn from_raw(ptr: *mut TSNode) -> Node<'tree> {
Node(*ptr, PhantomData)
}
/// Consumes the [Node], returning a raw pointer to the underlying C structure.
pub fn into_raw(self) -> *mut TSNode {
&mut ManuallyDrop::new(self).0
@ -43,6 +82,15 @@ impl<'tree> Node<'tree> {
}
impl<'a> TreeCursor<'a> {
/// Reconstructs a [TreeCursor] from a raw pointer.
///
/// # Safety
///
/// `ptr` must be non-null.
pub unsafe fn from_raw(ptr: *mut TSTreeCursor) -> TreeCursor<'a> {
TreeCursor(*ptr, PhantomData)
}
/// Consumes the [TreeCursor], returning a raw pointer to the underlying C structure.
pub fn into_raw(self) -> *mut TSTreeCursor {
&mut ManuallyDrop::new(self).0
@ -50,6 +98,225 @@ impl<'a> TreeCursor<'a> {
}
impl Query {
/// Reconstructs a [Query] from a raw pointer.
///
/// # Safety
///
/// `ptr` must be non-null.
pub unsafe fn from_raw(ptr: *mut TSQuery, source: &str) -> Result<Query, QueryError> {
let string_count = unsafe { ts_query_string_count(ptr) };
let capture_count = unsafe { ts_query_capture_count(ptr) };
let pattern_count = unsafe { ts_query_pattern_count(ptr) as usize };
let mut result = Query {
ptr: unsafe { NonNull::new_unchecked(ptr) },
capture_names: Vec::with_capacity(capture_count as usize),
capture_quantifiers: Vec::with_capacity(pattern_count as usize),
text_predicates: Vec::with_capacity(pattern_count),
property_predicates: Vec::with_capacity(pattern_count),
property_settings: Vec::with_capacity(pattern_count),
general_predicates: Vec::with_capacity(pattern_count),
};
// Build a vector of strings to store the capture names.
for i in 0..capture_count {
unsafe {
let mut length = 0u32;
let name =
ts_query_capture_name_for_id(ptr, i, &mut length as *mut u32) as *const u8;
let name = slice::from_raw_parts(name, length as usize);
let name = str::from_utf8_unchecked(name);
result.capture_names.push(name.to_string());
}
}
// Build a vector to store capture qunatifiers.
for i in 0..pattern_count {
let mut capture_quantifiers = Vec::with_capacity(capture_count as usize);
for j in 0..capture_count {
unsafe {
let quantifier = ts_query_capture_quantifier_for_id(ptr, i as u32, j);
capture_quantifiers.push(quantifier.into());
}
}
result.capture_quantifiers.push(capture_quantifiers);
}
// Build a vector of strings to represent literal values used in predicates.
let string_values = (0..string_count)
.map(|i| unsafe {
let mut length = 0u32;
let value = ts_query_string_value_for_id(ptr, i as u32, &mut length as *mut u32)
as *const u8;
let value = slice::from_raw_parts(value, length as usize);
let value = str::from_utf8_unchecked(value);
value.to_string()
})
.collect::<Vec<_>>();
// Build a vector of predicates for each pattern.
for i in 0..pattern_count {
let predicate_steps = unsafe {
let mut length = 0u32;
let raw_predicates =
ts_query_predicates_for_pattern(ptr, i as u32, &mut length as *mut u32);
if length > 0 {
slice::from_raw_parts(raw_predicates, length as usize)
} else {
&[]
}
};
let byte_offset = unsafe { ts_query_start_byte_for_pattern(ptr, i as u32) };
let row = source
.char_indices()
.take_while(|(i, _)| *i < byte_offset as usize)
.filter(|(_, c)| *c == '\n')
.count();
let type_done = TSQueryPredicateStepType_TSQueryPredicateStepTypeDone;
let type_capture = TSQueryPredicateStepType_TSQueryPredicateStepTypeCapture;
let type_string = TSQueryPredicateStepType_TSQueryPredicateStepTypeString;
let mut text_predicates = Vec::new();
let mut property_predicates = Vec::new();
let mut property_settings = Vec::new();
let mut general_predicates = Vec::new();
for p in predicate_steps.split(|s| s.type_ == type_done) {
if p.is_empty() {
continue;
}
if p[0].type_ != type_string {
return Err(predicate_error(
row,
format!(
"Expected predicate to start with a function name. Got @{}.",
result.capture_names[p[0].value_id as usize],
),
));
}
// Build a predicate for each of the known predicate function names.
let operator_name = &string_values[p[0].value_id as usize];
match operator_name.as_str() {
"eq?" | "not-eq?" => {
if p.len() != 3 {
return Err(predicate_error(
row,
format!(
"Wrong number of arguments to #eq? predicate. Expected 2, got {}.",
p.len() - 1
),
));
}
if p[1].type_ != type_capture {
return Err(predicate_error(row, format!(
"First argument to #eq? predicate must be a capture name. Got literal \"{}\".",
string_values[p[1].value_id as usize],
)));
}
let is_positive = operator_name == "eq?";
text_predicates.push(if p[2].type_ == type_capture {
TextPredicate::CaptureEqCapture(
p[1].value_id,
p[2].value_id,
is_positive,
)
} else {
TextPredicate::CaptureEqString(
p[1].value_id,
string_values[p[2].value_id as usize].clone(),
is_positive,
)
});
}
"match?" | "not-match?" => {
if p.len() != 3 {
return Err(predicate_error(row, format!(
"Wrong number of arguments to #match? predicate. Expected 2, got {}.",
p.len() - 1
)));
}
if p[1].type_ != type_capture {
return Err(predicate_error(row, format!(
"First argument to #match? predicate must be a capture name. Got literal \"{}\".",
string_values[p[1].value_id as usize],
)));
}
if p[2].type_ == type_capture {
return Err(predicate_error(row, format!(
"Second argument to #match? predicate must be a literal. Got capture @{}.",
result.capture_names[p[2].value_id as usize],
)));
}
let is_positive = operator_name == "match?";
let regex = &string_values[p[2].value_id as usize];
text_predicates.push(TextPredicate::CaptureMatchString(
p[1].value_id,
regex::bytes::Regex::new(regex).map_err(|_| {
predicate_error(row, format!("Invalid regex '{}'", regex))
})?,
is_positive,
));
}
"set!" => property_settings.push(Self::parse_property(
row,
&operator_name,
&result.capture_names,
&string_values,
&p[1..],
)?),
"is?" | "is-not?" => property_predicates.push((
Self::parse_property(
row,
&operator_name,
&result.capture_names,
&string_values,
&p[1..],
)?,
operator_name == "is?",
)),
_ => general_predicates.push(QueryPredicate {
operator: operator_name.clone().into_boxed_str(),
args: p[1..]
.iter()
.map(|a| {
if a.type_ == type_capture {
QueryPredicateArg::Capture(a.value_id)
} else {
QueryPredicateArg::String(
string_values[a.value_id as usize].clone().into_boxed_str(),
)
}
})
.collect(),
}),
}
}
result
.text_predicates
.push(text_predicates.into_boxed_slice());
result
.property_predicates
.push(property_predicates.into_boxed_slice());
result
.property_settings
.push(property_settings.into_boxed_slice());
result
.general_predicates
.push(general_predicates.into_boxed_slice());
}
Ok(result)
}
/// Consumes the [Query], returning a raw pointer to the underlying C structure.
pub fn into_raw(self) -> *mut TSQuery {
ManuallyDrop::new(self).ptr.as_ptr()
@ -57,6 +324,17 @@ impl Query {
}
impl QueryCursor {
/// Reconstructs a [QueryCursor] from a raw pointer.
///
/// # Safety
///
/// `ptr` must be non-null.
pub unsafe fn from_raw(ptr: *mut TSQueryCursor) -> QueryCursor {
QueryCursor {
ptr: NonNull::new_unchecked(ptr),
}
}
/// Consumes the [QueryCursor], returning a raw pointer to the underlying C structure.
pub fn into_raw(self) -> *mut TSQueryCursor {
ManuallyDrop::new(self).ptr.as_ptr()

View file

@ -1434,217 +1434,7 @@ impl Query {
});
}
let string_count = unsafe { ffi::ts_query_string_count(ptr) };
let capture_count = unsafe { ffi::ts_query_capture_count(ptr) };
let pattern_count = unsafe { ffi::ts_query_pattern_count(ptr) as usize };
let mut result = Query {
ptr: unsafe { NonNull::new_unchecked(ptr) },
capture_names: Vec::with_capacity(capture_count as usize),
capture_quantifiers: Vec::with_capacity(pattern_count as usize),
text_predicates: Vec::with_capacity(pattern_count),
property_predicates: Vec::with_capacity(pattern_count),
property_settings: Vec::with_capacity(pattern_count),
general_predicates: Vec::with_capacity(pattern_count),
};
// Build a vector of strings to store the capture names.
for i in 0..capture_count {
unsafe {
let mut length = 0u32;
let name =
ffi::ts_query_capture_name_for_id(ptr, i, &mut length as *mut u32) as *const u8;
let name = slice::from_raw_parts(name, length as usize);
let name = str::from_utf8_unchecked(name);
result.capture_names.push(name.to_string());
}
}
// Build a vector to store capture qunatifiers.
for i in 0..pattern_count {
let mut capture_quantifiers = Vec::with_capacity(capture_count as usize);
for j in 0..capture_count {
unsafe {
let quantifier = ffi::ts_query_capture_quantifier_for_id(ptr, i as u32, j);
capture_quantifiers.push(quantifier.into());
}
}
result.capture_quantifiers.push(capture_quantifiers);
}
// Build a vector of strings to represent literal values used in predicates.
let string_values = (0..string_count)
.map(|i| unsafe {
let mut length = 0u32;
let value =
ffi::ts_query_string_value_for_id(ptr, i as u32, &mut length as *mut u32)
as *const u8;
let value = slice::from_raw_parts(value, length as usize);
let value = str::from_utf8_unchecked(value);
value.to_string()
})
.collect::<Vec<_>>();
// Build a vector of predicates for each pattern.
for i in 0..pattern_count {
let predicate_steps = unsafe {
let mut length = 0u32;
let raw_predicates =
ffi::ts_query_predicates_for_pattern(ptr, i as u32, &mut length as *mut u32);
if length > 0 {
slice::from_raw_parts(raw_predicates, length as usize)
} else {
&[]
}
};
let byte_offset = unsafe { ffi::ts_query_start_byte_for_pattern(ptr, i as u32) };
let row = source
.char_indices()
.take_while(|(i, _)| *i < byte_offset as usize)
.filter(|(_, c)| *c == '\n')
.count();
let type_done = ffi::TSQueryPredicateStepType_TSQueryPredicateStepTypeDone;
let type_capture = ffi::TSQueryPredicateStepType_TSQueryPredicateStepTypeCapture;
let type_string = ffi::TSQueryPredicateStepType_TSQueryPredicateStepTypeString;
let mut text_predicates = Vec::new();
let mut property_predicates = Vec::new();
let mut property_settings = Vec::new();
let mut general_predicates = Vec::new();
for p in predicate_steps.split(|s| s.type_ == type_done) {
if p.is_empty() {
continue;
}
if p[0].type_ != type_string {
return Err(predicate_error(
row,
format!(
"Expected predicate to start with a function name. Got @{}.",
result.capture_names[p[0].value_id as usize],
),
));
}
// Build a predicate for each of the known predicate function names.
let operator_name = &string_values[p[0].value_id as usize];
match operator_name.as_str() {
"eq?" | "not-eq?" => {
if p.len() != 3 {
return Err(predicate_error(
row,
format!(
"Wrong number of arguments to #eq? predicate. Expected 2, got {}.",
p.len() - 1
),
));
}
if p[1].type_ != type_capture {
return Err(predicate_error(row, format!(
"First argument to #eq? predicate must be a capture name. Got literal \"{}\".",
string_values[p[1].value_id as usize],
)));
}
let is_positive = operator_name == "eq?";
text_predicates.push(if p[2].type_ == type_capture {
TextPredicate::CaptureEqCapture(
p[1].value_id,
p[2].value_id,
is_positive,
)
} else {
TextPredicate::CaptureEqString(
p[1].value_id,
string_values[p[2].value_id as usize].clone(),
is_positive,
)
});
}
"match?" | "not-match?" => {
if p.len() != 3 {
return Err(predicate_error(row, format!(
"Wrong number of arguments to #match? predicate. Expected 2, got {}.",
p.len() - 1
)));
}
if p[1].type_ != type_capture {
return Err(predicate_error(row, format!(
"First argument to #match? predicate must be a capture name. Got literal \"{}\".",
string_values[p[1].value_id as usize],
)));
}
if p[2].type_ == type_capture {
return Err(predicate_error(row, format!(
"Second argument to #match? predicate must be a literal. Got capture @{}.",
result.capture_names[p[2].value_id as usize],
)));
}
let is_positive = operator_name == "match?";
let regex = &string_values[p[2].value_id as usize];
text_predicates.push(TextPredicate::CaptureMatchString(
p[1].value_id,
regex::bytes::Regex::new(regex).map_err(|_| {
predicate_error(row, format!("Invalid regex '{}'", regex))
})?,
is_positive,
));
}
"set!" => property_settings.push(Self::parse_property(
row,
&operator_name,
&result.capture_names,
&string_values,
&p[1..],
)?),
"is?" | "is-not?" => property_predicates.push((
Self::parse_property(
row,
&operator_name,
&result.capture_names,
&string_values,
&p[1..],
)?,
operator_name == "is?",
)),
_ => general_predicates.push(QueryPredicate {
operator: operator_name.clone().into_boxed_str(),
args: p[1..]
.iter()
.map(|a| {
if a.type_ == type_capture {
QueryPredicateArg::Capture(a.value_id)
} else {
QueryPredicateArg::String(
string_values[a.value_id as usize].clone().into_boxed_str(),
)
}
})
.collect(),
}),
}
}
result
.text_predicates
.push(text_predicates.into_boxed_slice());
result
.property_predicates
.push(property_predicates.into_boxed_slice());
result
.property_settings
.push(property_settings.into_boxed_slice());
result
.general_predicates
.push(general_predicates.into_boxed_slice());
}
Ok(result)
unsafe { Query::from_raw(ptr, source) }
}
/// Get the byte offset where the given pattern starts in the query's source.
@ -2291,7 +2081,7 @@ impl<'a> Iterator for LossyUtf8<'a> {
}
}
fn predicate_error(row: usize, message: String) -> QueryError {
pub(crate) fn predicate_error(row: usize, message: String) -> QueryError {
QueryError {
kind: QueryErrorKind::Predicate,
row,