use std::slice;
use std::vec;
use crate::typing::Ty;
use crate::values::tuple::TupleRef;
use crate::values::type_repr::StarlarkTypeRepr;
use crate::values::UnpackValue;
use crate::values::Value;
#[derive(Default, Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct UnpackTuple<T> {
pub items: Vec<T>,
}
impl<T: StarlarkTypeRepr> StarlarkTypeRepr for UnpackTuple<T> {
fn starlark_type_repr() -> Ty {
Ty::tuple_of(T::starlark_type_repr())
}
}
impl<'v, T: UnpackValue<'v>> UnpackValue<'v> for UnpackTuple<T> {
fn unpack_value(value: Value<'v>) -> Option<Self> {
let tuple = TupleRef::from_value(value)?;
let mut items = Vec::with_capacity(tuple.len());
for v in tuple.iter() {
items.push(T::unpack_value(v)?);
}
Some(UnpackTuple { items })
}
}
impl<T> IntoIterator for UnpackTuple<T> {
type Item = T;
type IntoIter = vec::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.items.into_iter()
}
}
impl<'a, T> IntoIterator for &'a UnpackTuple<T> {
type Item = &'a T;
type IntoIter = slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.items.iter()
}
}
impl<'a, T> IntoIterator for &'a mut UnpackTuple<T> {
type Item = &'a mut T;
type IntoIter = slice::IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.items.iter_mut()
}
}
#[cfg(test)]
mod tests {
use crate::values::tuple::unpack::UnpackTuple;
use crate::values::Heap;
use crate::values::UnpackValue;
#[test]
fn test_unpack() {
let heap = Heap::new();
let v = heap.alloc(("a", "b"));
assert_eq!(
vec!["a", "b"],
UnpackTuple::<&str>::unpack_value(v).unwrap().items
);
assert!(UnpackTuple::<u32>::unpack_value(v).is_none());
assert!(UnpackTuple::<&str>::unpack_value(heap.alloc(1)).is_none());
}
}