use crate::{Archived, FixedIsize, FixedUsize};
use core::{mem, ptr, slice, str};
const OFFSET_BYTES: usize = mem::size_of::<FixedIsize>();
#[derive(Clone, Copy)]
#[repr(C)]
struct OutOfLineRepr {
len: Archived<usize>,
offset: [u8; OFFSET_BYTES],
}
pub const INLINE_CAPACITY: usize = mem::size_of::<OutOfLineRepr>() - 1;
#[derive(Clone, Copy)]
#[repr(C)]
struct InlineRepr {
bytes: [u8; INLINE_CAPACITY],
len: u8,
}
pub union ArchivedStringRepr {
out_of_line: OutOfLineRepr,
inline: InlineRepr,
}
impl ArchivedStringRepr {
#[inline]
pub fn is_inline(&self) -> bool {
unsafe { self.inline.len & 0x80 == 0 }
}
#[inline]
pub unsafe fn out_of_line_offset(&self) -> isize {
FixedIsize::from_le_bytes(self.out_of_line.offset) as isize
}
#[inline]
pub fn as_ptr(&self) -> *const u8 {
unsafe {
if self.is_inline() {
self.inline.bytes.as_ptr()
} else {
(self as *const Self)
.cast::<u8>()
.offset(self.out_of_line_offset())
}
}
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut u8 {
unsafe {
if self.is_inline() {
self.inline.bytes.as_mut_ptr()
} else {
(self as *mut Self)
.cast::<u8>()
.offset(self.out_of_line_offset())
}
}
}
#[inline]
pub fn len(&self) -> usize {
unsafe {
if self.is_inline() {
self.inline.len as usize
} else {
from_archived!(self.out_of_line.len) as usize
}
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[cfg(feature = "validation")]
#[inline]
pub fn as_str_ptr(&self) -> *const str {
ptr_meta::from_raw_parts(self.as_ptr().cast(), self.len())
}
#[inline]
pub fn bytes(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.as_ptr(), self.len()) }
}
#[inline]
pub fn bytes_mut(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len()) }
}
#[inline]
pub fn as_str(&self) -> &str {
unsafe { str::from_utf8_unchecked(self.bytes()) }
}
#[inline]
pub fn as_mut_str(&mut self) -> &mut str {
unsafe { str::from_utf8_unchecked_mut(self.bytes_mut()) }
}
#[inline]
pub unsafe fn emplace_inline(value: &str, out: *mut Self) {
let out_bytes = ptr::addr_of_mut!((*out).inline.bytes);
ptr::copy_nonoverlapping(value.as_bytes().as_ptr(), out_bytes.cast(), value.len());
let out_len = ptr::addr_of_mut!((*out).inline.len);
*out_len = value.len() as u8;
}
#[inline]
pub unsafe fn emplace_out_of_line(value: &str, pos: usize, target: usize, out: *mut Self) {
let out_len = ptr::addr_of_mut!((*out).out_of_line.len);
out_len.write(to_archived!(value.len() as FixedUsize));
let out_offset = ptr::addr_of_mut!((*out).out_of_line.offset);
let offset = crate::rel_ptr::signed_offset(pos, target).unwrap();
*out_offset = (offset as FixedIsize).to_le_bytes();
}
}