use std::{
iter,
ops::{Bound, Index, IndexMut, RangeBounds},
slice::{self, SliceIndex},
};
use allocator_api2::vec;
use gc_arena::allocator_api::MetricsAlloc;
use crate::{Context, FromMultiValue, FromValue, IntoMultiValue, IntoValue, TypeError, Value};
pub struct Stack<'gc, 'a> {
values: &'a mut vec::Vec<Value<'gc>, MetricsAlloc<'gc>>,
bottom: usize,
}
impl<'gc, 'a> Stack<'gc, 'a> {
pub fn new(values: &'a mut vec::Vec<Value<'gc>, MetricsAlloc<'gc>>, bottom: usize) -> Self {
assert!(values.len() >= bottom);
Self { values, bottom }
}
pub fn sub_stack(&mut self, bottom: usize) -> Stack<'gc, '_> {
Stack {
values: self.values,
bottom: self.bottom + bottom,
}
}
pub fn get(&self, i: usize) -> Value<'gc> {
self.values
.get(self.bottom + i)
.copied()
.unwrap_or_default()
}
pub fn push_back(&mut self, value: Value<'gc>) {
self.values.push(value);
}
pub fn push_front(&mut self, value: Value<'gc>) {
self.values.insert(self.bottom, value);
}
pub fn pop_back(&mut self) -> Value<'gc> {
if self.values.len() > self.bottom {
self.values.pop().unwrap()
} else {
Value::Nil
}
}
pub fn pop_front(&mut self) -> Value<'gc> {
if self.values.len() > self.bottom {
self.values.remove(self.bottom)
} else {
Value::Nil
}
}
pub fn len(&self) -> usize {
self.values.len() - self.bottom
}
pub fn is_empty(&self) -> bool {
self.values.len() == self.bottom
}
pub fn clear(&mut self) {
self.values.truncate(self.bottom);
}
pub fn resize(&mut self, size: usize) {
self.values.resize(self.bottom + size, Value::Nil);
}
pub fn drain<R: RangeBounds<usize>>(
&mut self,
range: R,
) -> vec::Drain<Value<'gc>, MetricsAlloc<'gc>> {
let start = match range.start_bound().cloned() {
Bound::Included(r) => Bound::Included(self.bottom + r),
Bound::Excluded(r) => Bound::Excluded(self.bottom + r),
Bound::Unbounded => Bound::Included(self.bottom),
};
let end = match range.end_bound().cloned() {
Bound::Included(r) => Bound::Included(self.bottom + r),
Bound::Excluded(r) => Bound::Excluded(self.bottom + r),
Bound::Unbounded => Bound::Unbounded,
};
self.values.drain((start, end))
}
pub fn into_back(&mut self, ctx: Context<'gc>, v: impl IntoMultiValue<'gc>) {
for v in v.into_multi_value(ctx) {
self.values.push(v.into_value(ctx));
}
}
pub fn into_front(&mut self, ctx: Context<'gc>, v: impl IntoMultiValue<'gc>) {
let mut c = 0;
for v in v.into_multi_value(ctx) {
c += 1;
self.values.push(v.into_value(ctx));
}
self.values[self.bottom..].rotate_right(c);
}
pub fn from_back<V: FromValue<'gc>>(&mut self, ctx: Context<'gc>) -> Result<V, TypeError> {
V::from_value(ctx, self.pop_back())
}
pub fn from_front<V: FromValue<'gc>>(&mut self, ctx: Context<'gc>) -> Result<V, TypeError> {
V::from_value(ctx, self.pop_front())
}
pub fn replace(&mut self, ctx: Context<'gc>, v: impl IntoMultiValue<'gc>) {
self.clear();
self.extend(v.into_multi_value(ctx));
}
pub fn consume<V: FromMultiValue<'gc>>(&mut self, ctx: Context<'gc>) -> Result<V, TypeError> {
V::from_multi_value(ctx, self.drain(..))
}
}
impl<'gc: 'b, 'a, 'b> IntoIterator for &'b Stack<'gc, 'a> {
type Item = Value<'gc>;
type IntoIter = iter::Copied<slice::Iter<'b, Value<'gc>>>;
fn into_iter(self) -> Self::IntoIter {
self.values[self.bottom..].iter().copied()
}
}
impl<'gc, 'a> Extend<Value<'gc>> for Stack<'gc, 'a> {
fn extend<T: IntoIterator<Item = Value<'gc>>>(&mut self, iter: T) {
self.values.extend(iter);
}
}
impl<'gc, 'a, 'b> Extend<Value<'gc>> for &'b mut Stack<'gc, 'a> {
fn extend<T: IntoIterator<Item = Value<'gc>>>(&mut self, iter: T) {
self.values.extend(iter);
}
}
impl<'gc: 'b, 'a, 'b> Extend<&'a Value<'gc>> for Stack<'gc, 'a> {
fn extend<T: IntoIterator<Item = &'a Value<'gc>>>(&mut self, iter: T) {
self.values.extend(iter);
}
}
impl<'gc: 'b, 'a, 'b, 'c> Extend<&'b Value<'gc>> for &'c mut Stack<'gc, 'a> {
fn extend<T: IntoIterator<Item = &'b Value<'gc>>>(&mut self, iter: T) {
self.values.extend(iter);
}
}
impl<'gc, 'a, I: SliceIndex<[Value<'gc>]>> Index<I> for Stack<'gc, 'a> {
type Output = <Vec<Value<'gc>> as Index<I>>::Output;
fn index(&self, index: I) -> &Self::Output {
&self.values[self.bottom..][index]
}
}
impl<'gc, 'a, I: SliceIndex<[Value<'gc>]>> IndexMut<I> for Stack<'gc, 'a> {
fn index_mut(&mut self, index: I) -> &mut Self::Output {
&mut self.values[self.bottom..][index]
}
}