all: implement AppendText alongside MarshalText (#9207)

This eventually allows encoding packages that may respect
the proposed encoding.TextAppender interface.
The performance gains from this is between 10-30%.

Updates tailscale/corp#14379

Signed-off-by: Joe Tsai <joetsai@digital-static.net>
This commit is contained in:
Joe Tsai
2023-09-01 18:15:19 -07:00
committed by GitHub
parent 9a3bc9049c
commit c6fadd6d71
12 changed files with 108 additions and 69 deletions

View File

@@ -72,9 +72,14 @@ func (k ChallengePublic) String() string {
return string(bs)
}
// AppendText implements encoding.TextAppender.
func (k ChallengePublic) AppendText(b []byte) ([]byte, error) {
return appendHexKey(b, chalPublicHexPrefix, k.k[:]), nil
}
// MarshalText implements encoding.TextMarshaler.
func (k ChallengePublic) MarshalText() ([]byte, error) {
return toHex(k.k[:], chalPublicHexPrefix), nil
return k.AppendText(nil)
}
// UnmarshalText implements encoding.TextUnmarshaler.

View File

@@ -127,9 +127,14 @@ func (k DiscoPublic) String() string {
return string(bs)
}
// AppendText implements encoding.TextAppender.
func (k DiscoPublic) AppendText(b []byte) ([]byte, error) {
return appendHexKey(b, discoPublicHexPrefix, k.k[:]), nil
}
// MarshalText implements encoding.TextMarshaler.
func (k DiscoPublic) MarshalText() ([]byte, error) {
return toHex(k.k[:], discoPublicHexPrefix), nil
return k.AppendText(nil)
}
// MarshalText implements encoding.TextUnmarshaler.

View File

@@ -67,9 +67,14 @@ func (k MachinePrivate) Public() MachinePublic {
return ret
}
// AppendText implements encoding.TextAppender.
func (k MachinePrivate) AppendText(b []byte) ([]byte, error) {
return appendHexKey(b, machinePrivateHexPrefix, k.k[:]), nil
}
// MarshalText implements encoding.TextMarshaler.
func (k MachinePrivate) MarshalText() ([]byte, error) {
return toHex(k.k[:], machinePrivateHexPrefix), nil
return k.AppendText(nil)
}
// MarshalText implements encoding.TextUnmarshaler.
@@ -243,9 +248,14 @@ func (k MachinePublic) String() string {
return string(bs)
}
// AppendText implements encoding.TextAppender.
func (k MachinePublic) AppendText(b []byte) ([]byte, error) {
return appendHexKey(b, machinePublicHexPrefix, k.k[:]), nil
}
// MarshalText implements encoding.TextMarshaler.
func (k MachinePublic) MarshalText() ([]byte, error) {
return toHex(k.k[:], machinePublicHexPrefix), nil
return k.AppendText(nil)
}
// MarshalText implements encoding.TextUnmarshaler.

View File

@@ -61,9 +61,14 @@ func (k *NLPrivate) UnmarshalText(b []byte) error {
return parseHex(k.k[:], mem.B(b), mem.S(nlPrivateHexPrefix))
}
// AppendText implements encoding.TextAppender.
func (k NLPrivate) AppendText(b []byte) ([]byte, error) {
return appendHexKey(b, nlPrivateHexPrefix, k.k[:]), nil
}
// MarshalText implements encoding.TextMarshaler.
func (k NLPrivate) MarshalText() ([]byte, error) {
return toHex(k.k[:], nlPrivateHexPrefix), nil
return k.AppendText(nil)
}
// Equal reports whether k and other are the same key.
@@ -132,10 +137,15 @@ func (k *NLPublic) UnmarshalText(b []byte) error {
return parseHex(k.k[:], mem.B(b), mem.S(nlPublicHexPrefix))
}
// AppendText implements encoding.TextAppender.
func (k NLPublic) AppendText(b []byte) ([]byte, error) {
return appendHexKey(b, nlPublicHexPrefix, k.k[:]), nil
}
// MarshalText implements encoding.TextMarshaler, emitting a
// representation of the form nlpub:<hex>.
func (k NLPublic) MarshalText() ([]byte, error) {
return toHex(k.k[:], nlPublicHexPrefix), nil
return k.AppendText(nil)
}
// CLIString returns a marshalled representation suitable for use
@@ -143,7 +153,7 @@ func (k NLPublic) MarshalText() ([]byte, error) {
// the nlpub:<hex> form emitted by MarshalText. Both forms can
// be decoded by UnmarshalText.
func (k NLPublic) CLIString() string {
return string(toHex(k.k[:], nlPublicHexPrefixCLI))
return string(appendHexKey(nil, nlPublicHexPrefixCLI, k.k[:]))
}
// Verifier returns a ed25519.PublicKey that can be used to

View File

@@ -103,9 +103,14 @@ func (k NodePrivate) Public() NodePublic {
return ret
}
// AppendText implements encoding.TextAppender.
func (k NodePrivate) AppendText(b []byte) ([]byte, error) {
return appendHexKey(b, nodePrivateHexPrefix, k.k[:]), nil
}
// MarshalText implements encoding.TextMarshaler.
func (k NodePrivate) MarshalText() ([]byte, error) {
return toHex(k.k[:], nodePrivateHexPrefix), nil
return k.AppendText(nil)
}
// MarshalText implements encoding.TextUnmarshaler.
@@ -308,9 +313,14 @@ func (k NodePublic) String() string {
return string(bs)
}
// AppendText implements encoding.TextAppender.
func (k NodePublic) AppendText(b []byte) ([]byte, error) {
return appendHexKey(b, nodePublicHexPrefix, k.k[:]), nil
}
// MarshalText implements encoding.TextMarshaler.
func (k NodePublic) MarshalText() ([]byte, error) {
return toHex(k.k[:], nodePublicHexPrefix), nil
return k.AppendText(nil)
}
// MarshalText implements encoding.TextUnmarshaler.

View File

@@ -10,6 +10,7 @@ import (
"errors"
"fmt"
"io"
"slices"
"go4.org/mem"
)
@@ -49,11 +50,19 @@ func clamp25519Private(b []byte) {
b[31] = (b[31] & 127) | 64
}
func toHex(k []byte, prefix string) []byte {
ret := make([]byte, len(prefix)+len(k)*2)
copy(ret, prefix)
hex.Encode(ret[len(prefix):], k)
return ret
func appendHexKey(dst []byte, prefix string, key []byte) []byte {
dst = slices.Grow(dst, len(prefix)+hex.EncodedLen(len(key)))
dst = append(dst, prefix...)
dst = hexAppendEncode(dst, key)
return dst
}
// TODO(https://go.dev/issue/53693): Use hex.AppendEncode instead.
func hexAppendEncode(dst, src []byte) []byte {
n := hex.EncodedLen(len(src))
dst = slices.Grow(dst, n)
hex.Encode(dst[len(dst):][:n], src)
return dst[:len(dst)+n]
}
// parseHex decodes a key string of the form "<prefix><hex string>"

View File

@@ -38,8 +38,12 @@ func ParsePrivateID(in string) (out PrivateID, err error) {
return out, err
}
func (id PrivateID) AppendText(b []byte) ([]byte, error) {
return hexAppendEncode(b, id[:]), nil
}
func (id PrivateID) MarshalText() ([]byte, error) {
return formatID(id), nil
return id.AppendText(nil)
}
func (id *PrivateID) UnmarshalText(in []byte) error {
@@ -47,7 +51,7 @@ func (id *PrivateID) UnmarshalText(in []byte) error {
}
func (id PrivateID) String() string {
return string(formatID(id))
return string(hexAppendEncode(nil, id[:]))
}
func (id PrivateID) IsZero() bool {
@@ -70,8 +74,12 @@ func ParsePublicID(in string) (out PublicID, err error) {
return out, err
}
func (id PublicID) AppendText(b []byte) ([]byte, error) {
return hexAppendEncode(b, id[:]), nil
}
func (id PublicID) MarshalText() ([]byte, error) {
return formatID(id), nil
return id.AppendText(nil)
}
func (id *PublicID) UnmarshalText(in []byte) error {
@@ -79,7 +87,7 @@ func (id *PublicID) UnmarshalText(in []byte) error {
}
func (id PublicID) String() string {
return string(formatID(id))
return string(hexAppendEncode(nil, id[:]))
}
func (id1 PublicID) Less(id2 PublicID) bool {
@@ -98,10 +106,12 @@ func (id PublicID) Prefix64() uint64 {
return binary.BigEndian.Uint64(id[:8])
}
func formatID(in [32]byte) []byte {
var hexArr [2 * len(in)]byte
hex.Encode(hexArr[:], in[:])
return hexArr[:]
// TODO(https://go.dev/issue/53693): Use hex.AppendEncode instead.
func hexAppendEncode(dst, src []byte) []byte {
n := hex.EncodedLen(len(src))
dst = slices.Grow(dst, n)
hex.Encode(dst[len(dst):][:n], src)
return dst[:len(dst)+n]
}
func parseID[Bytes []byte | string](funcName string, out *[32]byte, in Bytes) (err error) {