โ– humdrum codex / dots v1.0.0
1.7 KB raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package day

import (
	"fmt"
	"strings"
)

// Change describes one slot transition for the confirmation table.
type Change struct {
	Index  int
	FromID *string // nil = was empty
	ToID   *string // nil = cleared
}

// ResolveLog computes the write set for a log command. activityID nil means
// plan-fill: every target slot takes its plan block's activity, and any slot
// without one aborts the whole command (all-or-nothing).
func ResolveLog(targets []int, activityID *string, blocks, planBlocks map[int]string, blockSize int) (map[int]*string, []Change, error) {
	assignments := make(map[int]*string, len(targets))
	var overwrites []Change

	if activityID == nil {
		var missing []string
		for _, i := range targets {
			if _, ok := planBlocks[i]; !ok {
				missing = append(missing, SlotLabel(i, blockSize))
			}
		}
		if len(missing) > 0 {
			return nil, nil, fmt.Errorf("no planned activity at %s โ€” nothing painted", strings.Join(missing, ", "))
		}
	}

	for _, i := range targets {
		to := activityID
		if to == nil {
			v := planBlocks[i]
			to = &v
		}
		assignments[i] = to
		if from, ok := blocks[i]; ok && from != *to {
			f := from
			overwrites = append(overwrites, Change{Index: i, FromID: &f, ToID: to})
		}
	}
	return assignments, overwrites, nil
}

// ResolveClear computes the write set for a clear command. Only slots that
// are actually logged are touched; clearing an empty slot is a no-op.
func ResolveClear(targets []int, blocks map[int]string) (map[int]*string, []Change) {
	assignments := make(map[int]*string)
	var cleared []Change
	for _, i := range targets {
		if from, ok := blocks[i]; ok {
			f := from
			assignments[i] = nil
			cleared = append(cleared, Change{Index: i, FromID: &f, ToID: nil})
		}
	}
	return assignments, cleared
}