starlark/values/types/
list_or_tuple.rs

1/*
2 * Copyright 2019 The Starlark in Rust Authors.
3 * Copyright (c) Facebook, Inc. and its affiliates.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18//! Utility for unpacking a value of type `list[T]` or `tuple[T, ...]` into a vec.
19
20use std::slice;
21use std::vec;
22
23use either::Either;
24
25use crate::typing::Ty;
26use crate::values::list::UnpackList;
27use crate::values::tuple::UnpackTuple;
28use crate::values::type_repr::StarlarkTypeRepr;
29use crate::values::UnpackValue;
30use crate::values::Value;
31
32/// Unpack a value of type `list[T]` or `tuple[T, ...]` into a vec.
33#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
34pub struct UnpackListOrTuple<T> {
35    /// Unpacked items of the list or tuple.
36    pub items: Vec<T>,
37}
38
39impl<T> Default for UnpackListOrTuple<T> {
40    fn default() -> Self {
41        UnpackListOrTuple { items: Vec::new() }
42    }
43}
44
45impl<T: StarlarkTypeRepr> StarlarkTypeRepr for UnpackListOrTuple<T> {
46    type Canonical = <Either<UnpackList<T>, UnpackTuple<T>> as StarlarkTypeRepr>::Canonical;
47
48    fn starlark_type_repr() -> Ty {
49        Either::<UnpackList<T>, UnpackTuple<T>>::starlark_type_repr()
50    }
51}
52
53impl<'v, T: UnpackValue<'v>> UnpackValue<'v> for UnpackListOrTuple<T> {
54    type Error = <T as UnpackValue<'v>>::Error;
55
56    fn unpack_value_impl(value: Value<'v>) -> Result<Option<Self>, Self::Error> {
57        match Either::<UnpackList<T>, UnpackTuple<T>>::unpack_value_impl(value)
58            .map_err(|e| e.into_inner())?
59        {
60            Some(Either::Left(l)) => Ok(Some(UnpackListOrTuple { items: l.items })),
61            Some(Either::Right(r)) => Ok(Some(UnpackListOrTuple { items: r.items })),
62            None => Ok(None),
63        }
64    }
65}
66
67impl<T> IntoIterator for UnpackListOrTuple<T> {
68    type Item = T;
69    type IntoIter = vec::IntoIter<T>;
70
71    fn into_iter(self) -> Self::IntoIter {
72        self.items.into_iter()
73    }
74}
75
76impl<'a, T> IntoIterator for &'a UnpackListOrTuple<T> {
77    type Item = &'a T;
78    type IntoIter = slice::Iter<'a, T>;
79
80    fn into_iter(self) -> Self::IntoIter {
81        self.items.iter()
82    }
83}
84
85impl<'a, T> IntoIterator for &'a mut UnpackListOrTuple<T> {
86    type Item = &'a mut T;
87    type IntoIter = slice::IterMut<'a, T>;
88
89    fn into_iter(self) -> Self::IntoIter {
90        self.items.iter_mut()
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use crate::values::types::list_or_tuple::UnpackListOrTuple;
97    use crate::values::Heap;
98    use crate::values::UnpackValue;
99
100    #[test]
101    fn test_unpack() {
102        let heap = Heap::new();
103        let list = heap.alloc(vec!["a", "b"]);
104        let tuple = heap.alloc(("a", "b"));
105        let list_of_ints = heap.alloc(vec![1, 2]);
106        let tuple_of_ints = heap.alloc((1, 2));
107        assert_eq!(
108            vec!["a", "b"],
109            UnpackListOrTuple::<&str>::unpack_value(list)
110                .unwrap()
111                .unwrap()
112                .items
113        );
114        assert_eq!(
115            vec!["a", "b"],
116            UnpackListOrTuple::<&str>::unpack_value(tuple)
117                .unwrap()
118                .unwrap()
119                .items
120        );
121        assert!(
122            UnpackListOrTuple::<&str>::unpack_value(list_of_ints)
123                .unwrap()
124                .is_none()
125        );
126        assert!(
127            UnpackListOrTuple::<&str>::unpack_value(tuple_of_ints)
128                .unwrap()
129                .is_none()
130        );
131        assert!(
132            UnpackListOrTuple::<&str>::unpack_value(heap.alloc(1))
133                .unwrap()
134                .is_none()
135        );
136    }
137}