influxdb/id.go

133 lines
2.8 KiB
Go
Raw Normal View History

package platform
import (
"encoding/binary"
"encoding/hex"
"encoding/json"
"errors"
"reflect"
"strconv"
"unsafe"
)
2018-10-10 18:57:18 +00:00
// IDLength is the exact length a string (or a byte slice representing it) must have in order to be decoded into a valid ID.
const IDLength = 16
// ErrInvalidID signifies invalid IDs.
var ErrInvalidID = errors.New("invalid ID")
// ErrInvalidIDLength is returned when an ID has the incorrect number of bytes.
var ErrInvalidIDLength = errors.New("id must have a length of 16 bytes")
// ID is a unique identifier.
//
// Its zero value is not a valid ID.
type ID uint64
// IDGenerator represents a generator for IDs.
type IDGenerator interface {
// ID creates unique byte slice ID.
2018-07-30 11:38:23 +00:00
ID() ID
}
// IDFromString creates an ID from a given string.
//
// It errors if the input string does not match a valid ID.
func IDFromString(str string) (*ID, error) {
var id ID
err := id.DecodeFromString(str)
if err != nil {
return nil, err
}
return &id, nil
}
// InvalidID returns a zero ID.
func InvalidID() ID {
return 0
}
// Decode parses b as a hex-encoded byte-slice-string.
//
// It errors if the input byte slice does not have the correct length
// or if it contains all zeros.
func (i *ID) Decode(b []byte) error {
2018-10-10 18:57:18 +00:00
if len(b) != IDLength {
return ErrInvalidIDLength
}
res, err := strconv.ParseUint(unsafeBytesToString(b), 16, 64)
if err != nil {
return err
}
if *i = ID(res); !i.Valid() {
return ErrInvalidID
}
return nil
}
func unsafeBytesToString(in []byte) string {
src := *(*reflect.SliceHeader)(unsafe.Pointer(&in))
dst := reflect.StringHeader{
Data: src.Data,
Len: src.Len,
}
s := *(*string)(unsafe.Pointer(&dst))
return s
}
// DecodeFromString parses s as a hex-encoded string.
func (i *ID) DecodeFromString(s string) error {
return i.Decode([]byte(s))
}
// Encode converts ID to a hex-encoded byte-slice-string.
//
// It errors if the receiving ID holds its zero value.
func (i ID) Encode() ([]byte, error) {
if !i.Valid() {
return nil, ErrInvalidID
}
2018-10-10 18:57:18 +00:00
b := make([]byte, hex.DecodedLen(IDLength))
binary.BigEndian.PutUint64(b, uint64(i))
dst := make([]byte, hex.EncodedLen(len(b)))
hex.Encode(dst, b)
return dst, nil
}
// Valid checks whether the receiving ID is a valid one or not.
func (i ID) Valid() bool {
return i != 0
2018-07-30 11:38:23 +00:00
}
// String returns the ID as a hex encoded string.
//
// Returns an empty string in the case the ID is invalid.
func (i ID) String() string {
enc, _ := i.Encode()
return string(enc)
}
// UnmarshalJSON implements JSON unmarshaller for IDs.
func (i *ID) UnmarshalJSON(b []byte) error {
if b[0] == '"' {
b = b[1:]
}
if b[len(b)-1] == '"' {
b = b[:len(b)-1]
}
return i.Decode(b)
}
// MarshalJSON implements JSON marshaller for IDs.
func (i ID) MarshalJSON() ([]byte, error) {
enc, err := i.Encode()
if err != nil {
return nil, err
}
return json.Marshal(string(enc))
}