#![cfg_attr(not(feature="std"), no_std)]
#[cfg(not(feature="std"))]
extern crate alloc;
#[cfg(not(feature="std"))]
use alloc::alloc::{alloc, dealloc, Layout};
#[cfg(feature="std")]
use std::alloc::{alloc, dealloc, Layout};
use core::ops::{Deref, DerefMut};
use core::ptr;
use core::slice;
use core::str;
use core::fmt;
#[allow(unused)]
const STATIC: u8 = 0;
const INLINE: u8 = 1;
const BOXED: u8 = 2;
const DETERMINANT_BITS: u8 = 2; const INLINE_SIZE_BITS: u8 = (2 * size_of::<usize>()).ilog2() as u8;
const DETERMINANT_MASK: u8 = (1u8 << DETERMINANT_BITS) - 1; const INLINE_SIZE_MASK: u8 = (1u8 << INLINE_SIZE_BITS) - 1;
#[cfg(target_endian="little")]
const DETERMINANT_SHIFT: u8 = usize::BITS as u8 - DETERMINANT_BITS;
#[cfg(target_endian="big")]
const DETERMINANT_SHIFT: u8 = 0;
#[cfg(target_endian="little")]
const INLINE_SIZE_SHIFT: u8 = DETERMINANT_SHIFT - INLINE_SIZE_BITS;
#[cfg(target_endian="big")]
const INLINE_SIZE_SHIFT: u8 = DETERMINANT_BITS;
pub const MAX_SIZE: usize = usize::MAX >> DETERMINANT_BITS;
pub enum Error<T=()> {
AllocError(T),
TooLong(T),
}
pub struct TooLong<T=()>(pub T);
#[repr(transparent)]
#[derive(Clone)]
pub struct Sting(Sluice);
impl Sting {
pub const fn is_empty(&self) -> bool { self.0.is_empty() }
pub const fn len(&self) -> usize { self.0.len() }
pub const fn try_from_static(s: &'static str) -> Result<Self, TooLong> {
if s.len() > MAX_SIZE { return Err(TooLong(())) }
Ok(Sting(Sluice { ptr: s.as_ptr() as *mut u8, size: s.len() }))
}
pub const fn from_static(s: &'static str) -> Self {
if s.len() > MAX_SIZE { panic!("String too long") }
Sting(Sluice { ptr: s.as_ptr() as *mut u8, size: s.len() })
}
pub fn try_copy(s: &str) -> Result<Self, Error> {
Sluice::try_copy(s.as_bytes()).map(Sting)
}
pub fn copy(s: &str) -> Self {
Sting(Sluice::copy(s.as_bytes()))
}
}
impl PartialEq for Sting {
fn eq(&self, other: &Self) -> bool {
self.0.deref() == other.0.deref()
}
}
impl Eq for Sting {}
impl fmt::Debug for Sting {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt::Debug::fmt(self.deref(), f)
}
}
impl fmt::Display for Sting {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt::Display::fmt(self.deref(), f)
}
}
impl Deref for Sting {
type Target = str;
fn deref(&self) -> &str {
unsafe { str::from_utf8_unchecked(self.0.deref()) }
}
}
impl DerefMut for Sting {
fn deref_mut(&mut self) -> &mut str {
unsafe { str::from_utf8_unchecked_mut(self.0.deref_mut()) }
}
}
#[repr(C)]
pub struct Sluice {
ptr: *mut u8,
size: usize,
}
impl Sluice {
pub const fn len(&self) -> usize {
if self.code() == INLINE { return self.inline_size(); }
self.normal_size()
}
pub const fn is_empty(&self) -> bool { self.len() == 0 }
pub const fn try_from_static(s: &'static [u8]) -> Result<Self, TooLong> {
if s.len() > MAX_SIZE { return Err(TooLong(())) }
Ok(Sluice { ptr: s.as_ptr() as *mut u8, size: s.len() })
}
pub const fn from_static(s: &'static [u8]) -> Self {
if s.len() > MAX_SIZE { panic!("Slice too long") }
Sluice { ptr: s.as_ptr() as *mut u8, size: s.len() }
}
pub fn try_copy(s: &[u8]) -> Result<Self, Error> {
if s.len() > MAX_SIZE { return Err(Error::TooLong(())) }
if s.len() > INLINE_SIZE_MASK as usize {
let ptr = Self::alloc(s.len())?;
unsafe { ptr::copy_nonoverlapping(s.as_ptr(), ptr, s.len()) };
return Ok(Sluice { ptr, size: Self::new_boxed_size(s.len()) })
}
let size = Self::new_inline_size(s.len());
let mut me = Sluice { ptr: ptr::null_mut(), size };
let me_ptr = &mut me as *mut Sluice as *mut u8;
unsafe { ptr::copy_nonoverlapping(s.as_ptr(), me_ptr, s.len()) };
Ok(me)
}
pub fn copy(s: &[u8]) -> Self {
assert!(s.len() <= MAX_SIZE, "Slice too large!");
unsafe { Self::copy_unchecked(s) }
}
pub unsafe fn copy_unchecked(s: &[u8]) -> Self {
if s.len() > INLINE_SIZE_MASK as usize {
match Self::alloc(s.len()) {
Ok(ptr) => {
unsafe { ptr::copy_nonoverlapping(s.as_ptr(), ptr, s.len()) };
return Sluice { ptr, size: Self::new_boxed_size(s.len()) }
}
Err(_) => panic!("Allocation of {} bytes failed!", s.len()),
}
}
let size = Self::new_inline_size(s.len());
let mut me = Sluice { ptr: ptr::null_mut(), size };
let me_ptr = &mut me as *mut Sluice as *mut u8;
unsafe { ptr::copy_nonoverlapping(s.as_ptr(), me_ptr, s.len()) };
me
}
pub fn try_zeroed(len: usize) -> Result<Self, Error> {
if len > MAX_SIZE { return Err(Error::TooLong(())) }
if len > INLINE_SIZE_MASK as usize {
return match Self::alloc(len) {
Ok(ptr) => {
unsafe { ptr::write_bytes(ptr, 0u8, len) };
Ok(Sluice { ptr, size: Self::new_boxed_size(len) })
}
Err(_) => Err(Error::AllocError(()))
}
}
let size = Self::new_inline_size(len);
let mut me = Sluice { ptr: ptr::null_mut(), size };
let me_ptr = &mut me as *mut Sluice as *mut u8;
unsafe { ptr::write_bytes(me_ptr, 0u8, len) };
Ok(me)
}
pub fn zeroed(len: usize) -> Self {
assert!(len <= MAX_SIZE, "Slice too large!");
if len > INLINE_SIZE_MASK as usize {
return match Self::alloc(len) {
Ok(ptr) => {
unsafe { ptr::write_bytes(ptr, 0u8, len) };
Sluice { ptr, size: Self::new_boxed_size(len) }
}
Err(_) => panic!("Allocation of {} bytes failed!", len),
}
}
let size = Self::new_inline_size(len);
let mut me = Sluice { ptr: ptr::null_mut(), size };
let me_ptr = &mut me as *mut Sluice as *mut u8;
unsafe { ptr::write_bytes(me_ptr, 0u8, len) };
me
}
const fn code(&self) -> u8 { (self.size >> DETERMINANT_SHIFT) as u8 & DETERMINANT_MASK }
const fn inline_size(&self) -> usize {
(self.size >> INLINE_SIZE_SHIFT) & INLINE_SIZE_MASK as usize
}
const fn new_inline_size(len: usize) -> usize {
(len << INLINE_SIZE_SHIFT) | ((INLINE as usize) << DETERMINANT_SHIFT)
}
#[cfg(target_endian="little")]
const fn normal_size(&self) -> usize { self.size & MAX_SIZE }
#[cfg(target_endian="big")]
const fn normal_size(&self) -> usize { self.size >> DETERMINANT_BITS }
#[cfg(target_endian="little")]
const fn new_boxed_size(len: usize) -> usize {
len | ((BOXED as usize) << DETERMINANT_SHIFT)
}
#[cfg(target_endian="big")]
const fn new_boxed_size(len: usize) -> usize {
(len << DETERMINANT_BITS) | BOXED as usize
}
fn alloc(len: usize) -> Result<*mut u8, Error> {
let ptr = unsafe { alloc(Layout::from_size_align_unchecked(len, 1)) };
if ptr.is_null() { return Err(Error::TooLong(())) }
Ok(ptr)
}
}
impl Drop for Sluice {
fn drop(&mut self) {
if self.code() == BOXED {
unsafe {
let layout = Layout::from_size_align_unchecked(self.normal_size(),1);
dealloc(self.ptr, layout);
}
}
}
}
impl Deref for Sluice {
type Target = [u8];
fn deref(&self) -> &[u8] {
if self.code() == INLINE {
let len = self.inline_size();
let ptr = self as *const Sluice as *const u8;
unsafe { slice::from_raw_parts(ptr, len) }
} else {
unsafe { slice::from_raw_parts(self.ptr, self.normal_size()) }
}
}
}
impl DerefMut for Sluice {
fn deref_mut(&mut self) -> &mut [u8] {
if self.code() == INLINE {
let len = self.inline_size();
let ptr = self as *mut Sluice as *mut u8;
unsafe { slice::from_raw_parts_mut(ptr, len) }
} else {
unsafe { slice::from_raw_parts_mut(self.ptr, self.normal_size()) }
}
}
}
impl PartialEq for Sluice {
fn eq(&self, other: &Self) -> bool {
self.deref() == other.deref()
}
}
impl Eq for Sluice {}
impl fmt::Debug for Sluice {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt::Debug::fmt(self.deref(), f)
}
}
impl Clone for Sluice {
fn clone(&self) -> Self {
if self.code() == BOXED {
Sluice::copy(self.deref())
} else {
Sluice { ptr: self.ptr, size: self.size }
}
}
}