util.go 2.96 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2
package multiaddr

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
3
import "fmt"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
4 5 6

// Split returns the sub-address portions of a multiaddr.
func Split(m Multiaddr) []Multiaddr {
Steven Allen's avatar
Steven Allen committed
7 8 9 10 11
	var addrs []Multiaddr
	ForEach(m, func(c Component) bool {
		addrs = append(addrs, &c)
		return true
	})
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
12 13 14 15 16
	return addrs
}

// Join returns a combination of addresses.
func Join(ms ...Multiaddr) Multiaddr {
Steven Allen's avatar
Steven Allen committed
17 18 19 20 21 22 23 24
	switch len(ms) {
	case 0:
		// empty multiaddr, unfortunately, we have callers that rely on
		// this contract.
		return multiaddr{}
	case 1:
		return ms[0]
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
25 26 27 28 29 30 31 32 33 34 35

	length := 0
	bs := make([][]byte, len(ms))
	for i, m := range ms {
		bs[i] = m.Bytes()
		length += len(bs[i])
	}

	bidx := 0
	b := make([]byte, length)
	for _, mb := range bs {
Steven Allen's avatar
Steven Allen committed
36
		bidx += copy(b[bidx:], mb)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
37
	}
38
	return multiaddr{bytes: b}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
39 40 41 42
}

// Cast re-casts a byte slice as a multiaddr. will panic if it fails to parse.
func Cast(b []byte) Multiaddr {
Steven Allen's avatar
Steven Allen committed
43
	m, err := NewMultiaddrBytes(b)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
44 45 46
	if err != nil {
		panic(fmt.Errorf("multiaddr failed to parse: %s", err))
	}
Steven Allen's avatar
Steven Allen committed
47
	return m
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
48 49 50 51 52 53 54 55 56 57
}

// StringCast like Cast, but parses a string. Will also panic if it fails to parse.
func StringCast(s string) Multiaddr {
	m, err := NewMultiaddr(s)
	if err != nil {
		panic(fmt.Errorf("multiaddr failed to parse: %s", err))
	}
	return m
}
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154

// SplitFirst returns the first component and the rest of the multiaddr.
func SplitFirst(m Multiaddr) (*Component, Multiaddr) {
	b := m.Bytes()
	if len(b) == 0 {
		return nil, nil
	}
	n, c, err := readComponent(b)
	if err != nil {
		panic(err)
	}
	if len(b) == n {
		return &c, nil
	}
	return &c, multiaddr{b[n:]}
}

// SplitLast returns the rest of the multiaddr and the last component.
func SplitLast(m Multiaddr) (Multiaddr, *Component) {
	b := m.Bytes()
	if len(b) == 0 {
		return nil, nil
	}

	var (
		c      Component
		err    error
		offset int
	)
	for {
		var n int
		n, c, err = readComponent(b[offset:])
		if err != nil {
			panic(err)
		}
		if len(b) == n+offset {
			// Reached end
			if offset == 0 {
				// Only one component
				return nil, &c
			}
			return multiaddr{b[:offset]}, &c
		}
		offset += n
	}
}

// SplitFunc splits the multiaddr when the callback first returns true. The
// component on which the callback first returns will be included in the
// *second* multiaddr.
func SplitFunc(m Multiaddr, cb func(Component) bool) (Multiaddr, Multiaddr) {
	b := m.Bytes()
	if len(b) == 0 {
		return nil, nil
	}
	var (
		c      Component
		err    error
		offset int
	)
	for offset < len(b) {
		var n int
		n, c, err = readComponent(b[offset:])
		if err != nil {
			panic(err)
		}
		if cb(c) {
			break
		}
		offset += n
	}
	switch offset {
	case 0:
		return nil, m
	case len(b):
		return m, nil
	default:
		return multiaddr{b[:offset]}, multiaddr{b[offset:]}
	}
}

// ForEach walks over the multiaddr, component by component.
//
// This function iterates over components *by value* to avoid allocating.
func ForEach(m Multiaddr, cb func(c Component) bool) {
	b := m.Bytes()
	for len(b) > 0 {
		n, c, err := readComponent(b)
		if err != nil {
			panic(err)
		}
		if !cb(c) {
			return
		}
		b = b[n:]
	}
}