hive_console_sdk/expressions/
lib.rs1use std::collections::BTreeMap;
2use std::sync::LazyLock;
3
4use vrl::{
5 compiler::{compile as vrl_compile, Program as VrlProgram, TargetValue as VrlTargetValue},
6 core::Value as VrlValue,
7 path::OwnedSegment,
8 prelude::{
9 state::RuntimeState as VrlState, Context as VrlContext, Function, TimeZone as VrlTimeZone,
10 },
11 value::Secrets as VrlSecrets,
12};
13
14use crate::expressions::{
15 error::{ExpressionCompileError, ExpressionExecutionError},
16 functions::env::Env,
17};
18
19static VRL_FUNCTIONS: LazyLock<Vec<Box<dyn Function>>> = LazyLock::new(|| {
20 let mut funcs = vrl::stdlib::all();
21 funcs.push(Box::new(Env));
23 funcs
24});
25static VRL_TIMEZONE: LazyLock<VrlTimeZone> = LazyLock::new(VrlTimeZone::default);
26
27pub trait FromVrlValue: Sized {
29 type Error: std::error::Error + Send + Sync + 'static;
31
32 fn from_vrl_value(value: VrlValue) -> Result<Self, Self::Error>;
35}
36
37pub trait ToVrlValue {
39 fn to_vrl_value(&self) -> VrlValue;
41}
42
43pub trait CompileExpression {
45 fn compile_expression(
48 &self,
49 functions: Option<&[Box<dyn Function>]>,
50 ) -> Result<VrlProgram, ExpressionCompileError>;
51}
52
53impl CompileExpression for str {
54 fn compile_expression(
55 &self,
56 functions: Option<&[Box<dyn Function>]>,
57 ) -> Result<VrlProgram, ExpressionCompileError> {
58 let functions = functions.unwrap_or(&VRL_FUNCTIONS);
59
60 let compilation_result = vrl_compile(self, functions).map_err(|diagnostics| {
61 ExpressionCompileError::new(
62 self.to_string(),
63 vrl::diagnostic::Formatter::new(self, diagnostics).to_string(),
76 )
77 })?;
78
79 Ok(compilation_result.program)
80 }
81}
82
83pub trait ExecutableProgram {
87 fn execute(&self, value: VrlValue) -> Result<VrlValue, ExpressionExecutionError>;
88}
89
90impl ExecutableProgram for VrlProgram {
91 #[inline]
92 fn execute(&self, value: VrlValue) -> Result<VrlValue, ExpressionExecutionError> {
93 let mut target = VrlTargetValue {
94 value,
95 metadata: VrlValue::Object(BTreeMap::new()),
96 secrets: VrlSecrets::default(),
97 };
98
99 let mut state = VrlState::default();
100 let mut ctx = VrlContext::new(&mut target, &mut state, &VRL_TIMEZONE);
101
102 Ok(self.resolve(&mut ctx)?)
103 }
104}
105
106#[derive(Debug, Default, Clone)]
107struct HintNode {
108 is_terminal: bool,
109 children: Vec<(String, HintNode)>,
110}
111
112impl HintNode {
113 fn insert(&mut self, path: &[OwnedSegment]) {
114 if path.is_empty() {
115 self.is_terminal = true;
116 return;
117 }
118
119 let OwnedSegment::Field(ref f) = path[0] else {
120 return; };
122 let key = f.as_str();
123
124 let child_idx = if let Some(idx) = self.children.iter().position(|(k, _)| k == key) {
125 idx
126 } else {
127 self.children.push((key.to_string(), HintNode::default()));
128 self.children.len() - 1
129 };
130
131 self.children[child_idx].1.insert(&path[1..]);
132 }
133
134 fn get_child(&self, key: &str) -> Option<&HintNode> {
135 self.children.iter().find(|(k, _)| k == key).map(|(_, v)| v)
136 }
137}
138
139#[derive(Debug, Default, Clone)]
143pub struct ProgramHints {
144 root: HintNode,
145}
146
147impl ProgramHints {
148 pub fn from_program(program: &VrlProgram) -> Self {
149 let mut root = HintNode::default();
150 for q in &program.info().target_queries {
151 root.insert(&q.path.segments);
152 }
153 Self { root }
154 }
155
156 pub fn context_builder<'a>(
157 &'a self,
158 build_fn: impl FnOnce(&mut VrlObjectBuilder<'a, '_>),
159 ) -> VrlValue {
160 VrlContextBuilder::new(self).build_root(build_fn)
161 }
162}
163
164pub struct VrlContextBuilder<'a> {
165 hints: &'a ProgramHints,
166}
167
168impl<'a> VrlContextBuilder<'a> {
169 fn new(hints: &'a ProgramHints) -> Self {
170 Self { hints }
171 }
172
173 fn build_root(&self, build_fn: impl FnOnce(&mut VrlObjectBuilder<'a, '_>)) -> VrlValue {
175 let mut map = BTreeMap::new();
176 let mut obj_builder = VrlObjectBuilder {
177 node: Some(&self.hints.root),
178 force_build: self.hints.root.is_terminal,
179 map: &mut map,
180 };
181 build_fn(&mut obj_builder);
182 VrlValue::Object(map)
183 }
184}
185
186enum ChildState<'a> {
187 Skip,
188 Force,
189 Explore(&'a HintNode),
190}
191
192pub struct VrlObjectBuilder<'a, 'b> {
194 node: Option<&'a HintNode>,
195 force_build: bool,
196 map: &'b mut BTreeMap<vrl::value::KeyString, VrlValue>,
197}
198
199impl<'a, 'b> VrlObjectBuilder<'a, 'b> {
200 pub fn insert_lazy<F>(&mut self, key: &'static str, value_fn: F) -> &mut Self
202 where
203 F: FnOnce() -> VrlValue,
204 {
205 if !matches!(self.evaluate_child(key), ChildState::Skip) {
206 self.map.insert(key.into(), value_fn());
207 }
208 self
209 }
210
211 pub fn insert_object(
214 &mut self,
215 key: &'static str,
216 build_fn: impl FnOnce(&mut VrlObjectBuilder<'a, '_>),
217 ) -> &mut Self {
218 let child_state = self.evaluate_child(key);
219
220 if matches!(child_state, ChildState::Skip) {
221 return self;
222 }
223
224 let mut inner_map = BTreeMap::new();
225
226 let force_build = matches!(child_state, ChildState::Force);
227 let child_node = match child_state {
228 ChildState::Explore(n) => Some(n),
229 _ => None,
230 };
231
232 let mut sub_builder = VrlObjectBuilder {
233 node: child_node,
234 force_build,
235 map: &mut inner_map,
236 };
237 build_fn(&mut sub_builder);
238
239 if !inner_map.is_empty() || force_build {
241 self.map.insert(key.into(), VrlValue::Object(inner_map));
242 }
243 self
244 }
245
246 #[inline]
248 fn evaluate_child(&self, key: &str) -> ChildState<'a> {
249 if self.force_build {
250 return ChildState::Force;
251 }
252
253 let Some(node) = self.node else {
254 return ChildState::Skip;
255 };
256
257 let Some(child) = node.get_child(key) else {
258 return ChildState::Skip;
259 };
260
261 if child.is_terminal {
262 return ChildState::Force;
263 }
264
265 ChildState::Explore(child)
266 }
267}