Fix Array-with-TableStream-pointer expansion

When expanding and moving an ArrayRun that contains a pointer to table streams, the array needs to move, which means the table stream may temporarily have no pointers to the table. When the table re-adds itself on the other side, it's important that the table stream already know about the format of the parent table. For example, the length token may come from one of the parent element's fields.
This commit is contained in:
Benjamin Popp 2021-07-01 22:21:54 -05:00
parent d7e6d60d31
commit 24ae357a22
4 changed files with 15 additions and 5 deletions

View File

@ -440,7 +440,7 @@ namespace HavenSoft.HexManiac.Core.Models {
Debug.Assert(run.Start == source, $"{runs[i].Start:X6}{pointerSourceName} expects a pointer at {source:X6}, but the next pointer was found at {run.Start:X6}.");
Debug.Assert(ReadPointer(source) == runs[i].Start, $"Expected {source:X6} to point to {runs[i].Start:X6}{pointerSourceName}");
} else if (run is ITableRun) {
Debug.Assert(run.Start <= source);
Debug.Assert(run.Start <= source, $"The run at {runs[i].Start:X6} expects a pointer at {source:X6}, but found a table at {run.Start:X6}.");
Debug.Assert(ReadPointer(source) == runs[i].Start);
} else {
Debug.Fail($"Pointer must be a {nameof(PointerRun)} or live within an {nameof(ITableRun)}");

View File

@ -78,7 +78,9 @@ namespace HavenSoft.HexManiac.Core.Models.Runs {
} else {
IFormattedRun run = destinationRun;
hasError = destinationRun.Start != destination;
if (currentSegment is ArrayRunPointerSegment pointerSegment) {
// if the run isn't a ITableRun, parse the data to see if it's valid
// if it _is_ an ITableRun, skip this step
if (currentSegment is ArrayRunPointerSegment pointerSegment && !(run is ITableRun)) {
hasError |= FormatRunFactory.GetStrategy(pointerSegment.InnerFormat).TryParseData(data, string.Empty, destination, ref run).HasError;
}
}

View File

@ -30,7 +30,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs.Factory {
return tableStream.DeserializeRun("", token);
}
public override void UpdateNewRunFromPointerFormat(IDataModel model, ModelDelta token, string name, IReadOnlyList<ArrayRunElementSegment> sourceSegments, int parentIndex, ref IFormattedRun run) {
if (!TableStreamRun.TryParseTableStream(model, run.Start, run.PointerSources, name, Format, null, out var runAttempt)) return;
if (!TableStreamRun.TryParseTableStream(model, run.Start, run.PointerSources, name, Format, sourceSegments, out var runAttempt)) return;
model.ClearFormat(token, run.Start, runAttempt.Length);
run = runAttempt;
}

View File

@ -80,7 +80,14 @@ namespace HavenSoft.HexManiac.Core.Models.Runs {
return null;
}
public TableStreamRun(IDataModel model, int start, SortedSpan<int> sources, string formatString, IReadOnlyList<ArrayRunElementSegment> parsedSegments, IStreamEndStrategy endStream) : base(start, sources) {
public TableStreamRun(
IDataModel model,
int start,
SortedSpan<int> sources,
string formatString,
IReadOnlyList<ArrayRunElementSegment> parsedSegments,
IStreamEndStrategy endStream
) : base(start, sources) {
if (parsedSegments == null) parsedSegments = ArrayRun.ParseSegments(formatString.Substring(1, formatString.Length - 2), model);
this.model = model;
ElementContent = parsedSegments;
@ -121,7 +128,8 @@ namespace HavenSoft.HexManiac.Core.Models.Runs {
return format;
}
protected override BaseRun Clone(SortedSpan<int> newPointerSources) => new TableStreamRun(model, Start, newPointerSources, FormatString, ElementContent, endStream);
protected override BaseRun Clone(SortedSpan<int> newPointerSources) =>
new TableStreamRun(model, Start, newPointerSources, FormatString, ElementContent, endStream);
#endregion