vrl/compiler/
compile_config.rs

1use crate::path::OwnedTargetPath;
2use std::{
3    any::{Any, TypeId},
4    collections::{BTreeSet, HashMap},
5};
6
7type AnyMap = HashMap<TypeId, Box<dyn Any>>;
8
9pub struct CompileConfig {
10    /// Custom context injected by the external environment
11    custom: AnyMap,
12    read_only_paths: BTreeSet<ReadOnlyPath>,
13    check_unused_expressions: bool,
14}
15
16impl Default for CompileConfig {
17    fn default() -> Self {
18        CompileConfig {
19            custom: AnyMap::default(),
20            read_only_paths: BTreeSet::default(),
21            check_unused_expressions: true,
22        }
23    }
24}
25
26impl CompileConfig {
27    /// Get external context data from the external environment.
28    #[must_use]
29    pub fn get_custom<T: 'static>(&self) -> Option<&T> {
30        self.custom
31            .get(&TypeId::of::<T>())
32            .and_then(|t| t.downcast_ref())
33    }
34
35    /// Get external context data from the external environment.
36    pub fn get_custom_mut<T: 'static>(&mut self) -> Option<&mut T> {
37        self.custom
38            .get_mut(&TypeId::of::<T>())
39            .and_then(|t| t.downcast_mut())
40    }
41
42    /// Sets the external context data for VRL functions to use.
43    pub fn set_custom<T: 'static>(&mut self, data: T) {
44        self.custom.insert(TypeId::of::<T>(), Box::new(data) as _);
45    }
46
47    pub fn custom_mut(&mut self) -> &mut AnyMap {
48        &mut self.custom
49    }
50
51    /// Marks everything as read only. Any mutations on read-only values will result in a
52    /// compile time error.
53    pub fn set_read_only(&mut self) {
54        self.set_read_only_path(OwnedTargetPath::event_root(), true);
55        self.set_read_only_path(OwnedTargetPath::metadata_root(), true);
56    }
57
58    #[must_use]
59    pub fn is_read_only_path(&self, path: &OwnedTargetPath) -> bool {
60        for read_only_path in &self.read_only_paths {
61            // any paths that are a parent of read-only paths also can't be modified
62            if read_only_path.path.can_start_with(path) {
63                return true;
64            }
65
66            if read_only_path.recursive {
67                if path.can_start_with(&read_only_path.path) {
68                    return true;
69                }
70            } else if path == &read_only_path.path {
71                return true;
72            }
73        }
74        false
75    }
76
77    /// Adds a path that is considered read only. Assignments to any paths that match
78    /// will fail at compile time.
79    pub fn set_read_only_path(&mut self, path: OwnedTargetPath, recursive: bool) {
80        self.read_only_paths
81            .insert(ReadOnlyPath { path, recursive });
82    }
83
84    #[must_use]
85    pub fn unused_expression_check_enabled(&self) -> bool {
86        self.check_unused_expressions
87    }
88
89    pub fn disable_unused_expression_check(&mut self) {
90        self.check_unused_expressions = false;
91    }
92}
93
94#[derive(Debug, Clone, Ord, Eq, PartialEq, PartialOrd)]
95struct ReadOnlyPath {
96    path: OwnedTargetPath,
97    recursive: bool,
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103
104    #[derive(PartialEq, Eq, Debug)]
105    struct Potato(usize);
106
107    #[test]
108    fn can_get_custom() {
109        let mut config = CompileConfig::default();
110        config.set_custom(Potato(42));
111
112        assert_eq!(&Potato(42), config.get_custom::<Potato>().unwrap());
113    }
114
115    #[test]
116    fn can_get_custom_mut() {
117        let mut config = CompileConfig::default();
118        config.set_custom(Potato(42));
119
120        let potato = config.get_custom_mut::<Potato>().unwrap();
121        potato.0 = 43;
122
123        assert_eq!(&Potato(43), config.get_custom::<Potato>().unwrap());
124    }
125}