vrl/value/kind/collection/
index.rs

1use crate::path::OwnedSegment;
2use crate::value::kind::Collection;
3use crate::value::kind::collection::{CollectionKey, CollectionRemove};
4
5/// An `index` type that can be used in `Collection<Index>`
6#[derive(Debug, Clone, Default, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
7pub struct Index(usize);
8
9impl std::fmt::Display for Index {
10    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
11        self.0.fmt(f)
12    }
13}
14
15impl Index {
16    /// Get the [`usize`] value of the index.
17    #[must_use]
18    pub const fn to_usize(self) -> usize {
19        self.0
20    }
21}
22
23impl CollectionKey for Index {
24    fn to_segment(&self) -> OwnedSegment {
25        OwnedSegment::Index(self.0 as isize)
26    }
27}
28
29impl Collection<Index> {
30    /// Returns the largest known index, or None if no known indices exist.
31    #[must_use]
32    pub fn largest_known_index(&self) -> Option<usize> {
33        self.known()
34            .iter()
35            .filter_map(|(i, kind)| {
36                if kind.contains_any_defined() {
37                    Some(i.to_usize())
38                } else {
39                    None
40                }
41            })
42            .max()
43    }
44
45    /// Converts a negative index to a positive index (only if the exact positive index is known).
46    #[must_use]
47    pub fn get_positive_index(&self, index: isize) -> Option<usize> {
48        if self.unknown_kind().contains_any_defined() {
49            // positive index can't be known if there are unknown values
50            return None;
51        }
52
53        let negative_index = (-index) as usize;
54        if let Some(largest_known_index) = self.largest_known_index()
55            && largest_known_index >= negative_index - 1
56        {
57            // The exact index to remove is known.
58            return Some(((largest_known_index as isize) + 1 + index) as usize);
59        }
60        // Removing a non-existing index
61        None
62    }
63
64    /// The minimum possible length an array could be given the type information.
65    #[must_use]
66    pub fn min_length(&self) -> usize {
67        self.largest_known_index().map_or(0, |i| i + 1)
68    }
69
70    /// The exact length of the array, if it can be proven. Otherwise, None.
71    #[must_use]
72    pub fn exact_length(&self) -> Option<usize> {
73        if self.unknown_kind().contains_any_defined() {
74            None
75        } else {
76            // there are no defined unknown values, so all indices must be known
77            Some(self.min_length())
78        }
79    }
80
81    /// Removes the known value at the given index and shifts the
82    /// elements to the left.
83    pub fn remove_shift(&mut self, index: usize) {
84        let min_length = self.min_length();
85        self.known_mut().remove(&index.into());
86        for _ in index..min_length {
87            if let Some(value) = self.known_mut().remove(&(index + 1).into()) {
88                self.known_mut().insert(index.into(), value);
89            }
90        }
91    }
92}
93
94impl CollectionRemove for Collection<Index> {
95    type Key = Index;
96
97    fn remove_known(&mut self, key: &Index) {
98        self.remove_shift(key.0);
99    }
100}
101
102impl From<usize> for Index {
103    fn from(index: usize) -> Self {
104        (&index).into()
105    }
106}
107
108impl From<&usize> for Index {
109    fn from(index: &usize) -> Self {
110        Self(*index)
111    }
112}
113
114impl From<Index> for usize {
115    fn from(index: Index) -> Self {
116        (&index).into()
117    }
118}
119
120impl From<&Index> for usize {
121    fn from(index: &Index) -> Self {
122        index.0
123    }
124}
125
126impl<T: Into<Self>> std::ops::Add<T> for Index {
127    type Output = Self;
128
129    fn add(self, other: T) -> Self {
130        Self(self.0 + other.into().0)
131    }
132}
133
134impl<T: Into<Self>> std::ops::Sub<T> for Index {
135    type Output = Self;
136
137    fn sub(self, other: T) -> Self {
138        Self(self.0 - other.into().0)
139    }
140}