use std::slice;
use std::vec;
use either::Either;
use crate::typing::Ty;
use crate::values::list::UnpackList;
use crate::values::tuple::UnpackTuple;
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 UnpackListOrTuple<T> {
pub items: Vec<T>,
}
impl<T: StarlarkTypeRepr> StarlarkTypeRepr for UnpackListOrTuple<T> {
fn starlark_type_repr() -> Ty {
Either::<UnpackList<T>, UnpackTuple<T>>::starlark_type_repr()
}
}
impl<'v, T: UnpackValue<'v>> UnpackValue<'v> for UnpackListOrTuple<T> {
fn unpack_value(value: Value<'v>) -> Option<Self> {
match Either::<UnpackList<T>, UnpackTuple<T>>::unpack_value(value)? {
Either::Left(l) => Some(UnpackListOrTuple { items: l.items }),
Either::Right(r) => Some(UnpackListOrTuple { items: r.items }),
}
}
}
impl<T> IntoIterator for UnpackListOrTuple<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 UnpackListOrTuple<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 UnpackListOrTuple<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::types::list_or_tuple::UnpackListOrTuple;
use crate::values::Heap;
use crate::values::UnpackValue;
#[test]
fn test_unpack() {
let heap = Heap::new();
let list = heap.alloc(vec!["a", "b"]);
let tuple = heap.alloc(("a", "b"));
let list_of_ints = heap.alloc(vec![1, 2]);
let tuple_of_ints = heap.alloc((1, 2));
assert_eq!(
vec!["a", "b"],
UnpackListOrTuple::<&str>::unpack_value(list).unwrap().items
);
assert_eq!(
vec!["a", "b"],
UnpackListOrTuple::<&str>::unpack_value(tuple)
.unwrap()
.items
);
assert!(UnpackListOrTuple::<&str>::unpack_value(list_of_ints).is_none());
assert!(UnpackListOrTuple::<&str>::unpack_value(tuple_of_ints).is_none());
assert!(UnpackListOrTuple::<&str>::unpack_value(heap.alloc(1)).is_none());
}
}