use std::sync::Arc;
use super::VmValue;
const RED_ZONE: usize = 256 * 1024;
const STACK_PER_SEGMENT: usize = 4 * 1024 * 1024;
#[inline]
pub fn guard_recursion<R>(f: impl FnOnce() -> R) -> R {
stacker::maybe_grow(RED_ZONE, STACK_PER_SEGMENT, f)
}
#[inline]
pub fn is_recursive_container(value: &VmValue) -> bool {
matches!(
value,
VmValue::List(_)
| VmValue::Set(_)
| VmValue::Dict(_)
| VmValue::Pair(_)
| VmValue::EnumVariant(_)
| VmValue::StructInstance { .. }
| VmValue::Closure(_)
)
}
pub fn depth_within(value: &VmValue, limit: usize) -> bool {
let mut stack: Vec<(&VmValue, usize)> = vec![(value, 0)];
while let Some((value, depth)) = stack.pop() {
if depth > limit {
return false;
}
match value {
VmValue::List(items) | VmValue::Set(items) => {
for item in items.iter() {
stack.push((item, depth + 1));
}
}
VmValue::Dict(map) => {
for item in map.values() {
stack.push((item, depth + 1));
}
}
VmValue::Pair(pair) => {
stack.push((&pair.0, depth + 1));
stack.push((&pair.1, depth + 1));
}
VmValue::EnumVariant(variant) => {
for field in variant.fields.iter() {
stack.push((field, depth + 1));
}
}
VmValue::StructInstance { fields, .. } => {
for field in fields.iter().flatten() {
stack.push((field, depth + 1));
}
}
_ => {}
}
}
true
}
#[inline]
pub fn dismantle(value: VmValue) {
if is_recursive_container(&value) {
dismantle_values(std::iter::once(value));
}
}
pub fn dismantle_values<I: IntoIterator<Item = VmValue>>(values: I) {
let mut stack: Vec<VmValue> = values.into_iter().collect();
while let Some(value) = stack.pop() {
match value {
VmValue::List(items) | VmValue::Set(items) => {
if let Some(mut items) = Arc::into_inner(items) {
stack.append(&mut items);
}
}
VmValue::Dict(map) => {
if let Some(map) = Arc::into_inner(map) {
stack.extend(map.into_iter().map(|(_, value)| value));
}
}
VmValue::Pair(pair) => {
if let Some(pair) = Arc::into_inner(pair) {
stack.push(pair.0);
stack.push(pair.1);
}
}
VmValue::EnumVariant(variant) => {
if let Some(variant) = Arc::into_inner(variant) {
if let Some(mut fields) = Arc::into_inner(variant.fields) {
stack.append(&mut fields);
}
}
}
VmValue::StructInstance { fields, .. } => {
if let Some(fields) = Arc::into_inner(fields) {
stack.extend(fields.into_iter().flatten());
}
}
VmValue::Closure(closure) => {
if let Some(mut closure) = Arc::into_inner(closure) {
for scope in &mut closure.env.scopes {
if let Some(vars) = Arc::get_mut(&mut scope.vars) {
stack.extend(std::mem::take(vars).into_values().map(|(v, _)| v));
}
}
}
}
_ => {}
}
}
}