diff --git a/pkg/primitives/address_test.go b/pkg/primitives/address_test.go index 052aa40..b269be6 100644 --- a/pkg/primitives/address_test.go +++ b/pkg/primitives/address_test.go @@ -102,4 +102,32 @@ func TestAddressHelpers(t *testing.T) { t.Fatalf("%s: IsValid() = %v, want %v", tc.name, got, tc.isValid) } } + + left := Address{Version: 0, Hash: []byte{1, 2, 3}} + right := left.Clone() + + if !left.Equals(right) { + t.Fatal("Clone() should produce an equal address") + } + + if got := left.Compare(right); got != 0 { + t.Fatalf("Compare() = %d, want 0", got) + } + + if got := (Address{Version: 0, Hash: []byte{1, 2, 3}}).Compare(Address{Version: 1, Hash: []byte{1, 2, 3}}); got >= 0 { + t.Fatalf("Compare() = %d, want negative", got) + } + + if got := (Address{Version: 1, Hash: []byte{1, 2, 3}}).Compare(Address{Version: 0, Hash: []byte{1, 2, 3}}); got <= 0 { + t.Fatalf("Compare() = %d, want positive", got) + } + + var injected Address + if got := injected.Inject(left); got != &injected { + t.Fatal("Inject() should return the receiver") + } + + if !injected.Equals(left) { + t.Fatal("Inject() should copy the source address") + } } diff --git a/pkg/primitives/types.go b/pkg/primitives/types.go index dfbd55d..80c4ec7 100644 --- a/pkg/primitives/types.go +++ b/pkg/primitives/types.go @@ -37,6 +37,72 @@ type Address struct { Hash []byte } +// Inject copies another address into this one. +func (a *Address) Inject(other Address) *Address { + a.Version = other.Version + a.Hash = other.Hash + return a +} + +// Clone returns a shallow copy of the address. +func (a Address) Clone() Address { + var clone Address + return *clone.Inject(a) +} + +// Equals reports whether two addresses have the same version and hash. +func (a Address) Equals(other Address) bool { + if a.Version != other.Version { + return false + } + + if len(a.Hash) != len(other.Hash) { + return false + } + + for i := range a.Hash { + if a.Hash[i] != other.Hash[i] { + return false + } + } + + return true +} + +// Compare orders two addresses by version and then by hash bytes. +func (a Address) Compare(other Address) int { + if a.Version < other.Version { + return -1 + } + + if a.Version > other.Version { + return 1 + } + + min := len(a.Hash) + if len(other.Hash) < min { + min = len(other.Hash) + } + + for i := 0; i < min; i++ { + if a.Hash[i] < other.Hash[i] { + return -1 + } + if a.Hash[i] > other.Hash[i] { + return 1 + } + } + + switch { + case len(a.Hash) < len(other.Hash): + return -1 + case len(a.Hash) > len(other.Hash): + return 1 + default: + return 0 + } +} + // IsNull reports whether the address hash is entirely zero bytes. func (a Address) IsNull() bool { for _, b := range a.Hash {