Let Multiaddr implement marshalers: binary, text, json
This commit is contained in:
parent
0297994296
commit
0aa80854ab
51
component.go
51
component.go
|
@ -3,6 +3,7 @@ package multiaddr
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
@ -18,6 +19,54 @@ func (c *Component) Bytes() []byte {
|
|||
return c.bytes
|
||||
}
|
||||
|
||||
func (c *Component) MarshalBinary() ([]byte, error) {
|
||||
return c.Bytes(), nil
|
||||
}
|
||||
|
||||
func (c *Component) UnmarshalBinary(data []byte) error {
|
||||
_, comp, err := readComponent(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*c = comp
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Component) MarshalText() ([]byte, error) {
|
||||
return []byte(c.String()), nil
|
||||
}
|
||||
|
||||
func (c *Component) UnmarshalText(data []byte) error {
|
||||
bytes, err := stringToBytes(string(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, comp, err := readComponent(bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*c = comp
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Component) MarshalJSON() ([]byte, error) {
|
||||
txt, err := c.MarshalText()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(string(txt))
|
||||
}
|
||||
|
||||
func (m *Component) UnmarshalJSON(data []byte) error {
|
||||
var v string
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return m.UnmarshalText([]byte(v))
|
||||
}
|
||||
|
||||
func (c *Component) Equal(o Multiaddr) bool {
|
||||
return bytes.Equal(c.bytes, o.Bytes())
|
||||
}
|
||||
|
@ -34,7 +83,7 @@ func (c *Component) Decapsulate(o Multiaddr) Multiaddr {
|
|||
}
|
||||
|
||||
func (c *Component) Encapsulate(o Multiaddr) Multiaddr {
|
||||
m := multiaddr{bytes: c.bytes}
|
||||
m := &multiaddr{bytes: c.bytes}
|
||||
return m.Encapsulate(o)
|
||||
}
|
||||
|
||||
|
|
12
interface.go
12
interface.go
|
@ -1,5 +1,10 @@
|
|||
package multiaddr
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
/*
|
||||
Multiaddr is a cross-protocol, cross-platform format for representing
|
||||
internet addresses. It emphasizes explicitness and self-description.
|
||||
|
@ -14,6 +19,13 @@ Multiaddrs have both a binary and string representation.
|
|||
|
||||
*/
|
||||
type Multiaddr interface {
|
||||
json.Marshaler
|
||||
json.Unmarshaler
|
||||
encoding.TextMarshaler
|
||||
encoding.TextUnmarshaler
|
||||
encoding.BinaryMarshaler
|
||||
encoding.BinaryUnmarshaler
|
||||
|
||||
// Equal returns whether two Multiaddrs are exactly equal
|
||||
Equal(Multiaddr) bool
|
||||
|
||||
|
|
63
multiaddr.go
63
multiaddr.go
|
@ -2,6 +2,7 @@ package multiaddr
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
@ -24,7 +25,7 @@ func NewMultiaddr(s string) (a Multiaddr, err error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return multiaddr{bytes: b}, nil
|
||||
return &multiaddr{bytes: b}, nil
|
||||
}
|
||||
|
||||
// NewMultiaddrBytes initializes a Multiaddr from a byte representation.
|
||||
|
@ -41,23 +42,23 @@ func NewMultiaddrBytes(b []byte) (a Multiaddr, err error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return multiaddr{bytes: b}, nil
|
||||
return &multiaddr{bytes: b}, nil
|
||||
}
|
||||
|
||||
// Equal tests whether two multiaddrs are equal
|
||||
func (m multiaddr) Equal(m2 Multiaddr) bool {
|
||||
func (m *multiaddr) Equal(m2 Multiaddr) bool {
|
||||
return bytes.Equal(m.bytes, m2.Bytes())
|
||||
}
|
||||
|
||||
// Bytes returns the []byte representation of this Multiaddr
|
||||
//
|
||||
// Do not modify the returned buffer, it may be shared.
|
||||
func (m multiaddr) Bytes() []byte {
|
||||
func (m *multiaddr) Bytes() []byte {
|
||||
return m.bytes
|
||||
}
|
||||
|
||||
// String returns the string representation of a Multiaddr
|
||||
func (m multiaddr) String() string {
|
||||
func (m *multiaddr) String() string {
|
||||
s, err := bytesToString(m.bytes)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("multiaddr failed to convert back to string. corrupted? %s", err))
|
||||
|
@ -65,9 +66,49 @@ func (m multiaddr) String() string {
|
|||
return s
|
||||
}
|
||||
|
||||
func (m *multiaddr) MarshalBinary() ([]byte, error) {
|
||||
return m.Bytes(), nil
|
||||
}
|
||||
|
||||
func (m *multiaddr) UnmarshalBinary(data []byte) error {
|
||||
new, err := NewMultiaddrBytes(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*m = *(new.(*multiaddr))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *multiaddr) MarshalText() ([]byte, error) {
|
||||
return []byte(m.String()), nil
|
||||
}
|
||||
|
||||
func (m *multiaddr) UnmarshalText(data []byte) error {
|
||||
new, err := NewMultiaddr(string(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*m = *(new.(*multiaddr))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *multiaddr) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(m.String())
|
||||
}
|
||||
|
||||
func (m *multiaddr) UnmarshalJSON(data []byte) error {
|
||||
var v string
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
new, err := NewMultiaddr(v)
|
||||
*m = *(new.(*multiaddr))
|
||||
return err
|
||||
}
|
||||
|
||||
// Protocols returns the list of protocols this Multiaddr has.
|
||||
// will panic in case we access bytes incorrectly.
|
||||
func (m multiaddr) Protocols() []Protocol {
|
||||
func (m *multiaddr) Protocols() []Protocol {
|
||||
ps := make([]Protocol, 0, 8)
|
||||
b := m.bytes
|
||||
for len(b) > 0 {
|
||||
|
@ -96,18 +137,18 @@ func (m multiaddr) Protocols() []Protocol {
|
|||
}
|
||||
|
||||
// Encapsulate wraps a given Multiaddr, returning the resulting joined Multiaddr
|
||||
func (m multiaddr) Encapsulate(o Multiaddr) Multiaddr {
|
||||
func (m *multiaddr) Encapsulate(o Multiaddr) Multiaddr {
|
||||
mb := m.bytes
|
||||
ob := o.Bytes()
|
||||
|
||||
b := make([]byte, len(mb)+len(ob))
|
||||
copy(b, mb)
|
||||
copy(b[len(mb):], ob)
|
||||
return multiaddr{bytes: b}
|
||||
return &multiaddr{bytes: b}
|
||||
}
|
||||
|
||||
// Decapsulate unwraps Multiaddr up until the given Multiaddr is found.
|
||||
func (m multiaddr) Decapsulate(o Multiaddr) Multiaddr {
|
||||
func (m *multiaddr) Decapsulate(o Multiaddr) Multiaddr {
|
||||
s1 := m.String()
|
||||
s2 := o.String()
|
||||
i := strings.LastIndex(s1, s2)
|
||||
|
@ -115,7 +156,7 @@ func (m multiaddr) Decapsulate(o Multiaddr) Multiaddr {
|
|||
// if multiaddr not contained, returns a copy.
|
||||
cpy := make([]byte, len(m.bytes))
|
||||
copy(cpy, m.bytes)
|
||||
return multiaddr{bytes: cpy}
|
||||
return &multiaddr{bytes: cpy}
|
||||
}
|
||||
|
||||
ma, err := NewMultiaddr(s1[:i])
|
||||
|
@ -127,7 +168,7 @@ func (m multiaddr) Decapsulate(o Multiaddr) Multiaddr {
|
|||
|
||||
var ErrProtocolNotFound = fmt.Errorf("protocol not found in multiaddr")
|
||||
|
||||
func (m multiaddr) ValueForProtocol(code int) (value string, err error) {
|
||||
func (m *multiaddr) ValueForProtocol(code int) (value string, err error) {
|
||||
err = ErrProtocolNotFound
|
||||
ForEach(m, func(c Component) bool {
|
||||
if c.Protocol().Code == code {
|
||||
|
|
|
@ -555,3 +555,108 @@ func TestZone(t *testing.T) {
|
|||
t.Errorf("expected %s, got %s", ip6String, ma2.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBinaryMarshaler(t *testing.T) {
|
||||
addr := newMultiaddr(t, "/ip4/0.0.0.0/tcp/4001")
|
||||
b, err := addr.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addr2 := newMultiaddr(t, "")
|
||||
if err = addr2.UnmarshalBinary(b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !addr.Equal(addr2) {
|
||||
t.Error("expected equal addresses in circular marshaling test")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTextMarshaler(t *testing.T) {
|
||||
addr := newMultiaddr(t, "/ip4/0.0.0.0/tcp/4001")
|
||||
b, err := addr.MarshalText()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addr2 := newMultiaddr(t, "")
|
||||
if err = addr2.UnmarshalText(b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !addr.Equal(addr2) {
|
||||
t.Error("expected equal addresses in circular marshaling test")
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONMarshaler(t *testing.T) {
|
||||
addr := newMultiaddr(t, "/ip4/0.0.0.0/tcp/4001")
|
||||
b, err := addr.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addr2 := newMultiaddr(t, "")
|
||||
if err = addr2.UnmarshalJSON(b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !addr.Equal(addr2) {
|
||||
t.Error("expected equal addresses in circular marshaling test")
|
||||
}
|
||||
}
|
||||
|
||||
func TestComponentBinaryMarshaler(t *testing.T) {
|
||||
comp, err := NewComponent("ip4", "0.0.0.0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b, err := comp.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
comp2 := &Component{}
|
||||
if err = comp2.UnmarshalBinary(b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !comp.Equal(comp2) {
|
||||
t.Error("expected equal components in circular marshaling test")
|
||||
}
|
||||
}
|
||||
|
||||
func TestComponentTextMarshaler(t *testing.T) {
|
||||
comp, err := NewComponent("ip4", "0.0.0.0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b, err := comp.MarshalText()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
comp2 := &Component{}
|
||||
if err = comp2.UnmarshalText(b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !comp.Equal(comp2) {
|
||||
t.Error("expected equal components in circular marshaling test")
|
||||
}
|
||||
}
|
||||
|
||||
func TestComponentJSONMarshaler(t *testing.T) {
|
||||
comp, err := NewComponent("ip4", "0.0.0.0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b, err := comp.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
comp2 := &Component{}
|
||||
if err = comp2.UnmarshalJSON(b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !comp.Equal(comp2) {
|
||||
t.Error("expected equal components in circular marshaling test")
|
||||
}
|
||||
}
|
||||
|
|
10
util.go
10
util.go
|
@ -21,7 +21,7 @@ func Join(ms ...Multiaddr) Multiaddr {
|
|||
case 0:
|
||||
// empty multiaddr, unfortunately, we have callers that rely on
|
||||
// this contract.
|
||||
return multiaddr{}
|
||||
return &multiaddr{}
|
||||
case 1:
|
||||
return ms[0]
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ func Join(ms ...Multiaddr) Multiaddr {
|
|||
for _, mb := range bs {
|
||||
bidx += copy(b[bidx:], mb)
|
||||
}
|
||||
return multiaddr{bytes: b}
|
||||
return &multiaddr{bytes: b}
|
||||
}
|
||||
|
||||
// Cast re-casts a byte slice as a multiaddr. will panic if it fails to parse.
|
||||
|
@ -77,7 +77,7 @@ func SplitFirst(m Multiaddr) (*Component, Multiaddr) {
|
|||
if len(b) == n {
|
||||
return &c, nil
|
||||
}
|
||||
return &c, multiaddr{b[n:]}
|
||||
return &c, &multiaddr{b[n:]}
|
||||
}
|
||||
|
||||
// SplitLast returns the rest of the multiaddr and the last component.
|
||||
|
@ -109,7 +109,7 @@ func SplitLast(m Multiaddr) (Multiaddr, *Component) {
|
|||
// Only one component
|
||||
return nil, &c
|
||||
}
|
||||
return multiaddr{b[:offset]}, &c
|
||||
return &multiaddr{b[:offset]}, &c
|
||||
}
|
||||
offset += n
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ func SplitFunc(m Multiaddr, cb func(Component) bool) (Multiaddr, Multiaddr) {
|
|||
case len(b):
|
||||
return m, nil
|
||||
default:
|
||||
return multiaddr{b[:offset]}, multiaddr{b[offset:]}
|
||||
return &multiaddr{b[:offset]}, &multiaddr{b[offset:]}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue