#[cfg(feature = "alloc")]
use alloc::alloc::{Layout, alloc, dealloc, realloc};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::borrow::{Borrow, BorrowMut};
use core::cmp::Ordering;
use core::fmt::{self, Debug, Formatter};
use core::hash::{Hash, Hasher};
use core::iter::FromIterator;
use core::ops::{Deref, DerefMut, Index, IndexMut};
use core::slice::SliceIndex;
use core::{cmp, ptr};
use crate::value::{TypeTag, Value};
#[repr(C, align(8))]
struct ArrayHeader {
len: usize,
cap: usize,
}
#[repr(transparent)]
#[derive(Clone)]
pub struct VArray(pub(crate) Value);
impl VArray {
fn layout(cap: usize) -> Layout {
Layout::new::<ArrayHeader>()
.extend(Layout::array::<Value>(cap).unwrap())
.unwrap()
.0
.pad_to_align()
}
#[cfg(feature = "alloc")]
fn alloc(cap: usize) -> *mut ArrayHeader {
unsafe {
let layout = Self::layout(cap);
let ptr = alloc(layout).cast::<ArrayHeader>();
(*ptr).len = 0;
(*ptr).cap = cap;
ptr
}
}
#[cfg(feature = "alloc")]
fn realloc_ptr(ptr: *mut ArrayHeader, new_cap: usize) -> *mut ArrayHeader {
unsafe {
let old_cap = (*ptr).cap;
let old_layout = Self::layout(old_cap);
let new_layout = Self::layout(new_cap);
let new_ptr =
realloc(ptr.cast::<u8>(), old_layout, new_layout.size()).cast::<ArrayHeader>();
(*new_ptr).cap = new_cap;
new_ptr
}
}
#[cfg(feature = "alloc")]
fn dealloc_ptr(ptr: *mut ArrayHeader) {
unsafe {
let cap = (*ptr).cap;
let layout = Self::layout(cap);
dealloc(ptr.cast::<u8>(), layout);
}
}
fn header(&self) -> &ArrayHeader {
unsafe { &*(self.0.heap_ptr() as *const ArrayHeader) }
}
fn header_mut(&mut self) -> &mut ArrayHeader {
unsafe { &mut *(self.0.heap_ptr_mut() as *mut ArrayHeader) }
}
fn items_ptr(&self) -> *const Value {
unsafe { (self.0.heap_ptr() as *const ArrayHeader).add(1).cast() }
}
fn items_ptr_mut(&mut self) -> *mut Value {
unsafe { (self.0.heap_ptr_mut() as *mut ArrayHeader).add(1).cast() }
}
#[cfg(feature = "alloc")]
#[must_use]
pub fn new() -> Self {
Self::with_capacity(0)
}
#[cfg(feature = "alloc")]
#[must_use]
pub fn with_capacity(cap: usize) -> Self {
unsafe {
let ptr = Self::alloc(cap);
VArray(Value::new_ptr(ptr.cast(), TypeTag::ArrayOrTrue))
}
}
#[must_use]
pub fn len(&self) -> usize {
self.header().len
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[must_use]
pub fn capacity(&self) -> usize {
self.header().cap
}
#[must_use]
pub fn as_slice(&self) -> &[Value] {
unsafe { core::slice::from_raw_parts(self.items_ptr(), self.len()) }
}
pub fn as_mut_slice(&mut self) -> &mut [Value] {
unsafe { core::slice::from_raw_parts_mut(self.items_ptr_mut(), self.len()) }
}
#[cfg(feature = "alloc")]
pub fn reserve(&mut self, additional: usize) {
let current_cap = self.capacity();
let desired_cap = self
.len()
.checked_add(additional)
.expect("capacity overflow");
if current_cap >= desired_cap {
return;
}
let new_cap = cmp::max(current_cap * 2, desired_cap.max(4));
unsafe {
let new_ptr = Self::realloc_ptr(self.0.heap_ptr_mut().cast(), new_cap);
self.0.set_ptr(new_ptr.cast());
}
}
#[cfg(feature = "alloc")]
pub fn push(&mut self, value: impl Into<Value>) {
self.reserve(1);
unsafe {
let len = self.header().len;
let ptr = self.items_ptr_mut().add(len);
ptr.write(value.into());
self.header_mut().len = len + 1;
}
}
pub fn pop(&mut self) -> Option<Value> {
let len = self.len();
if len == 0 {
return None;
}
unsafe {
self.header_mut().len = len - 1;
let ptr = self.items_ptr_mut().add(len - 1);
Some(ptr.read())
}
}
#[cfg(feature = "alloc")]
pub fn insert(&mut self, index: usize, value: impl Into<Value>) {
let len = self.len();
assert!(index <= len, "index out of bounds");
self.reserve(1);
unsafe {
let ptr = self.items_ptr_mut().add(index);
if index < len {
ptr::copy(ptr, ptr.add(1), len - index);
}
ptr.write(value.into());
self.header_mut().len = len + 1;
}
}
pub fn remove(&mut self, index: usize) -> Option<Value> {
let len = self.len();
if index >= len {
return None;
}
unsafe {
let ptr = self.items_ptr_mut().add(index);
let value = ptr.read();
if index < len - 1 {
ptr::copy(ptr.add(1), ptr, len - index - 1);
}
self.header_mut().len = len - 1;
Some(value)
}
}
pub fn swap_remove(&mut self, index: usize) -> Option<Value> {
let len = self.len();
if index >= len {
return None;
}
self.as_mut_slice().swap(index, len - 1);
self.pop()
}
pub fn clear(&mut self) {
while self.pop().is_some() {}
}
pub fn truncate(&mut self, len: usize) {
while self.len() > len {
self.pop();
}
}
#[must_use]
pub fn get(&self, index: usize) -> Option<&Value> {
self.as_slice().get(index)
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut Value> {
self.as_mut_slice().get_mut(index)
}
#[cfg(feature = "alloc")]
pub fn shrink_to_fit(&mut self) {
let len = self.len();
let cap = self.capacity();
if len < cap {
unsafe {
let new_ptr = Self::realloc_ptr(self.0.heap_ptr_mut().cast(), len);
self.0.set_ptr(new_ptr.cast());
}
}
}
pub(crate) fn clone_impl(&self) -> Value {
let mut new = VArray::with_capacity(self.len());
for v in self.as_slice() {
new.push(v.clone());
}
new.0
}
pub(crate) fn drop_impl(&mut self) {
self.clear();
unsafe {
Self::dealloc_ptr(self.0.heap_ptr_mut().cast());
}
}
}
pub struct ArrayIntoIter {
array: VArray,
}
impl Iterator for ArrayIntoIter {
type Item = Value;
fn next(&mut self) -> Option<Self::Item> {
if self.array.is_empty() {
None
} else {
self.array.remove(0)
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.array.len();
(len, Some(len))
}
}
impl ExactSizeIterator for ArrayIntoIter {}
impl IntoIterator for VArray {
type Item = Value;
type IntoIter = ArrayIntoIter;
fn into_iter(self) -> Self::IntoIter {
ArrayIntoIter { array: self }
}
}
impl<'a> IntoIterator for &'a VArray {
type Item = &'a Value;
type IntoIter = core::slice::Iter<'a, Value>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
impl<'a> IntoIterator for &'a mut VArray {
type Item = &'a mut Value;
type IntoIter = core::slice::IterMut<'a, Value>;
fn into_iter(self) -> Self::IntoIter {
self.as_mut_slice().iter_mut()
}
}
impl Deref for VArray {
type Target = [Value];
fn deref(&self) -> &[Value] {
self.as_slice()
}
}
impl DerefMut for VArray {
fn deref_mut(&mut self) -> &mut [Value] {
self.as_mut_slice()
}
}
impl Borrow<[Value]> for VArray {
fn borrow(&self) -> &[Value] {
self.as_slice()
}
}
impl BorrowMut<[Value]> for VArray {
fn borrow_mut(&mut self) -> &mut [Value] {
self.as_mut_slice()
}
}
impl AsRef<[Value]> for VArray {
fn as_ref(&self) -> &[Value] {
self.as_slice()
}
}
impl<I: SliceIndex<[Value]>> Index<I> for VArray {
type Output = I::Output;
fn index(&self, index: I) -> &Self::Output {
&self.as_slice()[index]
}
}
impl<I: SliceIndex<[Value]>> IndexMut<I> for VArray {
fn index_mut(&mut self, index: I) -> &mut Self::Output {
&mut self.as_mut_slice()[index]
}
}
impl PartialEq for VArray {
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl Eq for VArray {}
impl PartialOrd for VArray {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let mut iter1 = self.iter();
let mut iter2 = other.iter();
loop {
match (iter1.next(), iter2.next()) {
(Some(a), Some(b)) => match a.partial_cmp(b) {
Some(Ordering::Equal) => continue,
other => return other,
},
(None, None) => return Some(Ordering::Equal),
(Some(_), None) => return Some(Ordering::Greater),
(None, Some(_)) => return Some(Ordering::Less),
}
}
}
}
impl Hash for VArray {
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_slice().hash(state);
}
}
impl Debug for VArray {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Debug::fmt(self.as_slice(), f)
}
}
impl Default for VArray {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "alloc")]
impl<T: Into<Value>> FromIterator<T> for VArray {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let iter = iter.into_iter();
let (lower, _) = iter.size_hint();
let mut array = VArray::with_capacity(lower);
for v in iter {
array.push(v);
}
array
}
}
#[cfg(feature = "alloc")]
impl<T: Into<Value>> Extend<T> for VArray {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
let iter = iter.into_iter();
let (lower, _) = iter.size_hint();
self.reserve(lower);
for v in iter {
self.push(v);
}
}
}
#[cfg(feature = "alloc")]
impl<T: Into<Value>> From<Vec<T>> for VArray {
fn from(vec: Vec<T>) -> Self {
vec.into_iter().collect()
}
}
#[cfg(feature = "alloc")]
impl<T: Into<Value> + Clone> From<&[T]> for VArray {
fn from(slice: &[T]) -> Self {
slice.iter().cloned().collect()
}
}
impl AsRef<Value> for VArray {
fn as_ref(&self) -> &Value {
&self.0
}
}
impl AsMut<Value> for VArray {
fn as_mut(&mut self) -> &mut Value {
&mut self.0
}
}
impl From<VArray> for Value {
fn from(arr: VArray) -> Self {
arr.0
}
}
impl VArray {
#[inline]
pub fn into_value(self) -> Value {
self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ValueType;
#[test]
fn test_new() {
let arr = VArray::new();
assert!(arr.is_empty());
assert_eq!(arr.len(), 0);
}
#[test]
fn test_push_pop() {
let mut arr = VArray::new();
arr.push(Value::from(1));
arr.push(Value::from(2));
arr.push(Value::from(3));
assert_eq!(arr.len(), 3);
assert_eq!(arr.pop().unwrap().as_number().unwrap().to_i64(), Some(3));
assert_eq!(arr.pop().unwrap().as_number().unwrap().to_i64(), Some(2));
assert_eq!(arr.pop().unwrap().as_number().unwrap().to_i64(), Some(1));
assert!(arr.pop().is_none());
}
#[test]
fn test_insert_remove() {
let mut arr = VArray::new();
arr.push(Value::from(1));
arr.push(Value::from(3));
arr.insert(1, Value::from(2));
assert_eq!(arr.len(), 3);
assert_eq!(arr[0].as_number().unwrap().to_i64(), Some(1));
assert_eq!(arr[1].as_number().unwrap().to_i64(), Some(2));
assert_eq!(arr[2].as_number().unwrap().to_i64(), Some(3));
let removed = arr.remove(1).unwrap();
assert_eq!(removed.as_number().unwrap().to_i64(), Some(2));
assert_eq!(arr.len(), 2);
}
#[test]
fn test_clone() {
let mut arr = VArray::new();
arr.push(Value::from("hello"));
arr.push(Value::from(42));
let arr2 = arr.clone();
assert_eq!(arr, arr2);
}
#[test]
fn inline_strings_in_array_remain_inline() {
let mut arr = VArray::new();
for len in 0..=crate::string::VString::INLINE_LEN_MAX.min(6) {
let s = "a".repeat(len);
arr.push(Value::from(s.as_str()));
}
for value in arr.iter() {
if value.value_type() == ValueType::String {
assert!(
value.is_inline_string(),
"array element lost inline representation"
);
}
}
let cloned = arr.clone();
for value in cloned.iter() {
if value.value_type() == ValueType::String {
assert!(
value.is_inline_string(),
"clone should preserve inline storage"
);
}
}
}
#[test]
fn test_iter() {
let mut arr = VArray::new();
arr.push(Value::from(1));
arr.push(Value::from(2));
let sum: i64 = arr
.iter()
.map(|v| v.as_number().unwrap().to_i64().unwrap())
.sum();
assert_eq!(sum, 3);
}
#[test]
fn test_collect() {
let arr: VArray = vec![1i64, 2, 3].into_iter().map(Value::from).collect();
assert_eq!(arr.len(), 3);
}
}