tlv/record: adds various tlv record constructors
This commit is contained in:
parent
6773d4770a
commit
96e0bb1411
153
tlv/record.go
Normal file
153
tlv/record.go
Normal file
@ -0,0 +1,153 @@
|
||||
package tlv
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
// Type is an 64-bit identifier for a TLV Record.
|
||||
type Type uint64
|
||||
|
||||
// Encoder is a signature for methods that can encode TLV values. An error
|
||||
// should be returned if the Encoder cannot support the underlying type of val.
|
||||
// The provided scratch buffer must be non-nil.
|
||||
type Encoder func(w io.Writer, val interface{}, buf *[8]byte) error
|
||||
|
||||
// Decoder is a signature for methods that can decode TLV values. An error
|
||||
// should be returned if the Decoder cannot support the underlying type of val.
|
||||
// The provided scratch buffer must be non-nil.
|
||||
type Decoder func(r io.Reader, val interface{}, buf *[8]byte, l uint64) error
|
||||
|
||||
// ENOP is an encoder that doesn't modify the io.Writer and never fails.
|
||||
func ENOP(io.Writer, interface{}, *[8]byte) error { return nil }
|
||||
|
||||
// DNOP is an encoder that doesn't modify the io.Reader and never fails.
|
||||
func DNOP(io.Reader, interface{}, *[8]byte, uint64) error { return nil }
|
||||
|
||||
// SizeFunc is a function that can compute the length of a given field. Since
|
||||
// the size of the underlying field can change, this allows the size of the
|
||||
// field to be evaluated at the time of encoding.
|
||||
type SizeFunc func() uint64
|
||||
|
||||
// SizeVarBytes returns a SizeFunc that can compute the length of a byte slice.
|
||||
func SizeVarBytes(e *[]byte) SizeFunc {
|
||||
return func() uint64 {
|
||||
return uint64(len(*e))
|
||||
}
|
||||
}
|
||||
|
||||
// Record holds the required information to encode or decode a TLV record.
|
||||
type Record struct {
|
||||
value interface{}
|
||||
typ Type
|
||||
staticSize uint64
|
||||
sizeFunc SizeFunc
|
||||
encoder Encoder
|
||||
decoder Decoder
|
||||
}
|
||||
|
||||
// Size returns the size of the Record's value. If no static size is known, the
|
||||
// dynamic size will be evaluated.
|
||||
func (f *Record) Size() uint64 {
|
||||
if f.sizeFunc == nil {
|
||||
return f.staticSize
|
||||
}
|
||||
|
||||
return f.sizeFunc()
|
||||
}
|
||||
|
||||
// MakePrimitiveRecord creates a record for common types.
|
||||
func MakePrimitiveRecord(typ Type, val interface{}) Record {
|
||||
var (
|
||||
staticSize uint64
|
||||
sizeFunc SizeFunc
|
||||
encoder Encoder
|
||||
decoder Decoder
|
||||
)
|
||||
switch e := val.(type) {
|
||||
case *uint8:
|
||||
staticSize = 1
|
||||
encoder = EUint8
|
||||
decoder = DUint8
|
||||
|
||||
case *uint16:
|
||||
staticSize = 2
|
||||
encoder = EUint16
|
||||
decoder = DUint16
|
||||
|
||||
case *uint32:
|
||||
staticSize = 4
|
||||
encoder = EUint32
|
||||
decoder = DUint32
|
||||
|
||||
case *uint64:
|
||||
staticSize = 8
|
||||
encoder = EUint64
|
||||
decoder = DUint64
|
||||
|
||||
case *[32]byte:
|
||||
staticSize = 32
|
||||
encoder = EBytes32
|
||||
decoder = DBytes32
|
||||
|
||||
case *[33]byte:
|
||||
staticSize = 33
|
||||
encoder = EBytes33
|
||||
decoder = DBytes33
|
||||
|
||||
case **btcec.PublicKey:
|
||||
staticSize = 33
|
||||
encoder = EPubKey
|
||||
decoder = DPubKey
|
||||
|
||||
case *[64]byte:
|
||||
staticSize = 64
|
||||
encoder = EBytes64
|
||||
decoder = DBytes64
|
||||
|
||||
case *[]byte:
|
||||
sizeFunc = SizeVarBytes(e)
|
||||
encoder = EVarBytes
|
||||
decoder = DVarBytes
|
||||
|
||||
default:
|
||||
panic("unknown primitive type")
|
||||
}
|
||||
|
||||
return Record{
|
||||
value: val,
|
||||
typ: typ,
|
||||
staticSize: staticSize,
|
||||
sizeFunc: sizeFunc,
|
||||
encoder: encoder,
|
||||
decoder: decoder,
|
||||
}
|
||||
}
|
||||
|
||||
// MakeStaticRecord creates a record for a field of fixed-size
|
||||
func MakeStaticRecord(typ Type, val interface{}, size uint64, encoder Encoder,
|
||||
decoder Decoder) Record {
|
||||
|
||||
return Record{
|
||||
value: val,
|
||||
typ: typ,
|
||||
staticSize: size,
|
||||
encoder: encoder,
|
||||
decoder: decoder,
|
||||
}
|
||||
}
|
||||
|
||||
// MakeDynamicRecord creates a record whose size may vary, and will be
|
||||
// determined at the time of encoding via sizeFunc.
|
||||
func MakeDynamicRecord(typ Type, val interface{}, sizeFunc SizeFunc,
|
||||
encoder Encoder, decoder Decoder) Record {
|
||||
|
||||
return Record{
|
||||
value: val,
|
||||
typ: typ,
|
||||
sizeFunc: sizeFunc,
|
||||
encoder: encoder,
|
||||
decoder: decoder,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user