123 lines
3.9 KiB
Go
123 lines
3.9 KiB
Go
package adt
|
|
|
|
import (
|
|
"bytes"
|
|
|
|
"github.com/filecoin-project/go-state-types/abi"
|
|
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 Array, out AdtArrayDiff) error {
|
|
notNew := make(map[int64]struct{}, curArr.Length())
|
|
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
|
|
}
|
|
|
|
// no modification
|
|
if !bytes.Equal(prevVal.Raw, curVal.Raw) {
|
|
if err := out.Modify(uint64(i), prevVal, curVal); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
notNew[i] = struct{}{}
|
|
return nil
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
curVal := new(typegen.Deferred)
|
|
return curArr.ForEach(curVal, func(i int64) error {
|
|
if _, ok := notNew[i]; ok {
|
|
return nil
|
|
}
|
|
return out.Add(uint64(i), curVal)
|
|
})
|
|
}
|
|
|
|
// 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.
|
|
|
|
// AdtMapDiff generalizes adt.Map diffing by accepting a Deferred type that can unmarshalled to its corresponding struct
|
|
// in an interface implantation.
|
|
// AsKey should return the Keyer implementation specific to the map
|
|
// Add should be called when a new k,v is added to the map
|
|
// Modify should be called when a value is modified in the map
|
|
// Remove should be called when a value is removed from the map
|
|
type AdtMapDiff interface {
|
|
AsKey(key string) (abi.Keyer, error)
|
|
Add(key string, val *typegen.Deferred) error
|
|
Modify(key string, from, to *typegen.Deferred) error
|
|
Remove(key string, val *typegen.Deferred) error
|
|
}
|
|
|
|
func DiffAdtMap(preMap, curMap Map, out AdtMapDiff) error {
|
|
notNew := make(map[string]struct{})
|
|
prevVal := new(typegen.Deferred)
|
|
if err := preMap.ForEach(prevVal, func(key string) error {
|
|
curVal := new(typegen.Deferred)
|
|
k, err := out.AsKey(key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
found, err := curMap.Get(k, curVal)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !found {
|
|
if err := out.Remove(key, prevVal); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// no modification
|
|
if !bytes.Equal(prevVal.Raw, curVal.Raw) {
|
|
if err := out.Modify(key, prevVal, curVal); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
notNew[key] = struct{}{}
|
|
return nil
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
curVal := new(typegen.Deferred)
|
|
return curMap.ForEach(curVal, func(key string) error {
|
|
if _, ok := notNew[key]; ok {
|
|
return nil
|
|
}
|
|
return out.Add(key, curVal)
|
|
})
|
|
}
|