ident: implement full representation
This can be used with both system and member identifiers. Signed-off-by: Yonah <contrib@gensokyo.uk>
This commit is contained in:
@@ -7,10 +7,16 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// ErrNewline is returned for identifiers found to contain newline characters.
|
||||
var ErrNewline = errors.New("identifier contains newline characters")
|
||||
var (
|
||||
// ErrNewline is returned for identifiers found to contain newline characters.
|
||||
ErrNewline = errors.New("identifier contains newline characters")
|
||||
// ErrSeparator is returned for representations of [F] missing its separator
|
||||
// byte in its expected index.
|
||||
ErrSeparator = errors.New("identifier has incorrect separator byte")
|
||||
)
|
||||
|
||||
// UnexpectedSizeError describes a malformed string representation of an
|
||||
// identifier, with unexpected length.
|
||||
@@ -41,3 +47,53 @@ type MS interface {
|
||||
// behaviour: a type is an identifier part if it has an ident method.
|
||||
ident()
|
||||
}
|
||||
|
||||
// F represents a full system or member identifier.
|
||||
type F[V any, T interface {
|
||||
MS
|
||||
*V
|
||||
}] struct {
|
||||
// Underlying system or member.
|
||||
I T
|
||||
// Split from instance suffix after [Separator] byte.
|
||||
Remote Remote
|
||||
}
|
||||
|
||||
// Separator is the byte separating representation of [MS] from [Remote].
|
||||
const Separator = ':'
|
||||
|
||||
// Encode appends the canonical string representation of full to dst and returns
|
||||
// the extended buffer.
|
||||
func (full *F[V, T]) Encode(dst []byte) []byte {
|
||||
dst = full.I.Encode(dst)
|
||||
dst = append(dst, Separator)
|
||||
dst = full.Remote.Encode(dst)
|
||||
return dst
|
||||
}
|
||||
|
||||
// String returns the canonical string representation of full.
|
||||
func (full *F[V, T]) String() string {
|
||||
s := full.Encode(nil)
|
||||
return unsafe.String(unsafe.SliceData(s), len(s))
|
||||
}
|
||||
|
||||
// MarshalText returns the result of Encode.
|
||||
func (full *F[V, T]) MarshalText() (data []byte, err error) {
|
||||
return full.Encode(nil), nil
|
||||
}
|
||||
|
||||
// UnmarshalText strictly decodes data into full.
|
||||
func (full *F[V, T]) UnmarshalText(data []byte) (err error) {
|
||||
sz := full.I.EncodedSize()
|
||||
if len(data) < sz+1 || data[sz] != Separator {
|
||||
return ErrSeparator
|
||||
}
|
||||
|
||||
if full.I == nil {
|
||||
full.I = new(V)
|
||||
}
|
||||
if err = full.I.UnmarshalText(data[:sz]); err != nil {
|
||||
return
|
||||
}
|
||||
return full.Remote.UnmarshalText(data[sz+1:])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user