///|
/// Array keywords: prefixItems, items, maxItems, minItems, uniqueItems,
/// contains, minContains, maxContains (2020-12).
fn kw_array(
ctx : Ctx,
obj : Map[String, Json],
inst : Json,
ip : Path,
sp : Path,
) -> Unit {
guard inst is Array(items) else { return }
let len = items.length()
match obj.get("maxItems") {
Some(Number(m, ..)) =>
if len > m.to_int() {
ctx.add_error(
ip,
sp.key("maxItems"),
"maxItems",
"array has \{len} items, more than maxItems \{m.to_int()}",
)
}
_ => ()
}
match obj.get("minItems") {
Some(Number(m, ..)) =>
if len < m.to_int() {
ctx.add_error(
ip,
sp.key("minItems"),
"minItems",
"array has \{len} items, fewer than minItems \{m.to_int()}",
)
}
_ => ()
}
// prefixItems applies to the leading positions; items applies to the rest.
let mut prefix = 0
let ip_str = render_path(ip)
match obj.get("prefixItems") {
Some(Array(schemas)) => {
prefix = schemas.length()
let bound = if prefix < len { prefix } else { len }
for i in 0.. ()
}
match obj.get("items") {
Some(schema) =>
for i in prefix.. ()
}
match obj.get("uniqueItems") {
Some(True) => {
let mut i = 0
let mut j = 0
let mut dup = false
while i < len && !dup {
j = i + 1
while j < len && !dup {
if items[i] == items[j] {
ctx.add_error(
ip.idx(j),
sp.key("uniqueItems"),
"uniqueItems",
"array items are not unique (items \{i} and \{j} are equal)",
)
dup = true
}
j = j + 1
}
i = i + 1
}
}
_ => ()
}
// contains: at least minContains (default 1 when `contains` is present)
// and at most maxContains elements must match the contains-schema.
match obj.get("contains") {
Some(contains_schema) => {
let mut matched = 0
for i in 0.. m.to_int()
_ => 1
}
if matched < min {
ctx.add_error(
ip,
sp.key("contains"),
"contains",
"\{matched} elements match `contains`, fewer than minContains \{min}",
)
}
match obj.get("maxContains") {
Some(Number(m, ..)) =>
if matched > m.to_int() {
ctx.add_error(
ip,
sp.key("maxContains"),
"maxContains",
"\{matched} elements match `contains`, more than maxContains \{m.to_int()}",
)
}
_ => ()
}
}
None => ()
}
}