From d96ba093915598b35cb097e34edee5cae9cef3df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tu=E1=BA=A5n-Anh=20Nguy=E1=BB=85n?= Date: Tue, 27 Aug 2019 09:36:16 +0700 Subject: [PATCH] Make Tree::changed_ranges return an Iterator instead of a Vec (#437) * Make Tree::changed_ranges return an Iterator instead of a Vec * Remove CBufferIter.free parameter --- cli/src/tests/corpus_test.rs | 2 +- cli/src/tests/parser_test.rs | 4 ++-- cli/src/tests/tree_test.rs | 2 +- lib/binding_rust/lib.rs | 22 +++++++-------------- lib/binding_rust/util.rs | 38 ++++++++++++++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 19 deletions(-) create mode 100644 lib/binding_rust/util.rs diff --git a/cli/src/tests/corpus_test.rs b/cli/src/tests/corpus_test.rs index 19c90e19..a8adce5f 100644 --- a/cli/src/tests/corpus_test.rs +++ b/cli/src/tests/corpus_test.rs @@ -337,7 +337,7 @@ fn check_consistent_sizes(tree: &Tree, input: &Vec) { } fn check_changed_ranges(old_tree: &Tree, new_tree: &Tree, input: &Vec) -> Result<(), String> { - let changed_ranges = old_tree.changed_ranges(new_tree); + let changed_ranges = old_tree.changed_ranges(new_tree).collect(); let old_scope_sequence = ScopeSequence::new(old_tree); let new_scope_sequence = ScopeSequence::new(new_tree); old_scope_sequence.check_changes(&new_scope_sequence, &input, &changed_ranges) diff --git a/cli/src/tests/parser_test.rs b/cli/src/tests/parser_test.rs index 184afd04..96b08af0 100644 --- a/cli/src/tests/parser_test.rs +++ b/cli/src/tests/parser_test.rs @@ -767,7 +767,7 @@ fn test_parsing_with_a_newly_excluded_range() { ); assert_eq!( - tree.changed_ranges(&first_tree), + tree.changed_ranges(&first_tree).collect::>(), vec![ // The first range that has changed syntax is the range of the newly-inserted text. Range { @@ -837,7 +837,7 @@ fn test_parsing_with_a_newly_included_range() { ); assert_eq!( - tree.changed_ranges(&first_tree), + tree.changed_ranges(&first_tree).collect::>(), vec![Range { start_byte: first_code_end_index + 1, end_byte: second_code_end_index + 1, diff --git a/cli/src/tests/tree_test.rs b/cli/src/tests/tree_test.rs index e22ce18e..b4e8ce7c 100644 --- a/cli/src/tests/tree_test.rs +++ b/cli/src/tests/tree_test.rs @@ -370,7 +370,7 @@ fn get_changed_ranges( ) -> Vec { perform_edit(tree, source_code, &edit); let new_tree = parser.parse(&source_code, Some(tree)).unwrap(); - let result = tree.changed_ranges(&new_tree); + let result = tree.changed_ranges(&new_tree).collect(); *tree = new_tree; result } diff --git a/lib/binding_rust/lib.rs b/lib/binding_rust/lib.rs index 208c45e3..23315ea4 100644 --- a/lib/binding_rust/lib.rs +++ b/lib/binding_rust/lib.rs @@ -1,4 +1,5 @@ mod ffi; +mod util; #[macro_use] extern crate serde_derive; @@ -16,7 +17,7 @@ use std::ffi::CStr; use std::marker::PhantomData; use std::os::raw::{c_char, c_void}; use std::sync::atomic::AtomicUsize; -use std::{fmt, ptr, slice, str, u16}; +use std::{fmt, ptr, str, u16}; pub const LANGUAGE_VERSION: usize = ffi::TREE_SITTER_LANGUAGE_VERSION; pub const PARSER_HEADER: &'static str = include_str!("../include/tree_sitter/parser.h"); @@ -447,15 +448,11 @@ impl Tree { TreePropertyCursor::new(self, property_sheet, source) } - pub fn changed_ranges(&self, other: &Tree) -> Vec { + pub fn changed_ranges(&self, other: &Tree) -> impl Iterator { + let mut count = 0; unsafe { - let mut count = 0; - let ptr = - ffi::ts_tree_get_changed_ranges(self.0, other.0, &mut count as *mut _ as *mut u32); - let ranges = slice::from_raw_parts(ptr, count); - let result = ranges.into_iter().map(|r| r.clone().into()).collect(); - free_ptr(ptr as *mut c_void); - result + let ptr = ffi::ts_tree_get_changed_ranges(self.0, other.0, &mut count as *mut _ as *mut u32); + util::CBufferIter::new(ptr, count).map(|r| r.into()) } } } @@ -638,7 +635,7 @@ impl<'tree> Node<'tree> { .to_str() .unwrap() .to_string(); - unsafe { free_ptr(c_string as *mut c_void) }; + unsafe { util::free_ptr(c_string as *mut c_void) }; result } @@ -1072,8 +1069,3 @@ impl std::error::Error for PropertySheetError { } } } - -extern "C" { - #[link_name = "rust_tree_sitter_free"] - fn free_ptr(ptr: *mut c_void); -} diff --git a/lib/binding_rust/util.rs b/lib/binding_rust/util.rs new file mode 100644 index 00000000..df73f830 --- /dev/null +++ b/lib/binding_rust/util.rs @@ -0,0 +1,38 @@ +use std::os::raw::c_void; + +extern "C" { + #[link_name = "rust_tree_sitter_free"] + pub fn free_ptr(ptr: *mut c_void); +} + +pub struct CBufferIter { + ptr: *mut T, + count: usize, + i: usize, +} + +impl CBufferIter { + pub unsafe fn new(ptr: *mut T, count: usize) -> Self { + Self { ptr, count, i: 0 } + } +} + +impl Iterator for CBufferIter { + type Item = T; + + fn next(&mut self) -> Option { + let i = self.i; + self.i += 1; + if i >= self.count { + None + } else { + Some(unsafe { *self.ptr.offset(i as isize) }) + } + } +} + +impl Drop for CBufferIter { + fn drop(&mut self) { + unsafe { free_ptr(self.ptr as *mut c_void); } + } +}