Merge pull request 'schemagen: keep null elements in arrays with nullable item types' (#8) from weaselbot/weaseljson:weaselbot/issue-5 into main

Reviewed-on: weaselab/weaseljson#8
This commit is contained in:
2026-06-18 20:07:48 +00:00
3 changed files with 64 additions and 1 deletions
+18
View File
@@ -71,6 +71,24 @@
}, },
"tree": { "tree": {
"$ref": "#/$defs/Node" "$ref": "#/$defs/Node"
},
"nullable_hobbies": {
"type": "array",
"items": {
"type": [
"string",
"null"
]
}
},
"nullable_scores": {
"type": "array",
"items": {
"type": [
"integer",
"null"
]
}
} }
}, },
"$defs": { "$defs": {
+13 -1
View File
@@ -86,7 +86,9 @@ int main() {
"value": 1, "value": 1,
"children": [ { "value": 2 }, { "value": 3 } ], "children": [ { "value": 2 }, { "value": 3 } ],
"next": { "value": 99 } "next": { "value": 99 }
} },
"nullable_hobbies": [null, "math", null, "lace", null],
"nullable_scores": [null, 10, null, 20, null]
})"; })";
RootBuilder b; RootBuilder b;
WeaselJsonStatus s = parseStrided(b, json); WeaselJsonStatus s = parseStrided(b, json);
@@ -116,6 +118,16 @@ int main() {
CHECK(r.tree && r.tree->children && (*r.tree->children)[0].value == 2); CHECK(r.tree && r.tree->children && (*r.tree->children)[0].value == 2);
CHECK(r.tree && r.tree->children && (*r.tree->children)[1].value == 3); CHECK(r.tree && r.tree->children && (*r.tree->children)[1].value == 3);
CHECK(r.tree && r.tree->next && r.tree->next->value == 99); CHECK(r.tree && r.tree->next && r.tree->next->value == 99);
CHECK(r.nullable_hobbies.has_value() && r.nullable_hobbies->size() == 5);
CHECK(r.nullable_hobbies && !(*r.nullable_hobbies)[0] &&
(*r.nullable_hobbies)[1] && *(*r.nullable_hobbies)[1] == "math" &&
!(*r.nullable_hobbies)[2] && (*r.nullable_hobbies)[3] &&
*(*r.nullable_hobbies)[3] == "lace" && !(*r.nullable_hobbies)[4]);
CHECK(r.nullable_scores.has_value() && r.nullable_scores->size() == 5);
CHECK(r.nullable_scores && !(*r.nullable_scores)[0] &&
(*r.nullable_scores)[1] && *(*r.nullable_scores)[1] == 10 &&
!(*r.nullable_scores)[2] && (*r.nullable_scores)[3] &&
*(*r.nullable_scores)[3] == 20 && !(*r.nullable_scores)[4]);
printf("ok happy path (byte-strided)\n"); printf("ok happy path (byte-strided)\n");
} }
} }
+33
View File
@@ -718,6 +718,34 @@ namespace {ns} {{"""
" }" " }"
) )
def _is_array_kind(self):
arrs = [n for n, _ in self.arr_types]
if not arrs:
return " bool isArrayKind(Kind) const { return false; }"
cases = " ".join(f"case Kind::{n}:" for n in arrs)
return (
" bool isArrayKind(Kind k) const {\n"
f" switch (k) {{ {cases} return true; default: return false; }}\n"
" }"
)
def _append_null(self):
lines = [
" void appendNull(Frame &f) {",
" switch (f.kind) {",
]
for name, tarr in self.arr_types:
vectype = self.base_cpp(tarr)
lines.append(f" case Kind::{name}: {{")
lines.append(f" auto *v = ({vectype} *)f.dest;")
lines.append(" v->emplace_back();")
lines.append(" return;")
lines.append(" }")
lines.append(" default: return;")
lines.append(" }")
lines.append(" }")
return "\n".join(lines)
def _is_strict(self): def _is_strict(self):
strict = [n for n, o in self.b.objects.items() if o.strict] strict = [n for n, o in self.b.objects.items() if o.strict]
if not strict: if not strict:
@@ -992,6 +1020,10 @@ private:
valueComplete(); valueComplete();
}} }}
{self._is_array_kind()}
{self._append_null()}
void cbNull() {{ void cbNull() {{
if (error_) return; if (error_) return;
Frame &f = stack_.back(); Frame &f = stack_.back();
@@ -999,6 +1031,7 @@ private:
SlotInfo si = slotInfoG(f); SlotInfo si = slotInfoG(f);
if (si.cat == Cat::Skip) {{ valueComplete(); return; }} if (si.cat == Cat::Skip) {{ valueComplete(); return; }}
if (!si.nullable) {{ reject(); return; }} if (!si.nullable) {{ reject(); return; }}
if (isArrayKind(f.kind)) appendNull(f); // keep null array elements
valueComplete(); // leave optional empty / pointer null valueComplete(); // leave optional empty / pointer null
}} }}