112 lines
4.1 KiB
Go
112 lines
4.1 KiB
Go
package engine
|
|
|
|
import "gitea.maximumdirect.net/eric/ConfigKit/internal/document"
|
|
|
|
// projectTierHistoryApplications composes each strict source's local projection
|
|
// with the tier operation. The retained source values stay in authored coordinates.
|
|
func projectTierHistoryApplications(applications []historyApplication, operations []sequenceHistoryContribution) []historyApplication {
|
|
mapped := false
|
|
for _, operation := range operations {
|
|
mapped = mapped || operation.mode == sequenceHistoryMapped
|
|
}
|
|
if !mapped {
|
|
return applications
|
|
}
|
|
projections := indexSequenceHistoryContributions(operations)
|
|
projected := cloneHistoryApplications(applications)
|
|
for index, original := range applications {
|
|
application := &projected[index]
|
|
var originalLookup *documentLookup
|
|
if path, found := projectSequenceOperationPath(original.path, projections); found {
|
|
application.path = path
|
|
}
|
|
for sequenceIndex, source := range original.sequences {
|
|
container := appendDestination(original.path, source.path)
|
|
operation, active := projections[container.String()]
|
|
if !active || operation.mode != sequenceHistoryMapped {
|
|
continue
|
|
}
|
|
if originalLookup == nil {
|
|
originalLookup = buildDocumentLookup(original.value)
|
|
}
|
|
value, found := documentAtPathWithLookup(original.value, source.path, originalLookup)
|
|
if !found || value.Kind != document.Sequence {
|
|
continue
|
|
}
|
|
sourceIndex := application.sequencesByPath[source.path.String()]
|
|
contribution := sequenceHistoryContribution{path: source.path.clone(), mode: sequenceHistoryMapped}
|
|
for inputIndex := range value.Sequence {
|
|
tierIndex := source.offset + inputIndex
|
|
if source.mode == sequenceHistoryMapped {
|
|
tierIndex = sourceIndex.outputForInput(inputIndex)
|
|
}
|
|
outputIndex, present := operation.projection.outputForInput(tierIndex)
|
|
if !present {
|
|
continue
|
|
}
|
|
contribution.items = append(contribution.items, sequenceItemProjection{inputIndex: inputIndex, outputIndex: outputIndex})
|
|
if _, replaced := operation.replacedOutputs[outputIndex]; replaced {
|
|
// Upsert replacements retain their lower-list position.
|
|
contribution.replacements = append(contribution.replacements, sequenceItemReplacement{
|
|
lowerIndex: outputIndex, higherIndex: inputIndex, outputIndex: outputIndex,
|
|
})
|
|
}
|
|
}
|
|
application.sequences[sequenceIndex] = contribution
|
|
}
|
|
application.sequencesByPath = indexSequenceHistoryContributions(application.sequences)
|
|
}
|
|
return projected
|
|
}
|
|
|
|
func projectSequenceOperationPath(path Path, projections map[string]sequenceHistoryContributionIndex) (Path, bool) {
|
|
projected := path.clone()
|
|
for index, segment := range path.segments {
|
|
if segment.kind != pathSegmentIndex {
|
|
continue
|
|
}
|
|
prefix := Path{segments: path.segments[:index]}
|
|
operation, found := projections[prefix.String()]
|
|
if !found || operation.mode != sequenceHistoryMapped {
|
|
continue
|
|
}
|
|
outputIndex, found := operation.projection.outputForInput(segment.index)
|
|
if !found {
|
|
return Path{}, false
|
|
}
|
|
projected.segments[index].index = outputIndex
|
|
}
|
|
return projected, true
|
|
}
|
|
|
|
// Project only incoming sources. Lower/displaced sources retain the coordinates
|
|
// of their own historical contribution, rather than becoming incoming survivors.
|
|
func projectTierSourceDestinations(sources []SourceInfo, versions []*sourceVersionEvidence, operations []sequenceHistoryContribution) {
|
|
if len(operations) == 0 {
|
|
return
|
|
}
|
|
projections := indexSequenceHistoryContributions(operations)
|
|
for index := range sources {
|
|
if path, found := projectSequenceOperationPath(sources[index].Destination, projections); found {
|
|
sources[index].Destination = path
|
|
}
|
|
}
|
|
for _, evidence := range versions {
|
|
if evidence == nil {
|
|
continue
|
|
}
|
|
paths := evidence.sensitivityPaths()
|
|
projected := make([]Path, len(paths))
|
|
for index, path := range paths {
|
|
projected[index] = path.clone()
|
|
if destination, found := projectSequenceOperationPath(path, projections); found {
|
|
projected[index] = destination
|
|
}
|
|
}
|
|
evidence.projectedPaths = projected
|
|
if path, found := projectSequenceOperationPath(evidence.destination, projections); found {
|
|
evidence.destination = path
|
|
}
|
|
}
|
|
}
|