use crate::state::LuaState;
use lua_types::error::LuaError;
pub(crate) const EOZ: i32 = -1;
pub type ChunkReader = Box<dyn FnMut(&mut LuaState) -> Result<Option<Vec<u8>>, LuaError>>;
pub struct LexBuffer {
buffer: Vec<u8>,
}
impl LexBuffer {
pub fn new() -> Self {
LexBuffer { buffer: Vec::new() }
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.buffer
}
pub fn capacity(&self) -> usize {
self.buffer.capacity()
}
pub fn len(&self) -> usize {
self.buffer.len()
}
pub fn truncate_by(&mut self, i: usize) {
let new_len = self.buffer.len().saturating_sub(i);
self.buffer.truncate(new_len);
}
pub fn clear(&mut self) {
self.buffer.clear();
}
pub fn resize(&mut self, _state: &mut LuaState, size: usize) -> Result<(), LuaError> {
self.buffer.resize(size, 0u8);
Ok(())
}
}
impl Default for LexBuffer {
fn default() -> Self {
Self::new()
}
}
pub struct ZIO {
n: usize,
p: usize,
reader: ChunkReader,
current_chunk: Vec<u8>,
}
impl ZIO {
pub fn new(reader: ChunkReader) -> Self {
ZIO {
n: 0,
p: 0,
current_chunk: Vec::new(),
reader,
}
}
pub fn from_bytes(bytes: Vec<u8>) -> Self {
let mut once = Some(bytes);
ZIO::new(Box::new(move |_state| Ok(once.take())))
}
pub fn take(&mut self) -> ZIO {
std::mem::replace(self, ZIO::from_bytes(Vec::new()))
}
pub(crate) fn fill(&mut self, state: &mut LuaState) -> Result<i32, LuaError> {
let chunk_opt = (self.reader)(state)?;
match chunk_opt {
None => Ok(EOZ),
Some(chunk) if chunk.is_empty() => Ok(EOZ),
Some(chunk) => {
self.n = chunk.len() - 1;
self.current_chunk = chunk;
self.p = 0;
let byte = self.current_chunk[self.p] as u8;
self.p += 1;
Ok(byte as i32)
}
}
}
#[inline]
pub fn getc(&mut self, state: &mut LuaState) -> Result<i32, LuaError> {
if self.n > 0 {
self.n -= 1;
let byte = self.current_chunk[self.p] as u8;
self.p += 1;
Ok(byte as i32)
} else {
self.fill(state)
}
}
pub(crate) fn read(&mut self, state: &mut LuaState, buf: &mut [u8]) -> Result<usize, LuaError> {
let mut remaining = buf.len();
let mut dst: usize = 0;
while remaining > 0 {
if self.n == 0 {
if self.fill(state)? == EOZ {
return Ok(remaining);
} else {
self.n += 1;
self.p -= 1;
}
}
let m = remaining.min(self.n);
buf[dst..dst + m].copy_from_slice(&self.current_chunk[self.p..self.p + m]);
self.n -= m;
self.p += m;
dst += m;
remaining -= m;
}
Ok(0)
}
}