use super::{borrowed::BorrowedBytesBlockIterator, error::InputError, *};
use crate::query::JsonString;
use std::{alloc, ptr, slice};
pub struct OwnedBytes {
bytes_ptr: ptr::NonNull<u8>,
len: usize,
capacity: usize,
last_block: LastBlock,
}
impl OwnedBytes {
unsafe fn finalize_new(ptr: ptr::NonNull<u8>, len: usize, cap: usize) -> Self {
let slice = slice::from_raw_parts(ptr.as_ptr(), len);
let last_block = in_slice::pad_last_block(slice);
Self {
bytes_ptr: ptr,
len,
capacity: cap,
last_block,
}
}
#[must_use]
#[inline(always)]
pub fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.bytes_ptr.as_ptr(), self.len) }
}
#[must_use]
#[inline(always)]
pub fn as_borrowed(&self) -> BorrowedBytes {
unsafe { BorrowedBytes::new(self.as_slice()) }
}
#[must_use]
#[inline(always)]
pub unsafe fn from_raw_parts(ptr: ptr::NonNull<u8>, size: usize) -> Self {
Self::finalize_new(ptr, size, size)
}
#[inline]
pub fn new<T: AsRef<[u8]>>(src: &T) -> Result<Self, InputError> {
let slice = src.as_ref();
let rem = slice.len() % MAX_BLOCK_SIZE;
let pad = if rem == 0 { 0 } else { MAX_BLOCK_SIZE - rem };
let size = slice.len() + pad;
if size == 0 {
return Ok(unsafe { Self::finalize_new(ptr::NonNull::dangling(), 0, 0) });
}
let layout = Self::get_layout(size)?;
let raw_ptr = unsafe { alloc::alloc(layout) };
let ptr = ptr::NonNull::new(raw_ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout));
unsafe {
ptr::copy_nonoverlapping(slice.as_ptr(), ptr.as_ptr(), slice.len());
ptr::write_bytes(ptr.as_ptr().add(slice.len()), 0, pad);
};
Ok(unsafe { Self::finalize_new(ptr, size, size) })
}
#[inline]
#[must_use]
pub unsafe fn new_unchecked<T: AsRef<[u8]>>(src: &T) -> Self {
let slice = src.as_ref();
let size = slice.len();
if size == 0 {
return Self::finalize_new(ptr::NonNull::dangling(), 0, 0);
}
let layout = Self::get_layout(size).unwrap_unchecked();
let raw_ptr = alloc::alloc(layout);
let ptr = ptr::NonNull::new(raw_ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout));
ptr::copy_nonoverlapping(slice.as_ptr(), ptr.as_ptr(), slice.len());
Self::finalize_new(ptr, size, size)
}
#[inline(always)]
fn get_layout(size: usize) -> Result<alloc::Layout, InputError> {
alloc::Layout::from_size_align(size, MAX_BLOCK_SIZE).map_err(|_err| InputError::AllocationSizeExceeded)
}
}
impl TryFrom<String> for OwnedBytes {
type Error = InputError;
#[inline]
fn try_from(value: String) -> Result<Self, Self::Error> {
Self::try_from(value.into_bytes())
}
}
impl TryFrom<Vec<u8>> for OwnedBytes {
type Error = InputError;
#[inline]
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
Self::new(&value)
}
}
impl TryFrom<&[u8]> for OwnedBytes {
type Error = InputError;
#[inline(always)]
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
Self::new(&value)
}
}
impl<'a> From<&BorrowedBytes<'a>> for OwnedBytes {
#[inline(always)]
fn from(value: &BorrowedBytes) -> Self {
unsafe { Self::new_unchecked(value) }
}
}
impl TryFrom<&str> for OwnedBytes {
type Error = InputError;
#[inline(always)]
fn try_from(value: &str) -> Result<Self, Self::Error> {
Self::try_from(value.as_bytes())
}
}
impl Drop for OwnedBytes {
#[inline]
fn drop(&mut self) {
if self.len == 0 {
return;
}
#[allow(clippy::expect_used)]
let layout = Self::get_layout(self.capacity).expect("layout for existing OwnedBytes must never change");
unsafe { alloc::dealloc(self.bytes_ptr.as_ptr(), layout) }
}
}
impl Input for OwnedBytes {
type BlockIterator<'a, 'r, const N: usize, R> = BorrowedBytesBlockIterator<'a, 'r, N, R>
where R: InputRecorder<&'a [u8]> + 'r;
type Block<'a, const N: usize> = &'a [u8];
#[inline(always)]
fn iter_blocks<'a, 'r, R, const N: usize>(&'a self, recorder: &'r R) -> Self::BlockIterator<'a, 'r, N, R>
where
R: InputRecorder<&'a [u8]>,
{
BorrowedBytesBlockIterator::new(self.as_slice(), &self.last_block, recorder)
}
#[inline]
fn seek_backward(&self, from: usize, needle: u8) -> Option<usize> {
in_slice::seek_backward(self.as_slice(), from, needle)
}
#[inline]
fn seek_forward<const N: usize>(&self, from: usize, needles: [u8; N]) -> Result<Option<(usize, u8)>, InputError> {
Ok(in_slice::seek_forward(self.as_slice(), from, needles))
}
#[inline]
fn seek_non_whitespace_forward(&self, from: usize) -> Result<Option<(usize, u8)>, InputError> {
Ok(in_slice::seek_non_whitespace_forward(self.as_slice(), from))
}
#[inline]
fn seek_non_whitespace_backward(&self, from: usize) -> Option<(usize, u8)> {
in_slice::seek_non_whitespace_backward(self.as_slice(), from)
}
#[inline]
fn find_member(&self, from: usize, label: &JsonString) -> Result<Option<usize>, InputError> {
Ok(in_slice::find_member(self.as_slice(), from, label))
}
#[inline]
fn is_member_match(&self, from: usize, to: usize, label: &JsonString) -> bool {
in_slice::is_member_match(self.as_slice(), from, to, label)
}
}