///|
fn evaluate_array(
program : Program,
plan : ArrayPlan,
value : Json,
path : String,
failures : Array[Fault]?,
depth : Int32,
limit : Int32,
scope : Array[Int32],
evaluated : EvaluationMarks?,
) -> Bool raise {
guard value is Array(values) else { return true }
let mut valid = true
if plan.minimum is Some(bound) && values.length() < bound {
valid = fail(
failures,
path,
pointer_step(plan.path, "minItems"),
"minItems",
"array has too few items",
)
if failures is None {
return false
}
}
if plan.maximum is Some(bound) && values.length() > bound {
valid = fail(
failures,
path,
pointer_step(plan.path, "maxItems"),
"maxItems",
"array has too many items",
)
if failures is None {
return false
}
}
let contains = fresh_marks(evaluated is Some(_))
let mut prefix_valid = true
let mut items_valid = true
let mut matches = 0
for index, child in values {
let child_path = pointer_step(path, index.to_string())
let schema = if index < plan.prefix.length() {
Some(plan.prefix[index])
} else {
plan.items
}
if schema is Some(node) &&
!evaluate(
program,
node,
child,
child_path,
failures,
depth + 1,
limit,
scope~,
) {
valid = false
if index < plan.prefix.length() {
prefix_valid = false
} else {
items_valid = false
}
if failures is None {
return false
}
}
if plan.contains is Some(node) &&
evaluate(program, node, child, child_path, None, depth + 1, limit, scope~) {
matches += 1
if contains is Some(marks) {
marks.items.add(index)
}
}
if plan.unique {
for previous in 0.. bound {
valid = fail(
failures,
path,
pointer_step(plan.path, "maxContains"),
"maxContains",
"too many items matched contains",
)
contains_valid = false
}
if contains_valid {
merge_marks(evaluated, contains)
}
}
valid
}