Reduce code redundancy by using `RawParser` and `RawParserExt`
Also added changelognext
parent
20f039cb85
commit
231dd53341
@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* Created on Tue May 03 2022
|
||||||
|
*
|
||||||
|
* This file is a part of Skytable
|
||||||
|
* Skytable (formerly known as TerrabaseDB or Skybase) is a free and open-source
|
||||||
|
* NoSQL database written by Sayan Nandan ("the Author") with the
|
||||||
|
* vision to provide flexibility in data modelling without compromising
|
||||||
|
* on performance, queryability or scalability.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022, Sayan Nandan <ohsayan@outlook.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
use {
|
||||||
|
super::{ParseError, ParseResult, UnsafeSlice},
|
||||||
|
core::mem::transmute,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The `RawParser` trait has three methods that implementors must define:
|
||||||
|
/// - `cursor_ptr` -> Should point to the current position in the buffer for the parser
|
||||||
|
/// - `cursor_ptr_mut` -> a mutable reference to the cursor
|
||||||
|
/// - `data_end_ptr` -> a ptr to one byte past the allocated area of the buffer
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// - `cursor_ptr` must point to a valid location in memory
|
||||||
|
/// - `data_end_ptr` must point to a valid location in memory, in the **same allocated area**
|
||||||
|
pub(super) unsafe trait RawParser {
|
||||||
|
fn cursor_ptr(&self) -> *const u8;
|
||||||
|
fn cursor_ptr_mut(&mut self) -> &mut *const u8;
|
||||||
|
fn data_end_ptr(&self) -> *const u8;
|
||||||
|
/// Check how many bytes we have left
|
||||||
|
fn remaining(&self) -> usize {
|
||||||
|
self.data_end_ptr() as usize - self.cursor_ptr() as usize
|
||||||
|
}
|
||||||
|
/// Check if we have `size` bytes remaining
|
||||||
|
fn has_remaining(&self, size: usize) -> bool {
|
||||||
|
self.remaining() >= size
|
||||||
|
}
|
||||||
|
/// Check if we have exhausted the buffer
|
||||||
|
fn exhausted(&self) -> bool {
|
||||||
|
self.cursor_ptr() >= self.data_end_ptr()
|
||||||
|
}
|
||||||
|
/// Check if the buffer is not exhausted
|
||||||
|
fn not_exhausted(&self) -> bool {
|
||||||
|
self.cursor_ptr() < self.data_end_ptr()
|
||||||
|
}
|
||||||
|
/// Attempts to return the byte pointed at by the cursor.
|
||||||
|
/// WARNING: The same segfault warning
|
||||||
|
unsafe fn get_byte_at_cursor(&self) -> u8 {
|
||||||
|
*self.cursor_ptr()
|
||||||
|
}
|
||||||
|
/// Increment the cursor by `by` positions
|
||||||
|
unsafe fn incr_cursor_by(&mut self, by: usize) {
|
||||||
|
let current = *self.cursor_ptr_mut();
|
||||||
|
*self.cursor_ptr_mut() = current.add(by);
|
||||||
|
}
|
||||||
|
/// Increment the position of the cursor by one position
|
||||||
|
unsafe fn incr_cursor(&mut self) {
|
||||||
|
self.incr_cursor_by(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) trait RawParserExt: RawParser {
|
||||||
|
/// Attempt to read `len` bytes
|
||||||
|
fn read_until(&mut self, len: usize) -> ParseResult<UnsafeSlice> {
|
||||||
|
if self.has_remaining(len) {
|
||||||
|
unsafe {
|
||||||
|
// UNSAFE(@ohsayan): Already verified lengths
|
||||||
|
let slice = UnsafeSlice::new(self.cursor_ptr(), len);
|
||||||
|
self.incr_cursor_by(len);
|
||||||
|
Ok(slice)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(ParseError::NotEnough)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(test)]
|
||||||
|
/// Attempt to read a byte slice terminated by an LF
|
||||||
|
fn read_line(&mut self) -> ParseResult<UnsafeSlice> {
|
||||||
|
let start_ptr = self.cursor_ptr();
|
||||||
|
unsafe {
|
||||||
|
while self.not_exhausted() && self.get_byte_at_cursor() != b'\n' {
|
||||||
|
self.incr_cursor();
|
||||||
|
}
|
||||||
|
if self.not_exhausted() && self.get_byte_at_cursor() == b'\n' {
|
||||||
|
let len = self.cursor_ptr() as usize - start_ptr as usize;
|
||||||
|
self.incr_cursor(); // skip LF
|
||||||
|
Ok(UnsafeSlice::new(start_ptr, len))
|
||||||
|
} else {
|
||||||
|
Err(ParseError::NotEnough)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Attempt to read a line, **rejecting an empty payload**
|
||||||
|
fn read_line_pedantic(&mut self) -> ParseResult<UnsafeSlice> {
|
||||||
|
let start_ptr = self.cursor_ptr();
|
||||||
|
unsafe {
|
||||||
|
while self.not_exhausted() && self.get_byte_at_cursor() != b'\n' {
|
||||||
|
self.incr_cursor();
|
||||||
|
}
|
||||||
|
let len = self.cursor_ptr() as usize - start_ptr as usize;
|
||||||
|
let has_lf = self.not_exhausted() && self.get_byte_at_cursor() == b'\n';
|
||||||
|
if has_lf && len != 0 {
|
||||||
|
self.incr_cursor(); // skip LF
|
||||||
|
Ok(UnsafeSlice::new(start_ptr, len))
|
||||||
|
} else {
|
||||||
|
// just some silly hackery
|
||||||
|
Err(transmute(has_lf))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Attempt to read an `usize` from the buffer
|
||||||
|
fn read_usize(&mut self) -> ParseResult<usize> {
|
||||||
|
let line = self.read_line_pedantic()?;
|
||||||
|
let bytes = line.as_slice();
|
||||||
|
let mut ret = 0usize;
|
||||||
|
for byte in bytes {
|
||||||
|
if byte.is_ascii_digit() {
|
||||||
|
ret = match ret.checked_mul(10) {
|
||||||
|
Some(r) => r,
|
||||||
|
None => return Err(ParseError::DatatypeParseFailure),
|
||||||
|
};
|
||||||
|
ret = match ret.checked_add((byte & 0x0F) as _) {
|
||||||
|
Some(r) => r,
|
||||||
|
None => return Err(ParseError::DatatypeParseFailure),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return Err(ParseError::DatatypeParseFailure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> RawParserExt for T where T: RawParser {}
|
Loading…
Reference in New Issue