use std::cell::Cell;
use boa_gc::{Finalize, Trace};
use crate::{
JsValue,
builtins::iterable::IteratorRecord,
native_function::{CoroutineBranch, CoroutineState, NativeCoroutine},
};
#[derive(Trace, Finalize, Default)]
#[boa_gc(unsafe_no_drop)]
pub(crate) enum Take {
#[default]
Completed,
Yielding {
remaining: Option<u64>,
iterated: IteratorRecord,
},
}
impl Take {
#[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();
let (mut iterated, remaining) = match st {
Self::Completed => return CoroutineState::Break(Ok(())),
Self::Yielding {
remaining: None,
iterated,
} => {
iterated.if_abrupt_close_iterator(completion, context)?;
(iterated, None)
}
Self::Yielding {
remaining: Some(remaining),
iterated,
} => {
iterated.if_abrupt_close_iterator(completion, context)?;
let Some(remaining) = remaining.checked_sub(1) else {
iterated.close(Ok(JsValue::undefined()), context).branch()?;
return CoroutineState::Break(Ok(()));
};
(iterated, Some(remaining))
}
};
match iterated.step_value(context).branch()? {
Some(value) => {
state.set(Self::Yielding {
remaining,
iterated,
});
CoroutineState::Continue(value)
}
None => CoroutineState::Break(Ok(())),
}
},
Cell::new(Self::Yielding {
iterated,
remaining: limit,
}),
)
}
}