#![no_std]
use core::sync::atomic::AtomicPtr;
use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering;
use core::sync::atomic::fence;
use core::mem::size_of;
use core::mem::ManuallyDrop;
use core::mem;
use core::mem::align_of;
use core::ptr;
use core::ops::Deref;
use core::ops::DerefMut;
use core::ops::Add;
use core::ops::AddAssign;
use core::slice;
use core::cmp::max;
use core::cmp::min;
extern crate alloc;
use alloc::vec::Vec;
use alloc::boxed::Box;
use alloc::str;
use alloc::string::String;
use alloc::string::FromUtf8Error;
use alloc::fmt;
#[repr(C)]
struct InnerLong {
#[cfg(target_endian="big")]
len: usize,
cap: usize,
ptr: * mut u8,
cbptr: AtomicPtr<AtomicUsize>,
#[cfg(target_endian="little")]
len: usize,
}
impl InnerLong {
#[inline]
fn from_vec(mut v: Vec<u8>, allowcb: bool, mincap: usize) -> Self {
let len = v.len();
let cap = v.capacity();
assert!(mincap <= cap);
let mincap = max(len,mincap);
let ptr = v.as_mut_ptr();
mem::forget(v);
let mut cbptr : * mut AtomicUsize = ptr::null_mut();
if allowcb {
unsafe {
let end = ptr.add(mincap);
let mut cbstart = mincap + end.align_offset(align_of::<AtomicUsize>());
let cbrequired = cbstart + size_of::<AtomicUsize>();
if cbrequired <= cap {
let cbextraspace = (cap - cbrequired) & !(align_of::<AtomicUsize>()-1);
cbstart += cbextraspace;
cbptr = ptr.add(cbstart) as * mut AtomicUsize;
*cbptr = AtomicUsize::new(3);
} else {
}
}
}
InnerLong { len : len, cap: cap, ptr: ptr, cbptr: AtomicPtr::new(cbptr) }
}
#[inline]
fn from_slice(s: &[u8], allowcb: bool, mincap: usize) -> Self {
let len = max(s.len(),mincap);
let mask = align_of::<AtomicUsize>() - 1;
let veccap = ((len + mask) & !mask) + size_of::<AtomicUsize>();
let mut v = Vec::with_capacity(veccap);
v.extend_from_slice(s);
Self::from_vec(v,allowcb,mincap)
}
#[inline]
fn make_unique(&mut self, mincap: usize, allowcb: bool) {
if self.cap == 0 { unsafe {
*self = InnerLong::from_slice(slice::from_raw_parts(self.ptr,self.len),allowcb,mincap);
}
} else {
let cbptr = self.cbptr.load(Ordering::Relaxed);
if cbptr.is_null() {
} else {
unsafe {
let refcount = (*cbptr).load(Ordering::Relaxed) >> 1;
if refcount == 1 {
if !allowcb {
if ((*cbptr).load(Ordering::Relaxed) & 1) == 0 {
let _ = Box::from_raw(cbptr);
}
self.cbptr.store(ptr::null_mut(),Ordering::Relaxed);
}
} else {
*self = InnerLong::from_slice(slice::from_raw_parts(self.ptr,self.len),allowcb,mincap) ;
}
}
}
}
}
fn usablecap(&self) -> usize {
let ptr = self.ptr as usize;
let cbptr = self.cbptr.load(Ordering::Relaxed) as usize;
if cbptr < ptr {
self.cap
} else {
min(cbptr - ptr,self.cap)
}
}
unsafe fn reserve(&mut self, mut mincap: usize, allowcb: bool) {
let cap = self.cap;
if mincap <= cap {
if mincap <= self.usablecap() { return }
self.cbptr = AtomicPtr::new(ptr::null_mut());
return
};
mincap = max(mincap, cap * 2);
*self = Self::from_slice(slice::from_raw_parts(self.ptr, self.len), allowcb, mincap);
}
}
impl Drop for InnerLong {
fn drop(&mut self) {
let len = self.len;
let cap = self.cap;
if cap == 0 { return } let cbptr = self.cbptr.load(Ordering::Relaxed);
unsafe {
if !cbptr.is_null() {
let oldcb = (*cbptr).fetch_sub(2, Ordering::Release); if oldcb > 3 { return } fence(Ordering::Acquire);
if (oldcb & 1) == 0 { let _ = Box::from_raw(cbptr);
}
}
let _ = Vec::from_raw_parts(self.ptr, len, cap);
}
}
}
const SHORTLEN : usize = size_of::<InnerLong>()-1;
#[repr(C)]
#[derive(Clone,Copy)]
struct InnerShort {
#[cfg(target_endian="big")]
len: u8,
data: [u8;SHORTLEN],
#[cfg(target_endian="little")]
len: u8,
}
#[repr(C)]
pub union MAByteString {
short: InnerShort,
long: ManuallyDrop<InnerLong>,
}
unsafe impl Send for MAByteString {}
unsafe impl Sync for MAByteString {}
impl MAByteString {
pub const fn new() -> Self {
MAByteString { short: InnerShort { data: [0; SHORTLEN] , len: 0x80 } }
}
pub fn from_slice(s: &[u8]) -> Self {
let len = s.len();
if len <= SHORTLEN {
let mut data : [u8; SHORTLEN] = [0; SHORTLEN];
data[0..len].copy_from_slice(&s);
MAByteString { short: InnerShort { data: data, len: len as u8 + 0x80 } }
} else {
MAByteString { long: ManuallyDrop::new(InnerLong::from_slice(s, true,0)) }
}
}
pub fn from_vec(v: Vec<u8>) -> Self {
let len = v.len();
if len <= SHORTLEN {
let mut data : [u8; SHORTLEN] = [0; SHORTLEN];
data[0..len].copy_from_slice(&v);
MAByteString { short: InnerShort { data: data, len: len as u8 + 0x80 } }
} else {
MAByteString { long: ManuallyDrop::new(InnerLong::from_vec(v, true, 0)) }
}
}
pub const fn from_static(s: &'static [u8]) -> Self {
let len = s.len();
if len <= SHORTLEN {
let mut data : [u8; SHORTLEN] = [0; SHORTLEN];
let mut i = 0;
while i < len {
data[i] = s[i];
i += 1;
}
MAByteString { short: InnerShort { data: data, len: len as u8 + 0x80 } }
} else {
MAByteString { long: ManuallyDrop::new(InnerLong { len : len, cap: 0, ptr: s.as_ptr() as *mut u8, cbptr: AtomicPtr::new(ptr::null_mut()) }) }
}
}
pub fn from_builder(b : MAByteStringBuilder) -> Self {
unsafe {
let len = b.long.len;
if len > isize::max as usize {
return MAByteString { short: b.short };
}
let cap = b.long.cap;
let ptr = b.long.ptr;
mem::forget(b);
let end = ptr.add(len);
let cbstart = len + end.align_offset(align_of::<AtomicUsize>());
let cbrequired = cbstart + size_of::<AtomicUsize>();
let mut cbptr : * mut AtomicUsize = ptr::null_mut();
if cbrequired <= cap {
cbptr = ptr.add(cbstart) as * mut AtomicUsize;
*cbptr = AtomicUsize::new(3);
}
MAByteString { long: ManuallyDrop::new(InnerLong { len : len, cap: cap, ptr: ptr, cbptr: AtomicPtr::new(cbptr) }) }
}
}
pub fn get_mode(&self) -> &'static str {
unsafe {
let len = self.long.len;
if len > isize::max as usize { "short"
} else if self.long.cap == 0 { "static"
} else {
let cbptr = self.long.cbptr.load(Ordering::Acquire);
if cbptr.is_null() {
"unique"
} else {
let cbval = (*cbptr).load(Ordering::Relaxed);
if (cbval & 1) == 0 {
if cbval <= 3 {
"cbowned (unique)"
} else {
"cbowned (shared)"
}
} else {
if cbval <= 3 {
"cbinline (unique)"
} else {
"cbinline (shared)"
}
}
}
}
}
}
fn reserve_extra_internal(&mut self, extracap: usize) -> (*mut u8, usize, bool) {
unsafe {
let mut len = self.long.len;
let mincap;
if len > isize::max as usize { len = (len >> ((size_of::<usize>() - 1) * 8)) - 0x80;
mincap = len + extracap;
if mincap > SHORTLEN {
let mincap = max(mincap,SHORTLEN*2);
*self = Self { long: ManuallyDrop::new(InnerLong::from_slice(slice::from_raw_parts(self.short.data.as_ptr(),len),true,mincap)) }
} else {
return (self.short.data.as_mut_ptr(),len, true);
}
} else {
mincap = len + extracap;
self.long.deref_mut().make_unique(mincap,true);
self.long.deref_mut().reserve(mincap,true);
}
return (self.long.ptr, len, false);
}
}
pub fn reserve(&mut self, mincap: usize) {
unsafe {
let mut len = self.long.len;
if len > isize::max as usize { if mincap > SHORTLEN {
len = (len >> ((size_of::<usize>() - 1) * 8)) - 0x80;
let mincap = max(mincap,SHORTLEN*2);
*self = Self { long: ManuallyDrop::new(InnerLong::from_slice(slice::from_raw_parts(self.short.data.as_ptr(),len),true,mincap)) }
}
} else {
self.long.deref_mut().make_unique(mincap,true);
self.long.deref_mut().reserve(mincap,true);
}
}
}
pub fn capacity(&self) -> usize {
unsafe {
let len = self.long.len;
if len > isize::max as usize { SHORTLEN
} else {
self.long.usablecap()
}
}
}
pub fn clear(&mut self) {
unsafe {
let len = self.long.len;
if len > isize::max as usize { self.short.len = 0x80;
} else if self.long.cap == 0 { self.short.len = 0x80;
} else {
let cbptr = self.long.cbptr.load(Ordering::Relaxed);
if cbptr.is_null() { self.long.len = 0;
} else {
let refcount = (*cbptr).load(Ordering::Relaxed) >> 1;
if refcount == 1 {
self.long.len = 0;
} else {
*self = Self::new();
}
}
}
}
}
pub fn into_vec(mut self) -> Vec<u8> {
unsafe {
let mut len = self.long.len;
if len > isize::max as usize { len = (len >> ((size_of::<usize>() - 1) * 8)) - 0x80;
return slice::from_raw_parts(self.short.data.as_ptr(), len).to_vec();
}
self.long.deref_mut().make_unique(0,true);
let cap = self.long.cap;
let ptr = self.long.ptr;
mem::forget(self);
return Vec::from_raw_parts(ptr,len,cap);
}
}
}
impl Drop for MAByteString {
fn drop(&mut self) {
unsafe {
let len = self.long.len;
if len > isize::max as usize { return }; ManuallyDrop::drop(&mut self.long);
}
}
}
impl Clone for MAByteString{
fn clone(&self) -> Self {
unsafe {
let len = self.long.len;
if len > isize::max as usize { MAByteString { short : self.short }
} else if self.long.cap == 0 { MAByteString { long : ManuallyDrop::new(InnerLong { len : len, cap: 0, ptr: self.long.ptr, cbptr: AtomicPtr::new(ptr::null_mut()) }) }
} else {
let mut cbptr = self.long.cbptr.load(Ordering::Acquire);
if cbptr.is_null() {
let newcbptr = Box::into_raw(Box::new(AtomicUsize::new(2)));
if let Err(cxcbptr) = self.long.cbptr.compare_exchange(ptr::null_mut(),newcbptr,Ordering::AcqRel,Ordering::Acquire) {
let _ = Box::from_raw(newcbptr);
cbptr = cxcbptr;
} else {
cbptr = newcbptr
}
}
if (*cbptr).fetch_add(2, Ordering::Relaxed) > usize::MAX / 2 {
(*cbptr).fetch_sub(2, Ordering::Relaxed);
panic!("reference count too high, you have a refrence leak");
}
MAByteString { long : ManuallyDrop::new(InnerLong { len : len, cap: self.long.cap, ptr: self.long.ptr, cbptr: AtomicPtr::new(cbptr) }) }
}
}
}
}
impl Deref for MAByteString {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
unsafe {
let mut len = self.long.len;
let ptr = if len > isize::max as usize {
len = (len >> ((size_of::<usize>() - 1) * 8)) - 0x80;
self.short.data.as_ptr()
} else {
self.long.ptr
};
slice::from_raw_parts(ptr,len)
}
}
}
impl DerefMut for MAByteString {
#[inline]
fn deref_mut(&mut self) -> &mut [u8] {
unsafe {
let mut len = self.long.len;
let ptr = if len > isize::max as usize { len = (len >> ((size_of::<usize>() - 1) * 8)) - 0x80;
self.short.data.as_mut_ptr()
} else {
self.long.deref_mut().make_unique(0,true);
self.long.ptr
};
slice::from_raw_parts_mut(ptr,len)
}
}
}
impl Add<&[u8]> for MAByteString {
type Output = Self;
fn add(mut self, rhs: &[u8]) -> Self {
self += rhs;
self
}
}
impl AddAssign<&[u8]> for MAByteString {
fn add_assign(&mut self, other: &[u8]) {
unsafe {
let (ptr, mut len, short) = self.reserve_extra_internal(other.len());
ptr::copy_nonoverlapping(other.as_ptr(), ptr.add(len), other.len());
len += other.len();
if short {
self.short.len = (len + 0x80) as u8;
} else {
self.long.len = len;
}
}
}
}
fn bytes_debug(s: &[u8], f: &mut fmt::Formatter<'_>) -> Result<(),fmt::Error> {
f.write_str("b\"")?;
let mut groupstart = 0;
let mut p = 0;
let len = s.len();
while p < len {
let c = s[p];
if (c < 0x20) || (c > 0x7E) || (c == b'\\') || (c == b'\"') {
if groupstart < p {
unsafe {
f.write_str(str::from_utf8_unchecked(&s[groupstart..p]))?;
}
}
if c == b'\\' {
f.write_str("\\\\")?;
} else if c == b'\"' {
f.write_str("\\\"")?;
} else {
let mut escaped: [u8;4] = *b"\\xxx";
let mut uppernibble = c >> 4;
if uppernibble < 10 {
uppernibble += b'0'
} else {
uppernibble -= 10;
uppernibble += b'a';
}
escaped[2] = uppernibble;
let mut lowernibble = c & 0xF;
if lowernibble < 10 {
lowernibble += b'0'
} else {
lowernibble -= 10;
lowernibble += b'a';
}
escaped[3] = lowernibble;
unsafe {
f.write_str(str::from_utf8_unchecked(&escaped))?;
}
}
groupstart = p + 1;
}
p += 1;
}
if groupstart < len {
unsafe {
f.write_str(str::from_utf8_unchecked(&s[groupstart..len]))?;
}
}
f.write_str("\"")?;
Ok(())
}
impl fmt::Debug for MAByteString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(),fmt::Error> {
bytes_debug(self,f)
}
}
impl PartialEq for MAByteString {
fn eq(&self, other : &MAByteString) -> bool {
return self.deref() == other.deref();
}
}
impl Eq for MAByteString {}
impl PartialEq<&[u8]> for MAByteString {
fn eq(&self, other : &&[u8]) -> bool {
return self.deref() == *other;
}
}
impl PartialEq<MAByteString> for &[u8] {
fn eq(&self, other : &MAByteString) -> bool {
return *self == other.deref();
}
}
impl<const N: usize> PartialEq<&[u8;N]> for MAByteString {
fn eq(&self, other : &&[u8;N]) -> bool {
return self.deref() == *other;
}
}
impl<const N: usize> PartialEq<MAByteString> for &[u8;N] {
fn eq(&self, other : &MAByteString) -> bool {
return *self == other.deref();
}
}
#[repr(C)]
pub union MAByteStringBuilder {
short: InnerShort,
long: ManuallyDrop<InnerLong>,
}
unsafe impl Send for MAByteStringBuilder {}
unsafe impl Sync for MAByteStringBuilder {}
impl MAByteStringBuilder {
pub const fn new() -> Self {
MAByteStringBuilder { short: InnerShort { data: [0; SHORTLEN] , len: 0x80 } }
}
pub fn from_slice(s: &[u8]) -> Self {
let len = s.len();
if len <= SHORTLEN {
let mut data : [u8; SHORTLEN] = [0; SHORTLEN];
data[0..len].copy_from_slice(&s);
MAByteStringBuilder { short: InnerShort { data: data, len: len as u8 + 0x80 } }
} else {
MAByteStringBuilder { long : ManuallyDrop::new(InnerLong::from_slice(s,false,0)) }
}
}
pub fn from_vec(v: Vec<u8>) -> Self {
let len = v.len();
if len <= SHORTLEN {
let mut data : [u8; SHORTLEN] = [0; SHORTLEN];
data[0..len].copy_from_slice(&v);
MAByteStringBuilder { short: InnerShort { data: data, len: len as u8 + 0x80 } }
} else {
MAByteStringBuilder { long: ManuallyDrop::new(InnerLong::from_vec(v,false,0)) }
}
}
pub fn from_mabs(mut s: MAByteString) -> Self {
unsafe {
let len = s.long.len;
if len > isize::max as usize { MAByteStringBuilder { short: s.short }
} else {
s.long.deref_mut().make_unique(0,false);
let inner = ptr::read(&mut s.long);
mem::forget(s);
MAByteStringBuilder { long: inner }
}
}
}
pub fn get_mode(&self) -> &'static str {
unsafe {
let len = self.long.len;
if len > isize::max as usize { "short"
} else if self.long.cap == 0 { "static (invalid)"
} else {
let cbptr = self.long.cbptr.load(Ordering::Acquire);
if cbptr.is_null() {
"unique"
} else if ((*cbptr).load(Ordering::Relaxed) & 1) == 0 {
"cbowned (inavlid)"
} else {
"cbinline (invalid)"
}
}
}
}
fn reserve_extra_internal(&mut self, extracap: usize) -> (*mut u8, usize, bool) {
unsafe {
let mut len = self.long.len;
let mincap;
if len > isize::max as usize { len = (len >> ((size_of::<usize>() - 1) * 8)) - 0x80;
mincap = len + extracap;
if mincap > SHORTLEN {
let mincap = max(mincap,SHORTLEN*2);
*self = Self { long: ManuallyDrop::new(InnerLong::from_slice(slice::from_raw_parts(self.short.data.as_ptr(),len),false,mincap)) }
} else {
return (self.short.data.as_mut_ptr(),len, true);
}
} else {
mincap = len + extracap;
self.long.deref_mut().reserve(mincap,false);
}
return (self.long.ptr, len, false);
}
}
pub fn reserve(&mut self, mincap: usize) {
unsafe {
let mut len = self.long.len;
if len > isize::max as usize { if mincap > SHORTLEN {
len = (len >> ((size_of::<usize>() - 1) * 8)) - 0x80;
let mincap = max(mincap,SHORTLEN*2);
*self = Self { long: ManuallyDrop::new(InnerLong::from_slice(slice::from_raw_parts(self.short.data.as_ptr(),len),false,mincap)) }
}
} else {
self.long.deref_mut().reserve(mincap,false);
}
}
}
pub fn capacity(&self) -> usize {
unsafe {
let len = self.long.len;
if len > isize::max as usize { SHORTLEN
} else {
self.long.cap
}
}
}
pub fn clear(&mut self) {
unsafe {
let len = self.long.len;
if len > isize::max as usize { self.short.len = 0x80;
} else {
self.long.len = 0;
}
}
}
pub fn into_vec(self) -> Vec<u8> {
unsafe {
let mut len = self.long.len;
if len > isize::max as usize { len = (len >> ((size_of::<usize>() - 1) * 8)) - 0x80;
return slice::from_raw_parts(self.short.data.as_ptr(), len).to_vec();
}
let cap = self.long.cap;
let ptr = self.long.ptr;
mem::forget(self);
return Vec::from_raw_parts(ptr,len,cap);
}
}
}
impl Drop for MAByteStringBuilder {
fn drop(&mut self) {
unsafe {
let len = self.long.len;
if len > isize::max as usize { return }; let cap = self.long.cap;
let _ = Vec::from_raw_parts(self.long.ptr, self.long.len, cap);
}
}
}
impl Clone for MAByteStringBuilder {
fn clone(&self) -> Self {
MAByteStringBuilder::from_slice(self)
}
}
impl Deref for MAByteStringBuilder {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
unsafe {
let mut len = self.long.len;
let ptr = if len > isize::max as usize {
len = (len >> ((size_of::<usize>() - 1) * 8)) - 0x80;
self.short.data.as_ptr()
} else {
self.long.ptr
};
slice::from_raw_parts(ptr,len)
}
}
}
impl DerefMut for MAByteStringBuilder {
#[inline]
fn deref_mut(&mut self) -> &mut [u8] {
unsafe {
let mut len = self.long.len;
let ptr = if len > isize::max as usize {
len = (len >> ((size_of::<usize>() - 1) * 8)) - 0x80;
self.short.data.as_mut_ptr()
} else {
self.long.ptr
};
slice::from_raw_parts_mut(ptr,len)
}
}
}
impl Add<&[u8]> for MAByteStringBuilder {
type Output = Self;
fn add(mut self, rhs: &[u8]) -> Self {
self += rhs;
self
}
}
impl AddAssign<&[u8]> for MAByteStringBuilder {
fn add_assign(&mut self, other: &[u8]) {
unsafe {
let (ptr, mut len, short) = self.reserve_extra_internal(other.len());
ptr::copy_nonoverlapping(other.as_ptr(), ptr.add(len), other.len());
len += other.len();
if short {
self.short.len = (len + 0x80) as u8;
} else {
self.long.len = len;
}
}
}
}
impl fmt::Debug for MAByteStringBuilder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(),fmt::Error> {
bytes_debug(self,f)
}
}
impl PartialEq for MAByteStringBuilder {
fn eq(&self, other : &MAByteStringBuilder) -> bool {
return self.deref() == other.deref();
}
}
impl Eq for MAByteStringBuilder {}
impl PartialEq<&[u8]> for MAByteStringBuilder {
fn eq(&self, other : &&[u8]) -> bool {
return self.deref() == *other;
}
}
impl PartialEq<MAByteStringBuilder> for &[u8] {
fn eq(&self, other : &MAByteStringBuilder) -> bool {
return *self == other.deref();
}
}
impl<const N: usize> PartialEq<&[u8;N]> for MAByteStringBuilder {
fn eq(&self, other : &&[u8;N]) -> bool {
return self.deref() == *other;
}
}
impl<const N: usize> PartialEq<MAByteStringBuilder> for &[u8;N] {
fn eq(&self, other : &MAByteStringBuilder) -> bool {
return *self == other.deref();
}
}
#[derive(Clone)]
pub struct MAString {
inner: MAByteString,
}
impl MAString {
pub const fn new() -> Self {
MAString { inner: MAByteString::new() }
}
pub fn from_slice(s: &str) -> Self {
MAString { inner: MAByteString::from_slice(s.as_bytes()) }
}
pub fn from_string(s: String) -> Self {
MAString { inner: MAByteString::from_vec(s.into_bytes()) }
}
pub const fn from_static(s: &'static str) -> Self {
MAString { inner: MAByteString::from_static(s.as_bytes()) }
}
pub fn from_builder(b : MAStringBuilder) -> Self {
MAString { inner: MAByteString::from_builder(b.inner) }
}
pub fn get_mode(&self) -> &'static str {
self.inner.get_mode()
}
pub fn as_mut_str(&mut self) -> &mut str {
unsafe {
str::from_utf8_unchecked_mut(&mut self.inner)
}
}
pub fn reserve(&mut self, mincap: usize) {
self.inner.reserve(mincap);
}
pub fn capacity(&self) -> usize {
self.inner.capacity()
}
pub fn clear(&mut self) {
self.inner.clear();
}
pub fn into_vec(self) -> Vec<u8> {
self.inner.into_vec()
}
pub unsafe fn from_utf8_unchecked(data: MAByteString) -> Self {
Self { inner: data }
}
pub fn from_utf8(data: MAByteString) -> Result<Self, FromUtf8Error> {
match str::from_utf8(&data) {
Ok(..) => Ok( Self { inner: data } ),
Err(..) => String::from_utf8(data.into_vec()).map(|_| unreachable!()),
}
}
pub fn from_utf8_lossy(data: MAByteString) -> Self {
match str::from_utf8(&data) {
Ok(..) => Self { inner: data },
Err(..) => Self::from_string(String::from_utf8_lossy(&data).into_owned()),
}
}
pub fn into_string(self) -> String {
unsafe {
String::from_utf8_unchecked(self.inner.into_vec())
}
}
pub fn into_bytes(self) -> MAByteString {
self.inner
}
}
impl Deref for MAString {
type Target = str;
#[inline]
fn deref(&self) -> &str {
unsafe {
str::from_utf8_unchecked(&self.inner)
}
}
}
impl DerefMut for MAString {
#[inline]
fn deref_mut(&mut self) -> &mut str {
unsafe {
str::from_utf8_unchecked_mut(&mut self.inner)
}
}
}
impl fmt::Display for MAString {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl fmt::Debug for MAString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(),fmt::Error> {
fmt::Debug::fmt(self.deref(),f)
}
}
impl PartialEq for MAString {
fn eq(&self, other : &MAString) -> bool {
return self.deref() == other.deref();
}
}
impl Eq for MAString {}
impl PartialEq<&str> for MAString {
fn eq(&self, other : &&str) -> bool {
return self.deref() == *other;
}
}
impl PartialEq<MAString> for &str {
fn eq(&self, other : &MAString) -> bool {
return *self == other.deref();
}
}
impl Add<&str> for MAString {
type Output = Self;
fn add(mut self, rhs: &str) -> Self {
self += rhs;
self
}
}
impl AddAssign<&str> for MAString {
fn add_assign(&mut self, other: &str) {
self.inner.add_assign(other.as_bytes());
}
}
#[derive(Clone)]
pub struct MAStringBuilder {
inner: MAByteStringBuilder,
}
impl MAStringBuilder {
pub const fn new() -> Self {
MAStringBuilder { inner: MAByteStringBuilder::new() }
}
pub fn from_slice(s: &str) -> Self {
MAStringBuilder { inner: MAByteStringBuilder::from_slice(s.as_bytes()) }
}
pub fn from_string(s: String) -> Self {
MAStringBuilder { inner: MAByteStringBuilder::from_vec(s.into_bytes()) }
}
pub fn from_mas(s: MAString) -> Self {
MAStringBuilder { inner: MAByteStringBuilder::from_mabs(s.inner) }
}
pub fn get_mode(&self) -> &'static str {
self.inner.get_mode()
}
pub fn as_mut_str(&mut self) -> &mut str {
unsafe {
str::from_utf8_unchecked_mut(&mut self.inner)
}
}
pub fn reserve(&mut self, mincap: usize) {
self.inner.reserve(mincap);
}
pub fn capacity(&self) -> usize {
self.inner.capacity()
}
pub fn clear(&mut self) {
self.inner.clear();
}
pub fn into_vec(self) -> Vec<u8> {
self.inner.into_vec()
}
pub unsafe fn from_utf8_unchecked(data: MAByteStringBuilder) -> Self {
Self { inner: data }
}
pub fn from_utf8(data: MAByteStringBuilder) -> Result<Self, FromUtf8Error> {
match str::from_utf8(&data) {
Ok(..) => Ok( Self { inner: data } ),
Err(..) => String::from_utf8(data.into_vec()).map(|_| unreachable!()),
}
}
pub fn from_utf8_lossy(data: MAByteStringBuilder) -> Self {
match str::from_utf8(&data) {
Ok(..) => Self { inner: data },
Err(..) => Self::from_string(String::from_utf8_lossy(&data).into_owned()),
}
}
pub fn into_string(self) -> String {
unsafe {
String::from_utf8_unchecked(self.inner.into_vec())
}
}
pub fn into_bytes(self) -> MAByteStringBuilder {
self.inner
}
}
impl Deref for MAStringBuilder {
type Target = str;
#[inline]
fn deref(&self) -> &str {
unsafe {
str::from_utf8_unchecked(&self.inner)
}
}
}
impl DerefMut for MAStringBuilder {
#[inline]
fn deref_mut(&mut self) -> &mut str {
unsafe {
str::from_utf8_unchecked_mut(&mut self.inner)
}
}
}
impl fmt::Display for MAStringBuilder {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl fmt::Debug for MAStringBuilder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(),fmt::Error> {
fmt::Debug::fmt(self.deref(),f)
}
}
impl PartialEq for MAStringBuilder {
fn eq(&self, other : &MAStringBuilder) -> bool {
return self.deref() == other.deref();
}
}
impl Eq for MAStringBuilder {}
impl PartialEq<&str> for MAStringBuilder {
fn eq(&self, other : &&str) -> bool {
return self.deref() == *other;
}
}
impl PartialEq<MAStringBuilder> for &str {
fn eq(&self, other : &MAStringBuilder) -> bool {
return *self == other.deref();
}
}
impl Add<&str> for MAStringBuilder {
type Output = Self;
fn add(mut self, rhs: &str) -> Self {
self += rhs;
self
}
}
impl AddAssign<&str> for MAStringBuilder {
fn add_assign(&mut self, other: &str) {
self.inner.add_assign(other.as_bytes());
}
}
#[test]
fn test_len_transmutation() {
let v = MAByteString { short: InnerShort { data: [0;SHORTLEN], len: 0x85 } };
unsafe {
assert_eq!(v.long.len >> ((size_of::<usize>() - 1) * 8),0x85);
}
}
#[cfg(test)]
macro_rules! assert_mode {
($s:expr, $expectedmode:expr) => {
#[allow(unused_labels)] 'skipcheck: {
let mode = $s.get_mode();
let expectedmode = $expectedmode;
#[cfg(miri)]
if (($s.as_ptr() as usize) & (mem::align_of::<AtomicPtr<usize>>() - 1)) != 0 {
if (mode == "unique") && (expectedmode == "cbinline (unique)") { break 'skipcheck }
if (mode == "cbowned (unique)") && (expectedmode == "cbinline (unique)") { break 'skipcheck }
if (mode == "cbowned (shared)") && (expectedmode == "cbinline (shared)") { break 'skipcheck }
}
assert_eq!(mode,expectedmode);
}
}
}
#[test]
fn test_reserve_extra_internal() {
let mut s = MAByteString::from_static(b"test");
assert_eq!(s.get_mode(),"short");
let oldptr = s.as_ptr();
let oldlen = s.len();
let (ptr, len, isshort) = s.reserve_extra_internal(10);
assert_eq!(ptr as *const u8,oldptr);
assert_eq!(len,oldlen);
assert_eq!(isshort, true);
assert_eq!(s,b"test");
assert_mode!(s,"short");
assert_eq!(s.capacity(),mem::size_of_val(&s)-1);
let oldptr = s.as_ptr();
let oldlen = s.len();
let (ptr, len, isshort) = s.reserve_extra_internal(100-s.len());
assert_ne!(ptr as *const u8,oldptr);
assert_eq!(len,oldlen);
assert_eq!(isshort, false);
assert_eq!(s,b"test");
assert_mode!(s,"cbinline (unique)");
assert!(s.capacity() >= 100);
assert!(s.capacity() <= 150);
assert_mode!(s,"cbinline (unique)");
let oldptr = s.as_ptr();
let oldlen = s.len();
let (ptr, len, isshort) = s.reserve_extra_internal(0); assert_eq!(ptr as *const u8,oldptr);
assert_eq!(len,oldlen);
assert_eq!(isshort, false);
assert!(s.capacity() >= 100);
assert!(s.capacity() <= 150);
let mut s = MAByteString::from_static(b"the quick brown fox jumped over the lazy dog");
assert_mode!(s,"static");
let oldptr = s.as_ptr();
let oldlen = s.len();
let (ptr, len, isshort) = s.reserve_extra_internal(0); assert_ne!(ptr as *const u8,oldptr);
assert_eq!(len,oldlen);
assert_eq!(isshort, false);
assert_eq!(s,b"the quick brown fox jumped over the lazy dog");
assert_mode!(s,"cbinline (unique)");
assert!(s.capacity() >= "the quick brown fox jumped over the lazy dog".len());
assert!(s.capacity() <= "the quick brown fox jumped over the lazy dog".len() + 50);
let mut s = MAByteString::from_static(b"the quick brown fox jumped over the lazy dog");
assert_mode!(s,"static");
let oldptr = s.as_ptr();
let oldlen = s.len();
let (ptr, len, isshort) = s.reserve_extra_internal(100-s.len());
assert_ne!(ptr as *const u8,oldptr);
assert_eq!(len,oldlen);
assert_eq!(isshort, false);
assert_eq!(s,b"the quick brown fox jumped over the lazy dog");
assert_mode!(s,"cbinline (unique)");
assert!(s.capacity() >= 100);
assert!(s.capacity() <= 150);
let s2 = s.clone();
assert_mode!(s,"cbinline (shared)");
assert_mode!(s2,"cbinline (shared)");
let oldptr = s.as_ptr();
let oldlen = s.len();
let (ptr, len, isshort) = s.reserve_extra_internal(0); assert_ne!(ptr as *const u8,oldptr);
assert_eq!(len,oldlen);
assert_eq!(isshort, false);
assert_mode!(s,"cbinline (unique)");
assert!(s.capacity() >= "the quick brown fox jumped over the lazy dog".len());
assert!(s.capacity() <= "the quick brown fox jumped over the lazy dog".len() + 50);
assert_mode!(s2,"cbinline (unique)");
assert!(s2.capacity() >= 100);
assert!(s2.capacity() <= 150);
let mut s = MAByteString::from_vec(b"the quick brown fox jumped over the lazy dog".to_vec());
assert_mode!(s,"unique");
let oldptr = s.as_ptr();
let oldlen = s.len();
let (ptr, len, isshort) = s.reserve_extra_internal(0); assert_eq!(ptr as *const u8,oldptr);
assert_eq!(len,oldlen);
assert_eq!(isshort, false);
assert_eq!(s,b"the quick brown fox jumped over the lazy dog");
assert_mode!(s,"unique");
assert!(s.capacity() >= "the quick brown fox jumped over the lazy dog".len());
assert!(s.capacity() <= "the quick brown fox jumped over the lazy dog".len() + 50);
let s2 = s.clone();
assert_mode!(s,"cbowned (shared)");
assert_mode!(s2,"cbowned (shared)");
let oldptr = s.as_ptr();
let oldlen = s.len();
let (ptr, len, isshort) = s.reserve_extra_internal(0); assert_ne!(ptr as *const u8,oldptr);
assert_eq!(len,oldlen);
assert_eq!(isshort, false);
assert_mode!(s,"cbinline (unique)");
assert!(s.capacity() >= "the quick brown fox jumped over the lazy dog".len());
assert!(s.capacity() <= "the quick brown fox jumped over the lazy dog".len() + 50);
assert_mode!(s2,"cbowned (unique)");
assert!(s2.capacity() >= "the quick brown fox jumped over the lazy dog".len());
assert!(s2.capacity() <= "the quick brown fox jumped over the lazy dog".len() + 50);
let mut s = MAByteString::from_slice(b"the quick brown fox jumped over the lazy dog");
assert_mode!(s,"cbinline (unique)");
let oldptr = s.as_ptr();
let oldlen = s.len();
let (ptr, len, isshort) = s.reserve_extra_internal(mem::size_of::<usize>());
assert_eq!(ptr as *const u8,oldptr);
assert_eq!(len,oldlen);
assert_eq!(isshort, false);
assert_mode!(s,"unique");
let mut s = MAByteStringBuilder::from_slice(b"test");
assert_mode!(s,"short");
let oldptr = s.as_ptr();
let oldlen = s.len();
let (ptr, len, isshort) = s.reserve_extra_internal(10);
assert_eq!(ptr as *const u8,oldptr);
assert_eq!(len,oldlen);
assert_eq!(isshort, true);
assert_eq!(s,b"test");
assert_mode!(s,"short");
assert_eq!(s.capacity(),mem::size_of_val(&s)-1);
let oldptr = s.as_ptr();
let oldlen = s.len();
let (ptr, len, isshort) = s.reserve_extra_internal(100-s.len());
assert_ne!(ptr as *const u8,oldptr);
assert_eq!(len,oldlen);
assert_eq!(isshort, false);
assert_eq!(s,b"test");
assert_mode!(s,"unique");
assert!(s.capacity() >= 100);
assert!(s.capacity() <= 150);
assert_mode!(s,"unique");
let oldptr = s.as_ptr();
let oldlen = s.len();
let (ptr, len, isshort) = s.reserve_extra_internal(0); assert_eq!(ptr as *const u8,oldptr);
assert_eq!(len,oldlen);
assert_eq!(isshort, false);
assert!(s.capacity() >= 100);
assert!(s.capacity() <= 150);
let mut s = MAByteStringBuilder::from_slice(b"the quick brown fox jumped over the lazy dog");
assert_mode!(s,"unique");
let oldptr = s.as_ptr();
let oldlen = s.len();
let (ptr, len, isshort) = s.reserve_extra_internal(100-s.len());
assert_ne!(ptr as *const u8,oldptr);
assert_eq!(len,oldlen);
assert_eq!(isshort, false);
assert_eq!(s,b"the quick brown fox jumped over the lazy dog");
assert_mode!(s,"unique");
assert!(s.capacity() >= 100);
assert!(s.capacity() <= 150);
let s2 = s.clone();
assert_mode!(s,"unique");
assert_mode!(s2,"unique");
let mut s = MAByteStringBuilder::from_vec(b"the quick brown fox jumped over the lazy dog".to_vec());
assert_mode!(s,"unique");
let oldptr = s.as_ptr();
let oldlen = s.len();
let (ptr, len, isshort) = s.reserve_extra_internal(0); assert_eq!(ptr as *const u8,oldptr);
assert_eq!(len,oldlen);
assert_eq!(isshort, false);
assert_eq!(s,b"the quick brown fox jumped over the lazy dog");
assert_mode!(s,"unique");
assert!(s.capacity() >= "the quick brown fox jumped over the lazy dog".len());
assert!(s.capacity() <= "the quick brown fox jumped over the lazy dog".len() + 50);
let mut s = MAByteStringBuilder::from_slice(b"the quick brown fox jumped over the lazy dog");
assert_mode!(s,"unique");
let oldptr = s.as_ptr();
let oldlen = s.len();
let (ptr, len, isshort) = s.reserve_extra_internal(b"the quick brown fox jumped over the lazy dog".len()+mem::size_of::<usize>());
assert_ne!(ptr as *const u8,oldptr);
assert_eq!(len,oldlen);
assert_eq!(isshort, false);
assert_mode!(s,"unique");
}