From 4d1f3557e51fc0723cb338e2f621594d63b891a2 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 24 Feb 2025 12:04:23 -0800 Subject: [PATCH] refactor: Backwards compatible Encapsulate/Decapsulate/Join/NewComponent (#272) * Backwards compatible Encapsulate/Decapsulate/Join * remove EncapsulateC * feat: Add Multiaddr.AppendComponent * remove .Empty (#274) prefer the simpler `len` check for Multiaddr and `== nil` for `*Component`. * export AsMultiaddrer interface * rename AsMultiaddr to Multiaddr Export Multiaddrer interface --- codec.go | 33 +++++++++++------- component.go | 86 +++++++++++++++++++++++------------------------ multiaddr.go | 49 ++++++++++++++------------- multiaddr_test.go | 75 ++++++++++++++++++++++++++++++++--------- net/convert.go | 6 ++-- net/ip.go | 10 +++--- net/resolve.go | 2 +- util.go | 40 +++++++++------------- util_test.go | 42 +++++++++++------------ v015-MIGRATION.md | 6 ++-- 10 files changed, 197 insertions(+), 152 deletions(-) diff --git a/codec.go b/codec.go index bdbeba6..1374aff 100644 --- a/codec.go +++ b/codec.go @@ -67,31 +67,36 @@ func stringToBytes(s string) ([]byte, error) { return b.Bytes(), nil } -func readComponent(b []byte) (int, Component, error) { +func readComponent(b []byte) (int, *Component, error) { var offset int code, n, err := ReadVarintCode(b) if err != nil { - return 0, Component{}, err + return 0, nil, err } offset += n p := ProtocolWithCode(code) if p.Code == 0 { - return 0, Component{}, fmt.Errorf("no protocol with code %d", code) + return 0, nil, fmt.Errorf("no protocol with code %d", code) } pPtr := protocolPtrByCode[code] if pPtr == nil { - return 0, Component{}, fmt.Errorf("no protocol with code %d", code) + return 0, nil, fmt.Errorf("no protocol with code %d", code) } if p.Size == 0 { - c, err := validateComponent(Component{ + c := &Component{ bytes: string(b[:offset]), valueStartIdx: offset, protocol: pPtr, - }) + } + + err := validateComponent(c) + if err != nil { + return 0, nil, err + } - return offset, c, err + return offset, c, nil } var size int @@ -100,7 +105,7 @@ func readComponent(b []byte) (int, Component, error) { var n int size, n, err = ReadVarintCode(b[offset:]) if err != nil { - return 0, Component{}, err + return 0, nil, err } offset += n } else { @@ -109,14 +114,18 @@ func readComponent(b []byte) (int, Component, error) { } if len(b[offset:]) < size || size <= 0 { - return 0, Component{}, fmt.Errorf("invalid value for size %d", len(b[offset:])) + return 0, nil, fmt.Errorf("invalid value for size %d", len(b[offset:])) } - c, err := validateComponent(Component{ + c := &Component{ bytes: string(b[:offset+size]), protocol: pPtr, valueStartIdx: offset, - }) + } + err = validateComponent(c) + if err != nil { + return 0, nil, err + } return offset + size, c, err } @@ -142,7 +151,7 @@ func readMultiaddr(b []byte) (int, Multiaddr, error) { return bytesRead, nil, fmt.Errorf("unexpected component after path component") } sawPathComponent = c.protocol.Path - res = append(res, c) + res = append(res, *c) } return bytesRead, res, nil } diff --git a/component.go b/component.go index d25f06a..6e8a640 100644 --- a/component.go +++ b/component.go @@ -19,26 +19,19 @@ type Component struct { valueStartIdx int // Index of the first byte of the Component's value in the bytes array } -func (c *Component) AsMultiaddr() Multiaddr { - if c.Empty() { +func (c *Component) Multiaddr() Multiaddr { + if c == nil { return nil } return []Component{*c} } -func (c *Component) Encapsulate(o Multiaddr) Multiaddr { - return c.AsMultiaddr().Encapsulate(o) -} - -func (c *Component) Decapsulate(o Multiaddr) Multiaddr { - return c.AsMultiaddr().Decapsulate(o) +func (c *Component) Encapsulate(o Multiaddrer) Multiaddr { + return c.Multiaddr().Encapsulate(o) } -func (c *Component) Empty() bool { - if c == nil { - return true - } - return len(c.bytes) == 0 +func (c *Component) Decapsulate(o Multiaddrer) Multiaddr { + return c.Multiaddr().Decapsulate(o) } func (c *Component) Bytes() []byte { @@ -63,7 +56,7 @@ func (c *Component) UnmarshalBinary(data []byte) error { if err != nil { return err } - *c = comp + *c = *comp return nil } @@ -87,7 +80,7 @@ func (c *Component) UnmarshalText(data []byte) error { if err != nil { return err } - *c = comp + *c = *comp return nil } @@ -180,9 +173,6 @@ func (c *Component) Value() string { if c == nil { return "" } - if c.Empty() { - return "" - } // This Component MUST have been checked by validateComponent when created value, _ := c.valueAndErr() return value @@ -236,24 +226,24 @@ func (c *Component) writeTo(b *strings.Builder) { } // NewComponent constructs a new multiaddr component -func NewComponent(protocol, value string) (Component, error) { +func NewComponent(protocol, value string) (*Component, error) { p := ProtocolWithName(protocol) if p.Code == 0 { - return Component{}, fmt.Errorf("unsupported protocol: %s", protocol) + return nil, fmt.Errorf("unsupported protocol: %s", protocol) } if p.Transcoder != nil { bts, err := p.Transcoder.StringToBytes(value) if err != nil { - return Component{}, err + return nil, err } return newComponent(p, bts) } else if value != "" { - return Component{}, fmt.Errorf("protocol %s doesn't take a value", p.Name) + return nil, fmt.Errorf("protocol %s doesn't take a value", p.Name) } return newComponent(p, nil) } -func newComponent(protocol Protocol, bvalue []byte) (Component, error) { +func newComponent(protocol Protocol, bvalue []byte) (*Component, error) { protocolPtr := protocolPtrByCode[protocol.Code] if protocolPtr == nil { protocolPtr = &protocol @@ -274,71 +264,79 @@ func newComponent(protocol Protocol, bvalue []byte) (Component, error) { // Shouldn't happen if len(maddr) != offset+len(bvalue) { - return Component{}, fmt.Errorf("component size mismatch: %d != %d", len(maddr), offset+len(bvalue)) + return nil, fmt.Errorf("component size mismatch: %d != %d", len(maddr), offset+len(bvalue)) } - return validateComponent( - Component{ - bytes: string(maddr), - protocol: protocolPtr, - valueStartIdx: offset, - }) + c := &Component{ + bytes: string(maddr), + protocol: protocolPtr, + valueStartIdx: offset, + } + + err := validateComponent(c) + if err != nil { + return nil, err + } + return c, nil } // validateComponent MUST be called after creating a non-zero Component. // It ensures that we will be able to call all methods on Component without // error. -func validateComponent(c Component) (Component, error) { +func validateComponent(c *Component) error { + if c == nil { + return errNilPtr + } if c.protocol == nil { - return Component{}, fmt.Errorf("component is missing its protocol") + return fmt.Errorf("component is missing its protocol") } if c.valueStartIdx > len(c.bytes) { - return Component{}, fmt.Errorf("component valueStartIdx is greater than the length of the component's bytes") + return fmt.Errorf("component valueStartIdx is greater than the length of the component's bytes") } if len(c.protocol.VCode) == 0 { - return Component{}, fmt.Errorf("Component is missing its protocol's VCode field") + return fmt.Errorf("Component is missing its protocol's VCode field") } if len(c.bytes) < len(c.protocol.VCode) { - return Component{}, fmt.Errorf("component size mismatch: %d != %d", len(c.bytes), len(c.protocol.VCode)) + return fmt.Errorf("component size mismatch: %d != %d", len(c.bytes), len(c.protocol.VCode)) } if !bytes.Equal([]byte(c.bytes[:len(c.protocol.VCode)]), c.protocol.VCode) { - return Component{}, fmt.Errorf("component's VCode field is invalid: %v != %v", []byte(c.bytes[:len(c.protocol.VCode)]), c.protocol.VCode) + return fmt.Errorf("component's VCode field is invalid: %v != %v", []byte(c.bytes[:len(c.protocol.VCode)]), c.protocol.VCode) } if c.protocol.Size < 0 { size, n, err := ReadVarintCode([]byte(c.bytes[len(c.protocol.VCode):])) if err != nil { - return Component{}, err + return err } if size != len(c.bytes[c.valueStartIdx:]) { - return Component{}, fmt.Errorf("component value size mismatch: %d != %d", size, len(c.bytes[c.valueStartIdx:])) + return fmt.Errorf("component value size mismatch: %d != %d", size, len(c.bytes[c.valueStartIdx:])) } if len(c.protocol.VCode)+n+size != len(c.bytes) { - return Component{}, fmt.Errorf("component size mismatch: %d != %d", len(c.protocol.VCode)+n+size, len(c.bytes)) + return fmt.Errorf("component size mismatch: %d != %d", len(c.protocol.VCode)+n+size, len(c.bytes)) } } else { // Fixed size value size := c.protocol.Size / 8 if size != len(c.bytes[c.valueStartIdx:]) { - return Component{}, fmt.Errorf("component value size mismatch: %d != %d", size, len(c.bytes[c.valueStartIdx:])) + return fmt.Errorf("component value size mismatch: %d != %d", size, len(c.bytes[c.valueStartIdx:])) } if len(c.protocol.VCode)+size != len(c.bytes) { - return Component{}, fmt.Errorf("component size mismatch: %d != %d", len(c.protocol.VCode)+size, len(c.bytes)) + return fmt.Errorf("component size mismatch: %d != %d", len(c.protocol.VCode)+size, len(c.bytes)) } } _, err := c.valueAndErr() if err != nil { - return Component{}, err + return err } if c.protocol.Transcoder != nil { err = c.protocol.Transcoder.ValidateBytes([]byte(c.bytes[c.valueStartIdx:])) if err != nil { - return Component{}, err + return err } } - return c, nil + return nil } diff --git a/multiaddr.go b/multiaddr.go index 3a8a03b..2565f51 100644 --- a/multiaddr.go +++ b/multiaddr.go @@ -25,18 +25,6 @@ func (m Multiaddr) copy() Multiaddr { return out } -func (m Multiaddr) Empty() bool { - if len(m) == 0 { - return true - } - for _, c := range m { - if !c.Empty() { - return false - } - } - return true -} - // NewMultiaddr parses and validates an input string, returning a *Multiaddr func NewMultiaddr(s string) (a Multiaddr, err error) { defer func() { @@ -181,23 +169,38 @@ func (m Multiaddr) Protocols() []Protocol { return out } -// Encapsulate wraps a given Multiaddr, returning the resulting joined Multiaddr -func (m Multiaddr) Encapsulate(o Multiaddr) Multiaddr { - return Join(m, o) +type Multiaddrer interface { + // Multiaddr returns the Multiaddr representation + Multiaddr() Multiaddr } -func (m Multiaddr) EncapsulateC(c *Component) Multiaddr { - if c.Empty() { - return m +func (m Multiaddr) Multiaddr() Multiaddr { + return m +} + +// AppendComponent is the same as using `append(m, *c)`, but with a safety check +// for a nil Component. +func (m Multiaddr) AppendComponent(cs ...*Component) Multiaddr { + for _, c := range cs { + if c == nil { + continue + } + m = append(m, *c) } - out := make([]Component, 0, len(m)+1) - out = append(out, m...) - out = append(out, *c) - return out + return m +} + +// Encapsulate wraps a given Multiaddr, returning the resulting joined Multiaddr +func (m Multiaddr) Encapsulate(other Multiaddrer) Multiaddr { + return Join(m, other) } // Decapsulate unwraps Multiaddr up until the given Multiaddr is found. -func (m Multiaddr) Decapsulate(rightParts Multiaddr) Multiaddr { +func (m Multiaddr) Decapsulate(rightPartsAny Multiaddrer) Multiaddr { + if rightPartsAny == nil { + return m + } + rightParts := rightPartsAny.Multiaddr() leftParts := m lastIndex := -1 diff --git a/multiaddr_test.go b/multiaddr_test.go index 28b068f..54fdc4c 100644 --- a/multiaddr_test.go +++ b/multiaddr_test.go @@ -32,7 +32,6 @@ func TestReturnsNilOnEmpty(t *testing.T) { require.Zero(t, len(a.Protocols())) require.Nil(t, a) require.Nil(t, c) - require.True(t, c.Empty()) // Test that empty multiaddr from various operations returns nil a = StringCast("/ip4/1.2.3.4/tcp/1234") @@ -45,7 +44,6 @@ func TestReturnsNilOnEmpty(t *testing.T) { c, a = SplitFirst(nil) require.Nil(t, a) require.Nil(t, c) - require.True(t, c.Empty()) a = StringCast("/ip4/1.2.3.4/tcp/1234") a = a.Decapsulate(a) @@ -72,13 +70,24 @@ func TestReturnsNilOnEmpty(t *testing.T) { _, err := NewMultiaddr("") require.Error(t, err) - a = JoinComponents() + var nilMultiaddr Multiaddr + a = nilMultiaddr.AppendComponent() require.Nil(t, a) a = Join() require.Nil(t, a) } +func TestJoinWithComponents(t *testing.T) { + var m Multiaddr + c, err := NewComponent("ip4", "127.0.0.1") + require.NoError(t, err) + + expected := "/ip4/127.0.0.1" + require.Equal(t, expected, Join(m, c).String()) + +} + func TestConstructFails(t *testing.T) { cases := []string{ "/ip4", @@ -313,7 +322,7 @@ func TestNilInterface(t *testing.T) { // Test components c, _ := SplitFirst(m1) - c.AsMultiaddr().Equal(m2) + c.Multiaddr().Equal(m2) c.Encapsulate(m2) c.Decapsulate(m2) @@ -415,7 +424,7 @@ func TestBytesSplitAndJoin(t *testing.T) { } } - joined := JoinComponents(split...) + joined := append(Multiaddr{}, split...) if !m.Equal(joined) { t.Errorf("joined components failed: %s != %s", m, joined) } @@ -520,6 +529,19 @@ func TestEncapsulate(t *testing.T) { if d != nil { t.Error("decapsulate /ip4 failed: ", d) } + + t.Run("Encapsulating with components", func(t *testing.T) { + left, last := SplitLast(m) + joined := left.Encapsulate(last) + require.True(t, joined.Equal(m)) + + first, rest := SplitFirst(m) + joined = first.Encapsulate(rest) + require.True(t, joined.Equal(m)) + // Component type + joined = (*first).Encapsulate(rest) + require.True(t, joined.Equal(m)) + }) } func TestDecapsulateComment(t *testing.T) { @@ -580,6 +602,16 @@ func TestDecapsulate(t *testing.T) { require.Equal(t, expected, actual) }) } + + for _, tc := range testcases { + t.Run("Decapsulating with components"+tc.left, func(t *testing.T) { + left, last := SplitLast(StringCast(tc.left)) + butLast := left.Decapsulate(last) + require.Equal(t, butLast.String(), left.String()) + // Round trip + require.Equal(t, tc.left, butLast.Encapsulate(last).String()) + }) + } } func assertValueForProto(t *testing.T, a Multiaddr, p int, exp string) { @@ -594,6 +626,17 @@ func assertValueForProto(t *testing.T, a Multiaddr, p int, exp string) { } } +func TestAppendComponent(t *testing.T) { + var m Multiaddr + res := m.AppendComponent(nil) + require.Equal(t, m, res) + + c, err := NewComponent("ip4", "127.0.0.1") + require.NoError(t, err) + res = m.AppendComponent(c) + require.Equal(t, "/ip4/127.0.0.1", res.String()) +} + func TestGetValue(t *testing.T) { a := newMultiaddr(t, "/ip4/127.0.0.1/utp/tcp/5555/udp/1234/tls/utp/ipfs/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP") assertValueForProto(t, a, P_IP4, "127.0.0.1") @@ -870,7 +913,7 @@ func TestComponentBinaryMarshaler(t *testing.T) { t.Fatal(err) } - comp2 := Component{} + var comp2 Component if err = comp2.UnmarshalBinary(b); err != nil { t.Fatal(err) } @@ -889,7 +932,7 @@ func TestComponentTextMarshaler(t *testing.T) { t.Fatal(err) } - comp2 := Component{} + var comp2 Component if err = comp2.UnmarshalText(b); err != nil { t.Fatal(err) } @@ -908,7 +951,7 @@ func TestComponentJSONMarshaler(t *testing.T) { t.Fatal(err) } - comp2 := Component{} + var comp2 Component if err = comp2.UnmarshalJSON(b); err != nil { t.Fatal(err) } @@ -946,10 +989,10 @@ func TestUseNil(t *testing.T) { func TestUseNilComponent(t *testing.T) { var foo *Component - foo.AsMultiaddr() + foo.Multiaddr() foo.Encapsulate(nil) foo.Decapsulate(nil) - foo.Empty() + require.True(t, foo == nil) foo.Bytes() foo.MarshalBinary() foo.MarshalJSON() @@ -967,7 +1010,7 @@ func TestUseNilComponent(t *testing.T) { _ = foo.String() var m Multiaddr = nil - m.EncapsulateC(foo) + m.Encapsulate(foo) } func TestFilterAddrs(t *testing.T) { @@ -1124,12 +1167,12 @@ func FuzzSplitRoundtrip(f *testing.F) { // Test SplitFirst first, rest := SplitFirst(addr) - joined := Join(first.AsMultiaddr(), rest) + joined := Join(first, rest) require.True(t, addr.Equal(joined), "SplitFirst and Join should round-trip") // Test SplitLast rest, last := SplitLast(addr) - joined = Join(rest, last.AsMultiaddr()) + joined = Join(rest, last) require.True(t, addr.Equal(joined), "SplitLast and Join should round-trip") p := addr.Protocols() @@ -1155,12 +1198,12 @@ func FuzzSplitRoundtrip(f *testing.F) { return c.Protocol().Code == proto.Code } beforeC, after := SplitFirst(addr) - joined = Join(beforeC.AsMultiaddr(), after) + joined = Join(beforeC, after) require.True(t, addr.Equal(joined)) tryPubMethods(after) before, afterC := SplitLast(addr) - joined = Join(before, afterC.AsMultiaddr()) + joined = Join(before, afterC) require.True(t, addr.Equal(joined)) tryPubMethods(before) @@ -1180,7 +1223,7 @@ func BenchmarkComponentValidation(b *testing.B) { } b.ReportAllocs() for i := 0; i < b.N; i++ { - _, err := validateComponent(comp) + err := validateComponent(comp) if err != nil { b.Fatal(err) } diff --git a/net/convert.go b/net/convert.go index be320d3..8056451 100644 --- a/net/convert.go +++ b/net/convert.go @@ -108,13 +108,13 @@ func FromIPAndZone(ip net.IP, zone string) (ma.Multiaddr, error) { if err != nil { return nil, err } - return c.AsMultiaddr(), nil + return c.Multiaddr(), nil case ip.To16() != nil: ip6C, err := ma.NewComponent("ip6", ip.String()) if err != nil { return nil, err } - ip6 := ip6C.AsMultiaddr() + ip6 := ip6C.Multiaddr() if zone == "" { return ip6, nil } else { @@ -362,5 +362,5 @@ func parseUnixNetAddr(a net.Addr) (ma.Multiaddr, error) { if err != nil { return nil, err } - return c.AsMultiaddr(), nil + return c.Multiaddr(), nil } diff --git a/net/ip.go b/net/ip.go index e8acecb..def9321 100644 --- a/net/ip.go +++ b/net/ip.go @@ -64,7 +64,7 @@ func IsIPLoopback(m ma.Multiaddr) bool { return false } c, _ := ma.SplitFirst(m) - if c.Empty() { + if c == nil { return false } switch c.Protocol().Code { @@ -83,7 +83,7 @@ func IsIP6LinkLocal(m ma.Multiaddr) bool { return false } c, _ := ma.SplitFirst(m) - if c.Empty() || c.Protocol().Code != ma.P_IP6 { + if c == nil || c.Protocol().Code != ma.P_IP6 { return false } ip := net.IP(c.RawValue()) @@ -106,11 +106,11 @@ func IsIPUnspecified(m ma.Multiaddr) bool { // else return m func zoneless(m ma.Multiaddr) ma.Multiaddr { head, tail := ma.SplitFirst(m) - if head.Empty() { + if head == nil { return nil } if head.Protocol().Code == ma.P_IP6ZONE { - if tail.Empty() { + if tail == nil { return nil } tailhead, _ := ma.SplitFirst(tail) @@ -127,6 +127,6 @@ func zoneless(m ma.Multiaddr) ma.Multiaddr { // used for NAT64 Translation. See RFC 6052 func IsNAT64IPv4ConvertedIPv6Addr(addr ma.Multiaddr) bool { c, _ := ma.SplitFirst(addr) - return !c.Empty() && c.Protocol().Code == ma.P_IP6 && + return c != nil && c.Protocol().Code == ma.P_IP6 && inAddrRange(c.RawValue(), nat64) } diff --git a/net/resolve.go b/net/resolve.go index 0b43d08..cd98fd8 100644 --- a/net/resolve.go +++ b/net/resolve.go @@ -14,7 +14,7 @@ func ResolveUnspecifiedAddress(resolve ma.Multiaddr, ifaceAddrs []ma.Multiaddr) first, rest := ma.SplitFirst(resolve) // if first component (ip) is not unspecified, use it as is. - if !IsIPUnspecified(first.AsMultiaddr()) { + if !IsIPUnspecified(first.Multiaddr()) { return []ma.Multiaddr{resolve}, nil } diff --git a/util.go b/util.go index 038c143..d063e39 100644 --- a/util.go +++ b/util.go @@ -9,23 +9,17 @@ func Split(m Multiaddr) []Component { return m } -func JoinComponents(cs ...Component) Multiaddr { - if len(cs) == 0 { - return nil - } - out := make([]Component, 0, len(cs)) - for _, c := range cs { - if !c.Empty() { - out = append(out, c) - } - } - return out -} - // Join returns a combination of addresses. // Note: This copies all the components from the input Multiaddrs. Depending on // your use case, you may prefer to use `append(leftMA, rightMA...)` instead. -func Join(ms ...Multiaddr) Multiaddr { +func Join(msInterfaces ...Multiaddrer) Multiaddr { + ms := make([]Multiaddr, len(msInterfaces)) + for i, m := range msInterfaces { + if m == nil { + continue + } + ms[i] = m.Multiaddr() + } size := 0 for _, m := range ms { size += len(m) @@ -36,11 +30,7 @@ func Join(ms ...Multiaddr) Multiaddr { out := make([]Component, 0, size) for _, m := range ms { - for _, c := range m { - if !c.Empty() { - out = append(out, c) - } - } + out = append(out, m...) } return out } @@ -65,7 +55,7 @@ func StringCast(s string) Multiaddr { // SplitFirst returns the first component and the rest of the multiaddr. func SplitFirst(m Multiaddr) (*Component, Multiaddr) { - if m.Empty() { + if len(m) == 0 { return nil, nil } if len(m) == 1 { @@ -78,7 +68,7 @@ func SplitFirst(m Multiaddr) (*Component, Multiaddr) { // SplitLast returns the rest of the multiaddr and the last component. func SplitLast(m Multiaddr) (Multiaddr, *Component) { - if m.Empty() { + if len(m) == 0 { return nil, nil } if len(m) == 1 { @@ -94,7 +84,7 @@ func SplitLast(m Multiaddr) (Multiaddr, *Component) { // component on which the callback first returns will be included in the // *second* multiaddr. func SplitFunc(m Multiaddr, cb func(Component) bool) (Multiaddr, Multiaddr) { - if m.Empty() { + if len(m) == 0 { return nil, nil } @@ -106,10 +96,10 @@ func SplitFunc(m Multiaddr, cb func(Component) bool) (Multiaddr, Multiaddr) { } } pre, post := m[:idx], m[idx:] - if pre.Empty() { + if len(pre) == 0 { pre = nil } - if post.Empty() { + if len(post) == 0 { post = nil } // defensive copy. Users can avoid by doing the split themselves. @@ -121,7 +111,7 @@ func SplitFunc(m Multiaddr, cb func(Component) bool) (Multiaddr, Multiaddr) { // This function iterates over components. // Return true to continue iteration, false to stop. // -// Prefer to use a standard for range loop instead +// Prefer a standard for range loop instead // e.g. `for _, c := range m { ... }` func ForEach(m Multiaddr, cb func(c Component) bool) { for _, c := range m { diff --git a/util_test.go b/util_test.go index 1409122..365ba41 100644 --- a/util_test.go +++ b/util_test.go @@ -21,8 +21,8 @@ func TestSplitFirstLast(t *testing.T) { head, tail := SplitFirst(addr) rest, last := SplitLast(addr) if len(x) == 0 { - if !head.Empty() { - t.Error("expected head to be empty") + if head != nil { + t.Error("expected head to be nil") } if tail != nil { t.Error("expected tail to be nil") @@ -30,15 +30,15 @@ func TestSplitFirstLast(t *testing.T) { if rest != nil { t.Error("expected rest to be nil") } - if !last.Empty() { - t.Error("expected last to be empty") + if last != nil { + t.Error("expected last to be nil") } continue } - if !head.AsMultiaddr().Equal(StringCast(x[0])) { + if !head.Multiaddr().Equal(StringCast(x[0])) { t.Errorf("expected %s to be %s", head, x[0]) } - if !last.AsMultiaddr().Equal(StringCast(x[len(x)-1])) { + if !last.Multiaddr().Equal(StringCast(x[len(x)-1])) { t.Errorf("expected %s to be %s", head, x[len(x)-1]) } if len(x) == 1 { @@ -65,38 +65,38 @@ func TestSplitFirstLast(t *testing.T) { t.Fatal(err) } - ci, m := SplitFirst(c.AsMultiaddr()) - if !ci.Equal(&c) || m != nil { + ci, m := SplitFirst(c.Multiaddr()) + if !ci.Equal(c) || m != nil { t.Error("split first on component failed") } - m, ci = SplitLast(c.AsMultiaddr()) - if !ci.Equal(&c) || m != nil { + m, ci = SplitLast(c.Multiaddr()) + if !ci.Equal(c) || m != nil { t.Error("split last on component failed") } - cis := Split(c.AsMultiaddr()) - if len(cis) != 1 || !cis[0].Equal(&c) { + cis := Split(c.Multiaddr()) + if len(cis) != 1 || !cis[0].Equal(c) { t.Error("split on component failed") } - m1, m2 := SplitFunc(c.AsMultiaddr(), func(c Component) bool { + m1, m2 := SplitFunc(c.Multiaddr(), func(c Component) bool { return true }) - if m1 != nil || !m2.Equal(c.AsMultiaddr()) { + if m1 != nil || !m2.Equal(c.Multiaddr()) { t.Error("split func(true) on component failed") } - m1, m2 = SplitFunc(c.AsMultiaddr(), func(c Component) bool { + m1, m2 = SplitFunc(c.Multiaddr(), func(c Component) bool { return false }) - if !m1.Equal(c.AsMultiaddr()) || m2 != nil { + if !m1.Equal(c.Multiaddr()) || m2 != nil { t.Error("split func(false) on component failed") } i := 0 - ForEach(c.AsMultiaddr(), func(ci Component) bool { + ForEach(c.Multiaddr(), func(ci Component) bool { if i != 0 { t.Error("expected exactly one component") } i++ - if !ci.Equal(&c) { + if !ci.Equal(c) { t.Error("foreach on component failed") } return true @@ -119,10 +119,10 @@ func TestSplitFunc(t *testing.T) { for i, cs := range x { target := StringCast(cs) a, b := SplitFunc(addr, func(c Component) bool { - return c.AsMultiaddr().Equal(target) + return c.Multiaddr().Equal(target) }) if i == 0 { - if !a.Empty() { + if a != nil { t.Error("expected nil addr") } } else { @@ -135,7 +135,7 @@ func TestSplitFunc(t *testing.T) { } } a, b := SplitFunc(addr, func(_ Component) bool { return false }) - if !a.Equal(addr) || !b.Empty() { + if !a.Equal(addr) || b != nil { t.Error("should not have split") } } diff --git a/v015-MIGRATION.md b/v015-MIGRATION.md index ab75a39..3af7180 100644 --- a/v015-MIGRATION.md +++ b/v015-MIGRATION.md @@ -2,7 +2,7 @@ - There is no `Multiaddr` interface type. - Multiaddr is now a concrete type. Not an interface. -- Empty Multiaddrs/ should be checked with `.Empty()`, not `== nil`. This is similar to how slices should be checked with `len(s) == 0` rather than `s == nil`. +- Empty Multiaddrs/Component should generally be checked with `.Empty()`, not `== nil`. This is similar to how slices should be checked with `len(s) == 0` rather than `s == nil`. - Components do not implement `Multiaddr` as there is no `Multiaddr` to implement. - `Multiaddr` can no longer be a key in a Map. If you want unique Multiaddrs, use `Multiaddr.String()` as the key, otherwise you can use the pointer value `*Multiaddr`. @@ -12,4 +12,6 @@ ## Migration tips for v0.15 -- If trying to encapsulate a Component to a Multiaddr, use `m.encapsulateC(c)`, instead of the old form of `m.Encapsulate(c)`. `Encapsulate` now only accepts a `Multiaddr`. `EncapsulateC` accepts a `Component`. +- If your use case supports it, prefer `append` to append a Component to a + Multiaddr rather than using `Encapsulate`. It's much faster as it does not do + a defensive copy.