Skip to content

Commit 1bcee71

Browse files
committed
chore(stdlib): Resolve bool and int constants during compilation for
1 parent 9bbe02a commit 1bcee71

14 files changed

Lines changed: 215 additions & 105 deletions

File tree

benches/stdlib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ criterion_group!(
2323
community_id,
2424
compact,
2525
contains,
26+
contains_all,
2627
crc,
2728
decode_base16,
2829
decode_base64,
@@ -298,6 +299,20 @@ bench_function! {
298299
}
299300
}
300301

302+
bench_function! {
303+
contains_all => vrl::stdlib::ContainsAll;
304+
305+
case_sensitive {
306+
args: func_args![value: "abcdefg", substrings: value!(["cde"]), case_sensitive: true],
307+
want: Ok(value!(true)),
308+
}
309+
310+
case_insensitive {
311+
args: func_args![value: "abcdefg", substrings: value!(["CDE"]), case_sensitive: false],
312+
want: Ok(value!(true)),
313+
}
314+
}
315+
301316
bench_function! {
302317
crc => vrl::stdlib::Crc;
303318

src/compiler/value/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,9 @@ impl From<ValueError> for ExpressionError {
9999
}
100100
}
101101
}
102+
103+
impl From<ValueError> for Box<dyn crate::diagnostic::DiagnosticMessage> {
104+
fn from(error: ValueError) -> Self {
105+
Box::new(error) as _
106+
}
107+
}

src/stdlib/chunks.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::compiler::prelude::*;
2+
use crate::stdlib::util::IntegerConstOrExpr;
23

3-
fn chunks(value: Value, chunk_size: Value) -> Resolved {
4+
fn chunks(value: Value, chunk_size: i64) -> Resolved {
45
let bytes = value.try_bytes()?;
5-
let chunk_size = chunk_size.try_integer()?;
66

77
if chunk_size < 1 {
88
return Err(r#""chunk_size" must be at least 1 byte"#.into());
@@ -86,17 +86,15 @@ impl Function for Chunks {
8686
arguments: ArgumentList,
8787
) -> Compiled {
8888
let value = arguments.required("value");
89-
let chunk_size = arguments.required("chunk_size");
89+
let chunk_size = IntegerConstOrExpr::new(arguments.required("chunk_size"), state)?;
9090

9191
// chunk_size is converted to a usize, so if a user-supplied Value::Integer (i64) is
9292
// larger than the platform's usize::MAX, it could fail to convert.
93-
if let Some(literal) = chunk_size.resolve_constant(state)
94-
&& let Some(integer) = literal.as_integer()
95-
{
93+
if let IntegerConstOrExpr::Constant(integer) = chunk_size {
9694
if integer < 1 {
9795
return Err(function::Error::InvalidArgument {
9896
keyword: "chunk_size",
99-
value: literal,
97+
value: Value::Integer(integer),
10098
error: r#""chunk_size" must be at least 1 byte"#,
10199
}
102100
.into());
@@ -105,7 +103,7 @@ impl Function for Chunks {
105103
if usize::try_from(integer).is_err() {
106104
return Err(function::Error::InvalidArgument {
107105
keyword: "chunk_size",
108-
value: literal,
106+
value: Value::Integer(integer),
109107
error: r#""chunk_size" is too large"#,
110108
}
111109
.into());
@@ -119,7 +117,7 @@ impl Function for Chunks {
119117
#[derive(Debug, Clone)]
120118
struct ChunksFn {
121119
value: Box<dyn Expression>,
122-
chunk_size: Box<dyn Expression>,
120+
chunk_size: IntegerConstOrExpr,
123121
}
124122

125123
impl FunctionExpression for ChunksFn {
@@ -130,8 +128,8 @@ impl FunctionExpression for ChunksFn {
130128
chunks(value, chunk_size)
131129
}
132130

133-
fn type_def(&self, state: &TypeState) -> TypeDef {
134-
let not_literal = self.chunk_size.resolve_constant(state).is_none();
131+
fn type_def(&self, _state: &TypeState) -> TypeDef {
132+
let not_literal = matches!(self.chunk_size, IntegerConstOrExpr::Expression(_));
135133

136134
TypeDef::array(Collection::from_unknown(Kind::bytes())).maybe_fallible(not_literal)
137135
}

src/stdlib/contains.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::compiler::prelude::*;
22
use crate::stdlib::string_utils::convert_to_string;
3+
use crate::stdlib::util::BoolConstOrExpr;
34

45
static DEFAULT_CASE_SENSITIVE: Value = Value::Boolean(true);
56

@@ -18,8 +19,7 @@ const PARAMETERS: &[Parameter] = &[
1819
.default(&DEFAULT_CASE_SENSITIVE),
1920
];
2021

21-
fn contains(value: &Value, substring: &Value, case_sensitive: Value) -> Resolved {
22-
let case_sensitive = case_sensitive.try_boolean()?;
22+
fn contains(value: &Value, substring: &Value, case_sensitive: bool) -> Resolved {
2323
let value = convert_to_string(value, !case_sensitive)?;
2424
let substring = convert_to_string(substring, !case_sensitive)?;
2525
Ok(value.contains(substring.as_ref()).into())
@@ -51,13 +51,17 @@ impl Function for Contains {
5151

5252
fn compile(
5353
&self,
54-
_state: &state::TypeState,
54+
state: &state::TypeState,
5555
_ctx: &mut FunctionCompileContext,
5656
arguments: ArgumentList,
5757
) -> Compiled {
5858
let value = arguments.required("value");
5959
let substring = arguments.required("substring");
60-
let case_sensitive = arguments.optional("case_sensitive");
60+
let case_sensitive = BoolConstOrExpr::new_with_default(
61+
arguments.optional("case_sensitive"),
62+
state,
63+
&DEFAULT_CASE_SENSITIVE,
64+
)?;
6165

6266
Ok(ContainsFn {
6367
value,
@@ -87,16 +91,14 @@ impl Function for Contains {
8791
struct ContainsFn {
8892
value: Box<dyn Expression>,
8993
substring: Box<dyn Expression>,
90-
case_sensitive: Option<Box<dyn Expression>>,
94+
case_sensitive: BoolConstOrExpr,
9195
}
9296

9397
impl FunctionExpression for ContainsFn {
9498
fn resolve(&self, ctx: &mut Context) -> Resolved {
9599
let value = self.value.resolve(ctx)?;
96100
let substring = self.substring.resolve(ctx)?;
97-
let case_sensitive = self
98-
.case_sensitive
99-
.map_resolve_with_default(ctx, || DEFAULT_CASE_SENSITIVE.clone())?;
101+
let case_sensitive = self.case_sensitive.resolve(ctx)?;
100102

101103
contains(&value, &substring, case_sensitive)
102104
}
@@ -190,5 +192,14 @@ mod tests {
190192
want: Ok(value!(true)),
191193
tdef: TypeDef::boolean().infallible(),
192194
}
195+
196+
case_insensitive_invalid_type {
197+
args: func_args![value: value!("foobar"),
198+
substring: value!("BAR"),
199+
case_sensitive: value!("no")
200+
],
201+
want: Err("expected boolean, got string"),
202+
tdef: TypeDef::boolean().infallible(),
203+
}
193204
];
194205
}

src/stdlib/contains_all.rs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
use crate::compiler::prelude::*;
22
use crate::stdlib::string_utils::convert_to_string;
3+
use crate::stdlib::util::BoolConstOrExpr;
34

4-
fn contains_all(value: &Value, substrings: Value, case_sensitive: Option<Value>) -> Resolved {
5-
let case_sensitive = match case_sensitive {
6-
Some(v) => v.try_boolean()?,
7-
None => true,
8-
};
9-
5+
fn contains_all(value: &Value, substrings: Value, case_sensitive: bool) -> Resolved {
106
let value_string = convert_to_string(value, !case_sensitive)?;
117
let substring_values = substrings.try_array()?;
128

@@ -58,13 +54,17 @@ impl Function for ContainsAll {
5854

5955
fn compile(
6056
&self,
61-
_state: &state::TypeState,
57+
state: &state::TypeState,
6258
_ctx: &mut FunctionCompileContext,
6359
arguments: ArgumentList,
6460
) -> Compiled {
6561
let value = arguments.required("value");
6662
let substrings = arguments.required("substrings");
67-
let case_sensitive = arguments.optional("case_sensitive");
63+
let case_sensitive = BoolConstOrExpr::new_with_default(
64+
arguments.optional("case_sensitive"),
65+
state,
66+
&Value::Boolean(true),
67+
)?;
6868

6969
Ok(ContainsAllFn {
7070
value,
@@ -99,18 +99,14 @@ impl Function for ContainsAll {
9999
struct ContainsAllFn {
100100
value: Box<dyn Expression>,
101101
substrings: Box<dyn Expression>,
102-
case_sensitive: Option<Box<dyn Expression>>,
102+
case_sensitive: BoolConstOrExpr,
103103
}
104104

105105
impl FunctionExpression for ContainsAllFn {
106106
fn resolve(&self, ctx: &mut Context) -> Resolved {
107107
let value = self.value.resolve(ctx)?;
108108
let substrings = self.substrings.resolve(ctx)?;
109-
let case_sensitive = self
110-
.case_sensitive
111-
.as_ref()
112-
.map(|expr| expr.resolve(ctx))
113-
.transpose()?;
109+
let case_sensitive = self.case_sensitive.resolve(ctx)?;
114110
contains_all(&value, substrings, case_sensitive)
115111
}
116112

src/stdlib/ends_with.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::compiler::prelude::*;
22
use crate::stdlib::string_utils::convert_to_string;
3+
use crate::stdlib::util::BoolConstOrExpr;
34

45
static DEFAULT_CASE_SENSITIVE: Value = Value::Boolean(true);
56

@@ -18,8 +19,7 @@ const PARAMETERS: &[Parameter] = &[
1819
.default(&DEFAULT_CASE_SENSITIVE),
1920
];
2021

21-
fn ends_with(value: &Value, substring: &Value, case_sensitive: Value) -> Resolved {
22-
let case_sensitive = case_sensitive.try_boolean()?;
22+
fn ends_with(value: &Value, substring: &Value, case_sensitive: bool) -> Resolved {
2323
let value = convert_to_string(value, !case_sensitive)?;
2424
let substring = convert_to_string(substring, !case_sensitive)?;
2525
Ok(value.ends_with(substring.as_ref()).into())
@@ -51,13 +51,17 @@ impl Function for EndsWith {
5151

5252
fn compile(
5353
&self,
54-
_state: &state::TypeState,
54+
state: &state::TypeState,
5555
_ctx: &mut FunctionCompileContext,
5656
arguments: ArgumentList,
5757
) -> Compiled {
5858
let value = arguments.required("value");
5959
let substring = arguments.required("substring");
60-
let case_sensitive = arguments.optional("case_sensitive");
60+
let case_sensitive = BoolConstOrExpr::new_with_default(
61+
arguments.optional("case_sensitive"),
62+
state,
63+
&DEFAULT_CASE_SENSITIVE,
64+
)?;
6165

6266
Ok(EndsWithFn {
6367
value,
@@ -92,14 +96,12 @@ impl Function for EndsWith {
9296
struct EndsWithFn {
9397
value: Box<dyn Expression>,
9498
substring: Box<dyn Expression>,
95-
case_sensitive: Option<Box<dyn Expression>>,
99+
case_sensitive: BoolConstOrExpr,
96100
}
97101

98102
impl FunctionExpression for EndsWithFn {
99103
fn resolve(&self, ctx: &mut Context) -> Resolved {
100-
let case_sensitive = self
101-
.case_sensitive
102-
.map_resolve_with_default(ctx, || DEFAULT_CASE_SENSITIVE.clone())?;
104+
let case_sensitive = self.case_sensitive.resolve(ctx)?;
103105
let substring = self.substring.resolve(ctx)?;
104106
let value = self.value.resolve(ctx)?;
105107

src/stdlib/find.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::compiler::prelude::*;
2+
use crate::stdlib::util::IntegerConstOrExpr;
23

34
static DEFAULT_FROM: Value = Value::Integer(0);
45

@@ -13,10 +14,10 @@ const PARAMETERS: &[Parameter] = &[
1314
];
1415

1516
#[allow(clippy::cast_possible_wrap)]
16-
fn find(value: Value, pattern: Value, from: Value) -> Resolved {
17+
fn find(value: Value, pattern: Value, from: i64) -> Resolved {
1718
// TODO consider removal options
1819
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
19-
let from = from.try_integer()? as usize;
20+
let from = from as usize;
2021

2122
Ok(FindFn::find(value, pattern, from)?
2223
.map_or(Value::Null, |value| Value::Integer(value as i64)))
@@ -78,13 +79,14 @@ impl Function for Find {
7879

7980
fn compile(
8081
&self,
81-
_state: &state::TypeState,
82+
state: &state::TypeState,
8283
_ctx: &mut FunctionCompileContext,
8384
arguments: ArgumentList,
8485
) -> Compiled {
8586
let value = arguments.required("value");
8687
let pattern = arguments.required("pattern");
87-
let from = arguments.optional("from");
88+
let from =
89+
IntegerConstOrExpr::new_with_default(arguments.optional("from"), state, &DEFAULT_FROM)?;
8890

8991
Ok(FindFn {
9092
value,
@@ -99,7 +101,7 @@ impl Function for Find {
99101
struct FindFn {
100102
value: Box<dyn Expression>,
101103
pattern: Box<dyn Expression>,
102-
from: Option<Box<dyn Expression>>,
104+
from: IntegerConstOrExpr,
103105
}
104106

105107
impl FindFn {
@@ -145,9 +147,7 @@ impl FunctionExpression for FindFn {
145147
fn resolve(&self, ctx: &mut Context) -> Resolved {
146148
let value = self.value.resolve(ctx)?;
147149
let pattern = self.pattern.resolve(ctx)?;
148-
let from = self
149-
.from
150-
.map_resolve_with_default(ctx, || DEFAULT_FROM.clone())?;
150+
let from = self.from.resolve(ctx)?;
151151

152152
find(value, pattern, from)
153153
}

0 commit comments

Comments
 (0)