1package cache
 2
 3import (
 4	"sync"
 5
 6	"github.com/git-bug/git-bug/entity/dag"
 7	"github.com/git-bug/git-bug/repository"
 8)
 9
10var _ dag.Interface[dag.Snapshot, dag.OperationWithApply[dag.Snapshot]] = &withSnapshot[dag.Snapshot, dag.OperationWithApply[dag.Snapshot]]{}
11
12// withSnapshot encapsulate an entity and maintain a snapshot efficiently.
13type withSnapshot[SnapT dag.Snapshot, OpT dag.OperationWithApply[SnapT]] struct {
14	dag.Interface[SnapT, OpT]
15	mu   sync.Mutex
16	snap *SnapT
17}
18
19func (ws *withSnapshot[SnapT, OpT]) Compile() SnapT {
20	ws.mu.Lock()
21	defer ws.mu.Unlock()
22	if ws.snap == nil {
23		snap := ws.Interface.Compile()
24		ws.snap = &snap
25	}
26	return *ws.snap
27}
28
29// Append intercept Bug.Append() to update the snapshot efficiently
30func (ws *withSnapshot[SnapT, OpT]) Append(op OpT) {
31	ws.mu.Lock()
32	defer ws.mu.Unlock()
33
34	ws.Interface.Append(op)
35
36	if ws.snap == nil {
37		return
38	}
39
40	op.Apply(*ws.snap)
41	(*ws.snap).AppendOperation(op)
42}
43
44// Commit intercept Bug.Commit() to update the snapshot efficiently
45func (ws *withSnapshot[SnapT, OpT]) Commit(repo repository.ClockedRepo) error {
46	ws.mu.Lock()
47	defer ws.mu.Unlock()
48
49	err := ws.Interface.Commit(repo)
50	if err != nil {
51		ws.snap = nil
52		return err
53	}
54
55	return nil
56}