use allocative::Allocative;
use starlark_derive::starlark_module;
use crate as starlark;
use crate::codemap::Span;
use crate::environment::GlobalsBuilder;
use crate::typing::call_args::TyCallArgs;
use crate::typing::callable::TyCallable;
use crate::typing::error::TypingOrInternalError;
use crate::typing::function::TyCustomFunctionImpl;
use crate::typing::ParamSpec;
use crate::typing::Ty;
use crate::typing::TypingOracleCtx;
use crate::values::tuple::UnpackTuple;
use crate::values::typing::StarlarkIter;
use crate::values::FrozenValue;
use crate::values::Heap;
use crate::values::Value;
use crate::values::ValueOfUnchecked;
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Allocative)]
struct ZipType;
impl TyCustomFunctionImpl for ZipType {
fn as_callable(&self) -> TyCallable {
TyCallable::new(ParamSpec::args(Ty::iter(Ty::any())), Ty::list(Ty::any()))
}
fn validate_call(
&self,
_span: Span,
args: &TyCallArgs,
oracle: TypingOracleCtx,
) -> Result<Ty, TypingOrInternalError> {
let mut iter_item_types: Vec<Ty> = Vec::new();
for pos in &args.pos {
let item_ty = oracle.iter_item(pos.as_ref())?;
iter_item_types.push(item_ty);
}
if args.args.is_some() {
Ok(Ty::list(Ty::any()))
} else {
Ok(Ty::list(Ty::tuple(iter_item_types)))
}
}
}
#[starlark_module]
pub(crate) fn register_zip(globals: &mut GlobalsBuilder) {
#[starlark(speculative_exec_safe, ty_custom_function = ZipType)]
fn zip<'v>(
#[starlark(args)] args: UnpackTuple<ValueOfUnchecked<'v, StarlarkIter<FrozenValue>>>,
heap: &'v Heap,
) -> starlark::Result<Vec<Value<'v>>> {
let mut v = Vec::new();
let mut first = true;
for arg in args.items {
let mut idx = 0;
for e in arg.get().iterate(heap)? {
if first {
v.push(heap.alloc((e,)));
idx += 1;
} else if idx < v.len() {
v[idx] = v[idx].add(heap.alloc((e,)), heap)?;
idx += 1;
}
}
v.truncate(idx);
first = false;
}
Ok(v)
}
}