use ropey::Rope;
use tree_sitter_c2rust::Node;
use tree_sitter_c2rust::TextProvider;
pub struct RopeProvider<'a>(pub &'a Rope);
impl<'a> TextProvider<&'a [u8]> for RopeProvider<'a> {
type I = ChunksBytes<'a>;
fn text(&mut self, node: Node) -> Self::I {
let fragment = self.0.byte_slice(node.start_byte()..node.end_byte());
ChunksBytes {
chunks: fragment.chunks(),
}
}
}
impl<'a> RopeProvider<'a> {
#[must_use]
pub fn new(value: &'a Rope) -> Self {
RopeProvider(value)
}
#[must_use]
pub fn chunk_callback(&self, byte_idx: usize) -> &[u8] {
if byte_idx > self.0.len_bytes() {
return b""; }
let (chunk, chunk_byte_idx, _, _) = self.0.chunk_at_byte(byte_idx);
let start = byte_idx - chunk_byte_idx;
&chunk.as_bytes()[start..]
}
}
impl<'a> From<&'a Rope> for RopeProvider<'a> {
fn from(value: &'a Rope) -> Self {
RopeProvider::new(value)
}
}
pub struct ChunksBytes<'a> {
chunks: ropey::iter::Chunks<'a>,
}
impl<'a> Iterator for ChunksBytes<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
self.chunks.next().map(str::as_bytes)
}
}
#[cfg(test)]
mod tests {
use super::*;
use test_log::test;
#[test]
fn test_rope_chunk_callback() {
let rope = Rope::from_str("0123456789".repeat(10000).as_str());
let rope_provider = RopeProvider::new(&rope);
let chunk = rope_provider.chunk_callback(5);
assert_eq!(chunk.len(), 984 - 5);
assert!(chunk.starts_with(b"5678"));
}
#[test]
fn test_rope_chunk_callback_end() {
let rope = Rope::from_str("");
let rope_provider = RopeProvider::new(&rope);
let chunk = rope_provider.chunk_callback(1);
assert_eq!(chunk.len(), 0);
}
}