package state import ( "github.com/filecoin-project/specs-actors/actors/util/adt" typegen "github.com/whyrusleeping/cbor-gen" ) // AdtArrayDiff generalizes adt.Array diffing by accepting a Deferred type that can unmarshalled to its corresponding struct // in an interface implantation. // Add should be called when a new k,v is added to the array // Modify should be called when a value is modified in the array // Remove should be called when a value is removed from the array type AdtArrayDiff interface { Add(key uint64, val *typegen.Deferred) error Modify(key uint64, from, to *typegen.Deferred) error Remove(key uint64, val *typegen.Deferred) error } // TODO Performance can be improved by diffing the underlying IPLD graph, e.g. https://github.com/ipfs/go-merkledag/blob/749fd8717d46b4f34c9ce08253070079c89bc56d/dagutils/diff.go#L104 // CBOR Marshaling will likely be the largest performance bottleneck here. // DiffAdtArray accepts two *adt.Array's and an AdtArrayDiff implementation. It does the following: // - All values that exist in preArr and not in curArr are passed to AdtArrayDiff.Remove() // - All values that exist in curArr nnd not in prevArr are passed to adtArrayDiff.Add() // - All values that exist in preArr and in curArr are passed to AdtArrayDiff.Modify() // - It is the responsibility of AdtArrayDiff.Modify() to determine if the values it was passed have been modified. func DiffAdtArray(preArr, curArr *adt.Array, out AdtArrayDiff) error { prevVal := new(typegen.Deferred) if err := preArr.ForEach(prevVal, func(i int64) error { curVal := new(typegen.Deferred) found, err := curArr.Get(uint64(i), curVal) if err != nil { return err } if !found { if err := out.Remove(uint64(i), prevVal); err != nil { return err } return nil } if err := out.Modify(uint64(i), prevVal, curVal); err != nil { return err } return curArr.Delete(uint64(i)) }); err != nil { return err } curVal := new(typegen.Deferred) return curArr.ForEach(curVal, func(i int64) error { return out.Add(uint64(i), curVal) }) }