static TxtNode *StructNodeFromTextNode(DecodeState& ds, TxtNode *txtNode, StructMetadata *structDef)
{
    CrashIf(TextNode != txtNode->type);
    str::Slice slice(txtNode->valStart, txtNode->valEnd);
    TxtNode *node = new TxtNode(StructNode);
    node->children = new Vec<TxtNode*>();
    uint16_t fieldNo = 0;
    TxtNode *child;
    for (;;) {
        slice.SkipWsUntilNewline();
        if (slice.Finished())
            goto Error;
        child = new TxtNode(TextNode);
        child->valStart = slice.curr;
        slice.SkipNonWs();
        child->valEnd = slice.curr;
        FieldMetadata *fieldDef = structDef->fields + fieldNo;
        char *fieldName = (char*)ds.fieldNamesSeq + fieldDef->nameOffset;
        child->keyStart = fieldName;
        child->keyEnd = fieldName + str::Len(fieldName);
        node->children->Append(child);
        ++fieldNo;
        if (fieldNo == structDef->nFields)
            break;
    }
    return node;
Error:
    FreeTxtNode(node);
    return NULL;
}
static uint8_t *DeserializeCompact(DecodeState& ds, TxtNode *node, const StructMetadata *structDef)
{
    CrashIf(TextNode != node->type);
    TxtNode *structNode = StructNodeFromTextNode(ds, node, structDef);
    if (!structNode)
        return NULL;
    uint8_t *res = DeserializeRec(ds, structNode, structDef);
    FreeTxtNode(structNode);
    return res;
}