vrl/value/kind/
conversion.rs

1use super::{Collection, Field, Index, Kind};
2
3impl Kind {
4    /// Get the inner object collection.
5    ///
6    /// This returns `None` if the type is not known to be an object.
7    #[must_use]
8    pub const fn as_object(&self) -> Option<&Collection<Field>> {
9        self.object.as_ref()
10    }
11
12    /// Get a mutable reference to the inner object collection.
13    ///
14    /// This returns `None` if the type is not known to be an object.
15    #[must_use]
16    pub fn as_object_mut(&mut self) -> Option<&mut Collection<Field>> {
17        self.object.as_mut()
18    }
19
20    /// Take an object `Collection` type out of the `Kind`.
21    ///
22    /// This returns `None` if the type is not known to be an object.
23    #[must_use]
24    pub fn into_object(self) -> Option<Collection<Field>> {
25        self.object
26    }
27
28    /// Get the inner array collection.
29    ///
30    /// This returns `None` if the type is not known to be an array.
31    #[must_use]
32    pub const fn as_array(&self) -> Option<&Collection<Index>> {
33        self.array.as_ref()
34    }
35
36    /// Get a mutable reference to the inner array collection.
37    ///
38    /// This returns `None` if the type is not known to be an array.
39    #[must_use]
40    pub fn as_array_mut(&mut self) -> Option<&mut Collection<Index>> {
41        self.array.as_mut()
42    }
43
44    /// Take an array `Collection` type out of the `Kind`.
45    ///
46    /// This returns `None` if the type is not known to be an array.
47    #[must_use]
48    pub fn into_array(self) -> Option<Collection<Index>> {
49        self.array
50    }
51
52    /// Returns `Kind`, with non-primitive states removed.
53    ///
54    /// That is, it returns `self,` but removes the `object` and `array` states.
55    #[must_use]
56    pub fn to_primitives(mut self) -> Self {
57        self.remove_array();
58        self.remove_object();
59        self
60    }
61
62    /// VRL has an interesting property where accessing an undefined value "upgrades"
63    /// it to a "null" value.
64    /// This should be used in places those implicit upgrades can occur.
65    // see: https://github.com/vectordotdev/vector/issues/13594
66    #[must_use]
67    pub fn upgrade_undefined(mut self) -> Self {
68        if self.is_never() {
69            return self;
70        }
71        if self.contains_undefined() {
72            self = self.without_undefined().or_null();
73        }
74        self
75    }
76}
77
78impl From<Collection<Field>> for Kind {
79    fn from(collection: Collection<Field>) -> Self {
80        Self::object(collection)
81    }
82}
83
84impl From<Collection<Index>> for Kind {
85    fn from(collection: Collection<Index>) -> Self {
86        Self::array(collection)
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use std::collections::{BTreeMap, HashMap};
93
94    use super::*;
95
96    #[test]
97    fn test_to_primitive() {
98        struct TestCase {
99            kind: Kind,
100            want: Kind,
101        }
102
103        for (title, TestCase { kind, want }) in HashMap::from([
104            (
105                "single primitive",
106                TestCase {
107                    kind: Kind::bytes(),
108                    want: Kind::bytes(),
109                },
110            ),
111            (
112                "multiple primitives",
113                TestCase {
114                    kind: Kind::integer().or_regex(),
115                    want: Kind::integer().or_regex(),
116                },
117            ),
118            (
119                "array only",
120                TestCase {
121                    kind: Kind::array(BTreeMap::default()),
122                    want: Kind::never(),
123                },
124            ),
125            (
126                "object only",
127                TestCase {
128                    kind: Kind::object(BTreeMap::default()),
129                    want: Kind::never(),
130                },
131            ),
132            (
133                "collections removed",
134                TestCase {
135                    kind: Kind::timestamp()
136                        .or_integer()
137                        .or_object(BTreeMap::default())
138                        .or_array(BTreeMap::default()),
139                    want: Kind::timestamp().or_integer(),
140                },
141            ),
142        ]) {
143            assert_eq!(kind.to_primitives(), want, "{title}");
144        }
145    }
146}