use std::fmt;
pub const MAX_INLINE_LEN: usize = 12;
pub const PREFIX_LEN: usize = 4;
#[derive(Clone, Copy)]
#[repr(C)]
pub union StringView {
inline: StringViewInline,
reference: StringViewReference,
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct StringViewInline {
pub len: i32,
pub inline: [u8; 12],
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct StringViewReference {
pub len: i32,
pub prefix: [u8; 4],
pub buffer_idx: i32,
pub offset: i32,
}
const _: () = {
assert!(
std::mem::size_of::<StringView>() == 16,
"string view must be 16 bytes"
);
};
impl StringView {
pub const EMPTY: Self = StringView {
inline: StringViewInline {
len: 0,
inline: [0; 12],
},
};
pub fn new_inline(data: &[u8]) -> Self {
let len = data.len();
assert!(len <= MAX_INLINE_LEN);
let mut inline = StringViewInline {
len: len as i32,
inline: [0; 12],
};
inline.inline[0..len].copy_from_slice(data);
StringView { inline }
}
pub fn new_reference(data: &[u8], buffer_idx: i32, offset: i32) -> Self {
let len = data.len();
assert!(len > MAX_INLINE_LEN);
let mut reference = StringViewReference {
len: len as i32,
prefix: [0; 4],
buffer_idx,
offset,
};
reference.prefix.copy_from_slice(&data[0..4]);
StringView { reference }
}
pub const fn is_inline(&self) -> bool {
unsafe { self.inline.len <= 12 }
}
pub const fn is_reference(&self) -> bool {
unsafe { self.inline.len > 12 }
}
pub fn data_len(&self) -> i32 {
unsafe { self.inline.len }
}
pub const fn to_bytes(self) -> [u8; 16] {
unsafe { std::mem::transmute::<Self, [u8; 16]>(self) }
}
pub const fn from_bytes(buf: [u8; 16]) -> Self {
unsafe { std::mem::transmute::<[u8; 16], Self>(buf) }
}
pub const fn as_inline(&self) -> &StringViewInline {
debug_assert!(self.is_inline());
unsafe { &self.inline }
}
pub const fn as_reference(&self) -> &StringViewReference {
debug_assert!(!self.is_inline());
unsafe { &self.reference }
}
pub const fn as_inline_mut(&mut self) -> &mut StringViewInline {
debug_assert!(self.is_inline());
unsafe { &mut self.inline }
}
pub const fn as_reference_mut(&mut self) -> &mut StringViewReference {
debug_assert!(!self.is_inline());
unsafe { &mut self.reference }
}
}
impl fmt::Debug for StringView {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_inline() {
write!(f, "{:?}", self.as_inline())
} else {
write!(f, "{:?}", self.as_reference())
}
}
}
#[derive(Clone, Copy)]
#[repr(C)]
pub union StringPtr {
inline: StringPtrInline,
reference: StringPtrReference,
}
impl From<StringViewInline> for StringPtr {
fn from(value: StringViewInline) -> Self {
StringPtr {
inline: StringPtrInline {
len: value.len,
inline: value.inline,
},
}
}
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct StringPtrInline {
pub len: i32,
pub inline: [u8; 12],
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct StringPtrReference {
pub len: i32,
pub prefix: [u8; 4],
pub ptr: *const u8,
}
const _: () = {
assert!(
std::mem::size_of::<StringPtr>() == 16,
"string ptr must be 16 bytes"
);
};
impl StringPtr {
pub const EMPTY: Self = StringPtr {
inline: StringPtrInline {
len: 0,
inline: [0; 12],
},
};
pub fn new_inline(data: &[u8]) -> Self {
let len = data.len();
assert!(len <= MAX_INLINE_LEN);
let mut inline = StringPtrInline {
len: len as i32,
inline: [0; 12],
};
inline.inline[0..len].copy_from_slice(data);
StringPtr { inline }
}
pub fn new_reference(data: &[u8]) -> Self {
let len = data.len();
assert!(len > MAX_INLINE_LEN);
let mut reference = StringPtrReference {
len: len as i32,
prefix: [0; 4],
ptr: data.as_ptr(),
};
reference.prefix.copy_from_slice(&data[0..4]);
StringPtr { reference }
}
pub fn as_bytes(&self) -> &[u8] {
unsafe {
if self.is_inline() {
&self.inline.inline[0..(self.inline.len as usize)]
} else {
std::slice::from_raw_parts(self.reference.ptr, self.reference.len as usize)
}
}
}
pub const fn is_inline(&self) -> bool {
unsafe { self.inline.len <= 12 }
}
pub const fn is_reference(&self) -> bool {
unsafe { self.inline.len > 12 }
}
pub fn data_len(&self) -> i32 {
unsafe { self.inline.len }
}
pub const fn to_bytes(self) -> [u8; 16] {
unsafe { std::mem::transmute::<Self, [u8; 16]>(self) }
}
pub const fn from_bytes(buf: [u8; 16]) -> Self {
unsafe { std::mem::transmute::<[u8; 16], Self>(buf) }
}
pub const fn as_inline(&self) -> &StringPtrInline {
debug_assert!(self.is_inline());
unsafe { &self.inline }
}
pub const fn as_reference(&self) -> &StringPtrReference {
debug_assert!(!self.is_inline());
unsafe { &self.reference }
}
pub const fn as_inline_mut(&mut self) -> &mut StringPtrInline {
debug_assert!(self.is_inline());
unsafe { &mut self.inline }
}
pub const fn as_reference_mut(&mut self) -> &mut StringPtrReference {
debug_assert!(!self.is_inline());
unsafe { &mut self.reference }
}
}
impl fmt::Debug for StringPtr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_inline() {
write!(f, "{:?}", self.as_inline())
} else {
write!(f, "{:?}", self.as_reference())
}
}
}