Skip to content

Commit 9166b45

Browse files
committed
feat(lang): add std.contains function
1 parent 63c39dd commit 9166b45

File tree

9 files changed

+77
-0
lines changed

9 files changed

+77
-0
lines changed

rsjsonnet-lang/src/program/data.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,7 @@ pub(super) enum BuiltInFunc {
785785
Avg,
786786
MinArray,
787787
MaxArray,
788+
Contains,
788789
// Sets
789790
Set,
790791
SetInter,

rsjsonnet-lang/src/program/eval/call.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,12 @@ impl<'p> Evaluator<'_, 'p> {
916916
self.state_stack.push(State::DoThunk(arg1.view()));
917917
self.state_stack.push(State::DoThunk(arg0.view()));
918918
}
919+
BuiltInFunc::Contains => {
920+
let [arg0, arg1] = check_num_args(args);
921+
self.state_stack
922+
.push(State::StdContains { value: arg1.view() });
923+
self.state_stack.push(State::DoThunk(arg0.view()));
924+
}
919925
BuiltInFunc::Set => {
920926
let [arg0, arg1] = check_num_args(args);
921927
self.state_stack.push(State::StdSet);

rsjsonnet-lang/src/program/eval/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1470,6 +1470,8 @@ impl<'p, 'a> Evaluator<'a, 'p> {
14701470
cur_index,
14711471
max_index,
14721472
} => self.do_std_max_array_check_item(keyf, array, cur_index, max_index)?,
1473+
State::StdContains { value } => self.do_std_contains(value)?,
1474+
State::StdContainsItem { array, index } => self.do_std_contains_item(array, index),
14731475
State::StdSet => self.do_std_set()?,
14741476
State::StdSetUniq {
14751477
orig_array,

rsjsonnet-lang/src/program/eval/state.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,13 @@ pub(super) enum State<'a, 'p> {
437437
cur_index: usize,
438438
max_index: usize,
439439
},
440+
StdContains {
441+
value: GcView<ThunkData<'p>>,
442+
},
443+
StdContainsItem {
444+
array: GcView<ArrayData<'p>>,
445+
index: usize,
446+
},
440447
StdSet,
441448
StdSetUniq {
442449
orig_array: GcView<ArrayData<'p>>,

rsjsonnet-lang/src/program/eval/stdlib.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3098,6 +3098,48 @@ impl<'p> Evaluator<'_, 'p> {
30983098
Ok(())
30993099
}
31003100

3101+
pub(super) fn do_std_contains(&mut self, value: GcView<ThunkData<'p>>) -> EvalResult<()> {
3102+
let array = self.value_stack.pop().unwrap();
3103+
let array = self.expect_std_func_arg_array(array, "contains", 0)?;
3104+
3105+
if let Some(item0) = array.first() {
3106+
let item0 = item0.view();
3107+
3108+
self.state_stack
3109+
.push(State::StdContainsItem { array, index: 0 });
3110+
self.state_stack.push(State::EqualsValue);
3111+
self.state_stack.push(State::DoThunk(item0));
3112+
self.state_stack.push(State::DoThunk(value.clone()));
3113+
self.state_stack.push(State::DoThunk(value));
3114+
} else {
3115+
self.value_stack.push(ValueData::Bool(false));
3116+
}
3117+
3118+
Ok(())
3119+
}
3120+
3121+
pub(super) fn do_std_contains_item(&mut self, array: GcView<ArrayData<'p>>, index: usize) {
3122+
let equal = self.bool_stack.pop().unwrap();
3123+
if equal {
3124+
*self.value_stack.last_mut().unwrap() = ValueData::Bool(true);
3125+
} else {
3126+
let next_index = index + 1;
3127+
if let Some(next_item) = array.get(next_index) {
3128+
let next_item = next_item.view();
3129+
self.value_stack
3130+
.push(self.value_stack.last().unwrap().clone());
3131+
self.state_stack.push(State::StdContainsItem {
3132+
array,
3133+
index: next_index,
3134+
});
3135+
self.state_stack.push(State::EqualsValue);
3136+
self.state_stack.push(State::DoThunk(next_item));
3137+
} else {
3138+
*self.value_stack.last_mut().unwrap() = ValueData::Bool(false);
3139+
}
3140+
}
3141+
}
3142+
31013143
pub(super) fn do_std_set(&mut self) -> EvalResult<()> {
31023144
let keyf = self.value_stack.pop().unwrap();
31033145
let arr = self.value_stack.pop().unwrap();

rsjsonnet-lang/src/program/stdlib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ impl<'p> Program<'p> {
227227
add_simple("any", BuiltInFunc::Any, &["arr"]);
228228
add_simple("sum", BuiltInFunc::Sum, &["sum"]);
229229
add_simple("avg", BuiltInFunc::Avg, &["avg"]);
230+
add_simple("contains", BuiltInFunc::Contains, &["arr", "elem"]);
230231
add_simple("base64", BuiltInFunc::Base64, &["input"]);
231232
add_simple(
232233
"base64DecodeBytes",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
std.contains(null, 0)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: first argument of `std.contains` is expected to be array, got null
2+
note: while evaluating call to `contains`
3+
--> invalid_arg.jsonnet:1:1
4+
|
5+
1 | std.contains(null, 0)
6+
| ---------------------
7+
note: during top-level value evaluation
8+

ui-tests/pass/stdlib/contains.jsonnet

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
std.assertEqual(std.contains([], "x"), false) &&
2+
std.assertEqual(std.contains(["x"], "x"), true) &&
3+
std.assertEqual(std.contains(["x"], "y"), false) &&
4+
std.assertEqual(std.contains(["a", "b", "c"], "x"), false) &&
5+
std.assertEqual(std.contains(["a", "b", "c"], "a"), true) &&
6+
std.assertEqual(std.contains(["a", "b", "c"], "b"), true) &&
7+
std.assertEqual(std.contains(["a", "b", "c"], "c"), true) &&
8+
9+
true

0 commit comments

Comments
 (0)