use std::cell::Cell;
use boa_gc::{Finalize, Trace};
use crate::{
builtins::iterable::IteratorRecord,
native_function::{CoroutineBranch, CoroutineState, NativeCoroutine},
};
#[derive(Trace, Finalize, Default)]
#[boa_gc(unsafe_no_drop)]
pub(crate) enum Drop {
#[default]
Completed,
Dropping {
limit: Option<u64>,
iterated: IteratorRecord,
},
Yielding {
iterated: IteratorRecord,
},
}
impl Drop {
#[allow(
clippy::new_ret_no_self,
reason = "slightly cleaner to have this be a `new` method"
)]
pub(crate) fn new(iterated: IteratorRecord, limit: Option<u64>) -> NativeCoroutine {
NativeCoroutine::from_copy_closure_with_captures(
|completion, state, context| {
let st = state.take();
match &st {
Self::Completed => {}
Self::Dropping { iterated, .. } | Self::Yielding { iterated } => {
iterated.if_abrupt_close_iterator(completion, context)?;
}
}
state.set(st);
loop {
let st = state.take();
match st {
Self::Completed => return CoroutineState::Break(Ok(())),
Self::Dropping {
limit: None,
mut iterated,
} => {
while !iterated.step(context).branch()? {}
return CoroutineState::Break(Ok(()));
}
Self::Dropping {
limit: Some(mut limit),
mut iterated,
} => {
while let Some(next) = limit.checked_sub(1) {
limit = next;
if iterated.step(context).branch()? {
return CoroutineState::Break(Ok(()));
}
}
state.set(Self::Yielding { iterated });
}
Self::Yielding { mut iterated } => {
return match iterated.step_value(context).branch()? {
Some(value) => {
state.set(Self::Yielding { iterated });
CoroutineState::Continue(value)
}
None => CoroutineState::Break(Ok(())),
};
}
}
}
},
Cell::new(Self::Dropping { limit, iterated }),
)
}
}