starlark/values/types/tuple/
unpack.rs

1/*
2 * Copyright 2018 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
18use std::slice;
19use std::vec;
20
21use crate::typing::Ty;
22use crate::values::tuple::TupleRef;
23use crate::values::type_repr::StarlarkTypeRepr;
24use crate::values::UnpackValue;
25use crate::values::Value;
26
27/// Unpack a value of type `tuple[T, ...]` into a vec.
28#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
29pub struct UnpackTuple<T> {
30    /// Unpacked items.
31    pub items: Vec<T>,
32}
33
34impl<T: Default> Default for UnpackTuple<T> {
35    fn default() -> Self {
36        UnpackTuple { items: Vec::new() }
37    }
38}
39
40impl<T: StarlarkTypeRepr> StarlarkTypeRepr for UnpackTuple<T> {
41    type Canonical = UnpackTuple<T::Canonical>;
42
43    fn starlark_type_repr() -> Ty {
44        Ty::tuple_of(T::starlark_type_repr())
45    }
46}
47
48impl<'v, T: UnpackValue<'v>> UnpackValue<'v> for UnpackTuple<T> {
49    type Error = <T as UnpackValue<'v>>::Error;
50
51    fn unpack_value_impl(value: Value<'v>) -> Result<Option<Self>, Self::Error> {
52        let Some(tuple) = TupleRef::from_value(value) else {
53            return Ok(None);
54        };
55        // TODO(nga): should not allocate if the first element is of the wrong type.
56        let mut items = Vec::with_capacity(tuple.len());
57        for v in tuple.iter() {
58            let Some(v) = T::unpack_value_impl(v)? else {
59                return Ok(None);
60            };
61            items.push(v);
62        }
63        Ok(Some(UnpackTuple { items }))
64    }
65}
66
67impl<T> IntoIterator for UnpackTuple<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 UnpackTuple<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 UnpackTuple<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::tuple::unpack::UnpackTuple;
97    use crate::values::Heap;
98    use crate::values::UnpackValue;
99
100    #[test]
101    fn test_unpack() {
102        let heap = Heap::new();
103        let v = heap.alloc(("a", "b"));
104        assert_eq!(
105            vec!["a", "b"],
106            UnpackTuple::<&str>::unpack_value(v).unwrap().unwrap().items
107        );
108        assert!(UnpackTuple::<u32>::unpack_value(v).unwrap().is_none());
109        assert!(
110            UnpackTuple::<&str>::unpack_value(heap.alloc(1))
111                .unwrap()
112                .is_none()
113        );
114    }
115}