#![allow(unsafe_code)]
use hermes_support::buffer::SourceBuffer;
use std::rc::Rc;
pub struct Cursor {
buffer: Rc<SourceBuffer>,
start: *const u8,
cur: *const u8,
end: *const u8,
}
impl Cursor {
pub fn new(buffer: Rc<SourceBuffer>) -> Cursor {
let raw = buffer.raw(); let n = buffer.bytes().len(); let start = raw.as_ptr();
let end = unsafe { start.add(n) };
Cursor {
buffer,
start,
cur: start,
end,
}
}
#[inline]
pub fn offset(&self) -> u32 {
(unsafe { self.cur.offset_from(self.start) }) as u32
}
#[inline]
pub fn at_end(&self) -> bool {
self.cur >= self.end
}
#[inline]
pub fn peek(&self) -> u8 {
unsafe { *self.cur }
}
#[inline]
pub fn peek_at(&self, n: usize) -> u8 {
unsafe { *self.cur.add(n) }
}
#[inline]
pub fn advance(&mut self, n: usize) {
unsafe {
self.cur = self.cur.add(n);
}
}
#[inline]
pub fn seek(&mut self, offset: u32) {
unsafe {
self.cur = self.start.add(offset as usize);
}
}
#[inline]
pub fn seek_end(&mut self) {
self.cur = self.end;
}
#[inline]
pub fn slice_from(&self, from_offset: u32) -> &[u8] {
&self.buffer.raw()[from_offset as usize..self.offset() as usize]
}
#[inline]
pub fn slice(&self, from_offset: u32, to_offset: u32) -> &[u8] {
&self.buffer.raw()[from_offset as usize..to_offset as usize]
}
#[inline]
pub fn raw(&self) -> &[u8] {
self.buffer.raw()
}
pub fn peek_utf8(&self) -> (u32, u32) {
let bytes = self.raw();
let mut i = self.offset() as usize;
let cp = crate::utf8::decode_utf8::<false>(bytes, &mut i, |_| {});
(cp, i as u32)
}
pub fn buffer(&self) -> &Rc<SourceBuffer> {
&self.buffer
}
}
#[cfg(test)]
mod tests {
use super::*;
use hermes_support::buffer::SourceBuffer;
use std::rc::Rc;
fn cur(s: &str) -> Cursor {
Cursor::new(Rc::new(SourceBuffer::from_str("t", s)))
}
#[test]
fn basic() {
let mut c = cur("ab");
assert_eq!(c.offset(), 0);
assert_eq!(c.peek(), b'a');
assert_eq!(c.peek_at(1), b'b');
assert_eq!(c.peek_at(2), 0); assert!(!c.at_end());
c.advance(1);
assert_eq!(c.offset(), 1);
assert_eq!(c.peek(), b'b');
c.advance(1);
assert_eq!(c.peek(), 0);
assert!(c.at_end());
}
#[test]
fn peek_utf8_no_advance() {
let c = cur("\u{4e2d}x"); let (cp, next) = c.peek_utf8();
assert_eq!(cp, 0x4E2D);
assert_eq!(next, 3); assert_eq!(c.offset(), 0); }
#[test]
fn slicing_and_seek() {
let mut c = cur("hello");
c.advance(2);
assert_eq!(c.slice_from(0), b"he"); c.seek(4);
assert_eq!(c.offset(), 4);
assert_eq!(c.peek(), b'o');
}
}