message MessageStacksMessage {
  // All of the edge labels are converted to Uint8Array's,
  // then packed sequentially into this one big
  // array. Lengths are stored in the next field.
  required bytes edgeLabelsPacked = 1;
  // For Uint8Array's, this is length; for strings, it is ~length
  // (bitwise NOT). That way, we store the type in the sign bit, at the
  // cost of only one bit.
  repeated sint32 edgeLabelLengths = 2 [packed=true];
  // For each edge, id of its head (parent). ID 0 = root,
  // ID n + 1 = tail of edgeLabels[n].
  repeated uint32 edgeParents = 3 [packed=true];
  // For each messageStack, id of its lowest edge.
  repeated uint32 messageStackIDs = 4 [packed=true];
  // When the batch contains a single messageStack, edgeParents and messageStackIDs
  // are []. Instead, just use the edge labels in order (given by
  // edgeLabelsPacked and edgeLabelLengths) as the single
  // messageStack.
}

message SavedStateTreeMessage {
  optional bytes self = 1;
  repeated string childrenKeys = 2;
  repeated SavedStateTreeMessage childrenValues = 3;
}