84
vendor/github.com/bifurcation/mint/syntax/README.md
generated
vendored
Normal file
84
vendor/github.com/bifurcation/mint/syntax/README.md
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
TLS Syntax
|
||||
==========
|
||||
|
||||
TLS defines [its own syntax](https://tlswg.github.io/tls13-spec/#rfc.section.3)
|
||||
for describing structures used in that protocol. To facilitate experimentation
|
||||
with TLS in Go, this module maps that syntax to the Go structure syntax, taking
|
||||
advantage of Go's type annotations to encode non-type information carried in the
|
||||
TLS presentation format.
|
||||
|
||||
For example, in the TLS specification, a ClientHello message has the following
|
||||
structure:
|
||||
|
||||
~~~~~
|
||||
uint16 ProtocolVersion;
|
||||
opaque Random[32];
|
||||
uint8 CipherSuite[2];
|
||||
enum { ... (65535)} ExtensionType;
|
||||
|
||||
struct {
|
||||
ExtensionType extension_type;
|
||||
opaque extension_data<0..2^16-1>;
|
||||
} Extension;
|
||||
|
||||
struct {
|
||||
ProtocolVersion legacy_version = 0x0303; /* TLS v1.2 */
|
||||
Random random;
|
||||
opaque legacy_session_id<0..32>;
|
||||
CipherSuite cipher_suites<2..2^16-2>;
|
||||
opaque legacy_compression_methods<1..2^8-1>;
|
||||
Extension extensions<0..2^16-1>;
|
||||
} ClientHello;
|
||||
~~~~~
|
||||
|
||||
This maps to the following Go type definitions:
|
||||
|
||||
~~~~~
|
||||
type protocolVersion uint16
|
||||
type random [32]byte
|
||||
type cipherSuite uint16 // or [2]byte
|
||||
type extensionType uint16
|
||||
|
||||
type extension struct {
|
||||
ExtensionType extensionType
|
||||
ExtensionData []byte `tls:"head=2"`
|
||||
}
|
||||
|
||||
type clientHello struct {
|
||||
LegacyVersion protocolVersion
|
||||
Random random
|
||||
LegacySessionID []byte `tls:"head=1,max=32"`
|
||||
CipherSuites []cipherSuite `tls:"head=2,min=2"`
|
||||
LegacyCompressionMethods []byte `tls:"head=1,min=1"`
|
||||
Extensions []extension `tls:"head=2"`
|
||||
}
|
||||
~~~~~
|
||||
|
||||
Then you can just declare, marshal, and unmarshal structs just like you would
|
||||
with, say JSON.
|
||||
|
||||
The available annotations right now are all related to vectors:
|
||||
|
||||
* `head`: The number of bytes of length to use as a "header"
|
||||
* `min`: The minimum length of the vector, in bytes
|
||||
* `max`: The maximum length of the vector, in bytes
|
||||
|
||||
## Not supported
|
||||
|
||||
* The `select()` syntax for creating alternate version of the same struct (see,
|
||||
e.g., the KeyShare extension)
|
||||
|
||||
* The backreference syntax for array lengths or select parameters, as in `opaque
|
||||
fragment[TLSPlaintext.length]`. Note, however, that in cases where the length
|
||||
immediately preceds the array, these can be reframed as vectors with
|
||||
appropriate sizes.
|
||||
|
||||
|
||||
QUIC Extensions Syntax
|
||||
======================
|
||||
syntax also supports some minor extensions to allow implementing QUIC.
|
||||
|
||||
* The `varint` annotation describes a QUIC-style varint
|
||||
* `head=none` means no header, i.e., the bytes are encoded directly on the wire.
|
||||
On reading, the decoder will consume all available data.
|
||||
* `head=varint` means to encode the header as a varint
|
||||
344
vendor/github.com/bifurcation/mint/syntax/decode.go
generated
vendored
Normal file
344
vendor/github.com/bifurcation/mint/syntax/decode.go
generated
vendored
Normal file
@@ -0,0 +1,344 @@
|
||||
package syntax
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func Unmarshal(data []byte, v interface{}) (int, error) {
|
||||
// Check for well-formedness.
|
||||
// Avoids filling out half a data structure
|
||||
// before discovering a JSON syntax error.
|
||||
d := decodeState{}
|
||||
d.Write(data)
|
||||
return d.unmarshal(v)
|
||||
}
|
||||
|
||||
// Unmarshaler is the interface implemented by types that can
|
||||
// unmarshal a TLS description of themselves. Note that unlike the
|
||||
// JSON unmarshaler interface, it is not known a priori how much of
|
||||
// the input data will be consumed. So the Unmarshaler must state
|
||||
// how much of the input data it consumed.
|
||||
type Unmarshaler interface {
|
||||
UnmarshalTLS([]byte) (int, error)
|
||||
}
|
||||
|
||||
// These are the options that can be specified in the struct tag. Right now,
|
||||
// all of them apply to variable-length vectors and nothing else
|
||||
type decOpts struct {
|
||||
head uint // length of length in bytes
|
||||
min uint // minimum size in bytes
|
||||
max uint // maximum size in bytes
|
||||
varint bool // whether to decode as a varint
|
||||
}
|
||||
|
||||
type decodeState struct {
|
||||
bytes.Buffer
|
||||
}
|
||||
|
||||
func (d *decodeState) unmarshal(v interface{}) (read int, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if _, ok := r.(runtime.Error); ok {
|
||||
panic(r)
|
||||
}
|
||||
if s, ok := r.(string); ok {
|
||||
panic(s)
|
||||
}
|
||||
err = r.(error)
|
||||
}
|
||||
}()
|
||||
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Kind() != reflect.Ptr || rv.IsNil() {
|
||||
return 0, fmt.Errorf("Invalid unmarshal target (non-pointer or nil)")
|
||||
}
|
||||
|
||||
read = d.value(rv)
|
||||
return read, nil
|
||||
}
|
||||
|
||||
func (e *decodeState) value(v reflect.Value) int {
|
||||
return valueDecoder(v)(e, v, decOpts{})
|
||||
}
|
||||
|
||||
type decoderFunc func(e *decodeState, v reflect.Value, opts decOpts) int
|
||||
|
||||
func valueDecoder(v reflect.Value) decoderFunc {
|
||||
return typeDecoder(v.Type().Elem())
|
||||
}
|
||||
|
||||
func typeDecoder(t reflect.Type) decoderFunc {
|
||||
// Note: Omits the caching / wait-group things that encoding/json uses
|
||||
return newTypeDecoder(t)
|
||||
}
|
||||
|
||||
var (
|
||||
unmarshalerType = reflect.TypeOf(new(Unmarshaler)).Elem()
|
||||
)
|
||||
|
||||
func newTypeDecoder(t reflect.Type) decoderFunc {
|
||||
if t.Kind() != reflect.Ptr && reflect.PtrTo(t).Implements(unmarshalerType) {
|
||||
return unmarshalerDecoder
|
||||
}
|
||||
|
||||
switch t.Kind() {
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return uintDecoder
|
||||
case reflect.Array:
|
||||
return newArrayDecoder(t)
|
||||
case reflect.Slice:
|
||||
return newSliceDecoder(t)
|
||||
case reflect.Struct:
|
||||
return newStructDecoder(t)
|
||||
case reflect.Ptr:
|
||||
return newPointerDecoder(t)
|
||||
default:
|
||||
panic(fmt.Errorf("Unsupported type (%s)", t))
|
||||
}
|
||||
}
|
||||
|
||||
///// Specific decoders below
|
||||
|
||||
func unmarshalerDecoder(d *decodeState, v reflect.Value, opts decOpts) int {
|
||||
um, ok := v.Interface().(Unmarshaler)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("Non-Unmarshaler passed to unmarshalerEncoder"))
|
||||
}
|
||||
|
||||
read, err := um.UnmarshalTLS(d.Bytes())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if read > d.Len() {
|
||||
panic(fmt.Errorf("Invalid return value from UnmarshalTLS"))
|
||||
}
|
||||
|
||||
d.Next(read)
|
||||
return read
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
func uintDecoder(d *decodeState, v reflect.Value, opts decOpts) int {
|
||||
if opts.varint {
|
||||
return varintDecoder(d, v, opts)
|
||||
}
|
||||
|
||||
uintLen := int(v.Elem().Type().Size())
|
||||
buf := d.Next(uintLen)
|
||||
if len(buf) != uintLen {
|
||||
panic(fmt.Errorf("Insufficient data to read uint"))
|
||||
}
|
||||
|
||||
return setUintFromBuffer(v, buf)
|
||||
}
|
||||
|
||||
func varintDecoder(d *decodeState, v reflect.Value, opts decOpts) int {
|
||||
l, val := readVarint(d)
|
||||
|
||||
uintLen := int(v.Elem().Type().Size())
|
||||
if uintLen < l {
|
||||
panic(fmt.Errorf("Uint too small to fit varint: %d < %d", uintLen, l))
|
||||
}
|
||||
|
||||
v.Elem().SetUint(val)
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func readVarint(d *decodeState) (int, uint64) {
|
||||
// Read the first octet and decide the size of the presented varint
|
||||
first := d.Next(1)
|
||||
if len(first) != 1 {
|
||||
panic(fmt.Errorf("Insufficient data to read varint length"))
|
||||
}
|
||||
|
||||
twoBits := uint(first[0] >> 6)
|
||||
varintLen := 1 << twoBits
|
||||
|
||||
rest := d.Next(varintLen - 1)
|
||||
if len(rest) != varintLen-1 {
|
||||
panic(fmt.Errorf("Insufficient data to read varint"))
|
||||
}
|
||||
|
||||
buf := append(first, rest...)
|
||||
buf[0] &= 0x3f
|
||||
|
||||
return len(buf), decodeUintFromBuffer(buf)
|
||||
}
|
||||
|
||||
func decodeUintFromBuffer(buf []byte) uint64 {
|
||||
val := uint64(0)
|
||||
for _, b := range buf {
|
||||
val = (val << 8) + uint64(b)
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
func setUintFromBuffer(v reflect.Value, buf []byte) int {
|
||||
v.Elem().SetUint(decodeUintFromBuffer(buf))
|
||||
return len(buf)
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type arrayDecoder struct {
|
||||
elemDec decoderFunc
|
||||
}
|
||||
|
||||
func (ad *arrayDecoder) decode(d *decodeState, v reflect.Value, opts decOpts) int {
|
||||
n := v.Elem().Type().Len()
|
||||
read := 0
|
||||
for i := 0; i < n; i += 1 {
|
||||
read += ad.elemDec(d, v.Elem().Index(i).Addr(), opts)
|
||||
}
|
||||
return read
|
||||
}
|
||||
|
||||
func newArrayDecoder(t reflect.Type) decoderFunc {
|
||||
dec := &arrayDecoder{typeDecoder(t.Elem())}
|
||||
return dec.decode
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type sliceDecoder struct {
|
||||
elementType reflect.Type
|
||||
elementDec decoderFunc
|
||||
}
|
||||
|
||||
func (sd *sliceDecoder) decode(d *decodeState, v reflect.Value, opts decOpts) int {
|
||||
var length uint64
|
||||
var read int
|
||||
var data []byte
|
||||
|
||||
if opts.head == 0 {
|
||||
panic(fmt.Errorf("Cannot decode a slice without a header length"))
|
||||
}
|
||||
|
||||
// If the caller indicated there is no header, then read everything from the buffer
|
||||
if opts.head == headValueNoHead {
|
||||
for {
|
||||
chunk := d.Next(1024)
|
||||
data = append(data, chunk...)
|
||||
if len(chunk) != 1024 {
|
||||
break
|
||||
}
|
||||
}
|
||||
length = uint64(len(data))
|
||||
if opts.max > 0 && length > uint64(opts.max) {
|
||||
panic(fmt.Errorf("Length of vector exceeds declared max"))
|
||||
}
|
||||
if length < uint64(opts.min) {
|
||||
panic(fmt.Errorf("Length of vector below declared min"))
|
||||
}
|
||||
} else {
|
||||
if opts.head != headValueVarint {
|
||||
lengthBytes := d.Next(int(opts.head))
|
||||
if len(lengthBytes) != int(opts.head) {
|
||||
panic(fmt.Errorf("Not enough data to read header"))
|
||||
}
|
||||
read = len(lengthBytes)
|
||||
length = decodeUintFromBuffer(lengthBytes)
|
||||
} else {
|
||||
read, length = readVarint(d)
|
||||
}
|
||||
if opts.max > 0 && length > uint64(opts.max) {
|
||||
panic(fmt.Errorf("Length of vector exceeds declared max"))
|
||||
}
|
||||
if length < uint64(opts.min) {
|
||||
panic(fmt.Errorf("Length of vector below declared min"))
|
||||
}
|
||||
|
||||
data = d.Next(int(length))
|
||||
if len(data) != int(length) {
|
||||
panic(fmt.Errorf("Available data less than declared length [%d < %d]", len(data), length))
|
||||
}
|
||||
}
|
||||
|
||||
elemBuf := &decodeState{}
|
||||
elemBuf.Write(data)
|
||||
elems := []reflect.Value{}
|
||||
for elemBuf.Len() > 0 {
|
||||
elem := reflect.New(sd.elementType)
|
||||
read += sd.elementDec(elemBuf, elem, opts)
|
||||
elems = append(elems, elem)
|
||||
}
|
||||
|
||||
v.Elem().Set(reflect.MakeSlice(v.Elem().Type(), len(elems), len(elems)))
|
||||
for i := 0; i < len(elems); i += 1 {
|
||||
v.Elem().Index(i).Set(elems[i].Elem())
|
||||
}
|
||||
return read
|
||||
}
|
||||
|
||||
func newSliceDecoder(t reflect.Type) decoderFunc {
|
||||
dec := &sliceDecoder{
|
||||
elementType: t.Elem(),
|
||||
elementDec: typeDecoder(t.Elem()),
|
||||
}
|
||||
return dec.decode
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type structDecoder struct {
|
||||
fieldOpts []decOpts
|
||||
fieldDecs []decoderFunc
|
||||
}
|
||||
|
||||
func (sd *structDecoder) decode(d *decodeState, v reflect.Value, opts decOpts) int {
|
||||
read := 0
|
||||
for i := range sd.fieldDecs {
|
||||
read += sd.fieldDecs[i](d, v.Elem().Field(i).Addr(), sd.fieldOpts[i])
|
||||
}
|
||||
return read
|
||||
}
|
||||
|
||||
func newStructDecoder(t reflect.Type) decoderFunc {
|
||||
n := t.NumField()
|
||||
sd := structDecoder{
|
||||
fieldOpts: make([]decOpts, n),
|
||||
fieldDecs: make([]decoderFunc, n),
|
||||
}
|
||||
|
||||
for i := 0; i < n; i += 1 {
|
||||
f := t.Field(i)
|
||||
|
||||
tag := f.Tag.Get("tls")
|
||||
tagOpts := parseTag(tag)
|
||||
|
||||
sd.fieldOpts[i] = decOpts{
|
||||
head: tagOpts["head"],
|
||||
max: tagOpts["max"],
|
||||
min: tagOpts["min"],
|
||||
varint: tagOpts[varintOption] > 0,
|
||||
}
|
||||
|
||||
sd.fieldDecs[i] = typeDecoder(f.Type)
|
||||
}
|
||||
|
||||
return sd.decode
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type pointerDecoder struct {
|
||||
base decoderFunc
|
||||
}
|
||||
|
||||
func (pd *pointerDecoder) decode(d *decodeState, v reflect.Value, opts decOpts) int {
|
||||
v.Elem().Set(reflect.New(v.Elem().Type().Elem()))
|
||||
return pd.base(d, v.Elem(), opts)
|
||||
}
|
||||
|
||||
func newPointerDecoder(t reflect.Type) decoderFunc {
|
||||
baseDecoder := typeDecoder(t.Elem())
|
||||
pd := pointerDecoder{base: baseDecoder}
|
||||
return pd.decode
|
||||
}
|
||||
276
vendor/github.com/bifurcation/mint/syntax/encode.go
generated
vendored
Normal file
276
vendor/github.com/bifurcation/mint/syntax/encode.go
generated
vendored
Normal file
@@ -0,0 +1,276 @@
|
||||
package syntax
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func Marshal(v interface{}) ([]byte, error) {
|
||||
e := &encodeState{}
|
||||
err := e.marshal(v, encOpts{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.Bytes(), nil
|
||||
}
|
||||
|
||||
// Marshaler is the interface implemented by types that
|
||||
// have a defined TLS encoding.
|
||||
type Marshaler interface {
|
||||
MarshalTLS() ([]byte, error)
|
||||
}
|
||||
|
||||
// These are the options that can be specified in the struct tag. Right now,
|
||||
// all of them apply to variable-length vectors and nothing else
|
||||
type encOpts struct {
|
||||
head uint // length of length in bytes
|
||||
min uint // minimum size in bytes
|
||||
max uint // maximum size in bytes
|
||||
varint bool // whether to encode as a varint
|
||||
}
|
||||
|
||||
type encodeState struct {
|
||||
bytes.Buffer
|
||||
}
|
||||
|
||||
func (e *encodeState) marshal(v interface{}, opts encOpts) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if _, ok := r.(runtime.Error); ok {
|
||||
panic(r)
|
||||
}
|
||||
if s, ok := r.(string); ok {
|
||||
panic(s)
|
||||
}
|
||||
err = r.(error)
|
||||
}
|
||||
}()
|
||||
e.reflectValue(reflect.ValueOf(v), opts)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *encodeState) reflectValue(v reflect.Value, opts encOpts) {
|
||||
valueEncoder(v)(e, v, opts)
|
||||
}
|
||||
|
||||
type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts)
|
||||
|
||||
func valueEncoder(v reflect.Value) encoderFunc {
|
||||
if !v.IsValid() {
|
||||
panic(fmt.Errorf("Cannot encode an invalid value"))
|
||||
}
|
||||
return typeEncoder(v.Type())
|
||||
}
|
||||
|
||||
func typeEncoder(t reflect.Type) encoderFunc {
|
||||
// Note: Omits the caching / wait-group things that encoding/json uses
|
||||
return newTypeEncoder(t)
|
||||
}
|
||||
|
||||
var (
|
||||
marshalerType = reflect.TypeOf(new(Marshaler)).Elem()
|
||||
)
|
||||
|
||||
func newTypeEncoder(t reflect.Type) encoderFunc {
|
||||
if t.Implements(marshalerType) {
|
||||
return marshalerEncoder
|
||||
}
|
||||
|
||||
switch t.Kind() {
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return uintEncoder
|
||||
case reflect.Array:
|
||||
return newArrayEncoder(t)
|
||||
case reflect.Slice:
|
||||
return newSliceEncoder(t)
|
||||
case reflect.Struct:
|
||||
return newStructEncoder(t)
|
||||
case reflect.Ptr:
|
||||
return newPointerEncoder(t)
|
||||
default:
|
||||
panic(fmt.Errorf("Unsupported type (%s)", t))
|
||||
}
|
||||
}
|
||||
|
||||
///// Specific encoders below
|
||||
|
||||
func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
panic(fmt.Errorf("Cannot encode nil pointer"))
|
||||
}
|
||||
|
||||
m, ok := v.Interface().(Marshaler)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("Non-Marshaler passed to marshalerEncoder"))
|
||||
}
|
||||
|
||||
b, err := m.MarshalTLS()
|
||||
if err == nil {
|
||||
_, err = e.Write(b)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
func uintEncoder(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
if opts.varint {
|
||||
varintEncoder(e, v, opts)
|
||||
return
|
||||
}
|
||||
|
||||
writeUint(e, v.Uint(), int(v.Type().Size()))
|
||||
}
|
||||
|
||||
func varintEncoder(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
writeVarint(e, v.Uint())
|
||||
}
|
||||
|
||||
func writeVarint(e *encodeState, u uint64) {
|
||||
if (u >> 62) > 0 {
|
||||
panic(fmt.Errorf("uint value is too big for varint"))
|
||||
}
|
||||
|
||||
var varintLen int
|
||||
for _, len := range []uint{1, 2, 4, 8} {
|
||||
if u < (uint64(1) << (8*len - 2)) {
|
||||
varintLen = int(len)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
twoBits := map[int]uint64{1: 0x00, 2: 0x01, 4: 0x02, 8: 0x03}[varintLen]
|
||||
shift := uint(8*varintLen - 2)
|
||||
writeUint(e, u|(twoBits<<shift), varintLen)
|
||||
}
|
||||
|
||||
func writeUint(e *encodeState, u uint64, len int) {
|
||||
data := make([]byte, len)
|
||||
for i := 0; i < len; i += 1 {
|
||||
data[i] = byte(u >> uint(8*(len-i-1)))
|
||||
}
|
||||
e.Write(data)
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type arrayEncoder struct {
|
||||
elemEnc encoderFunc
|
||||
}
|
||||
|
||||
func (ae *arrayEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
n := v.Len()
|
||||
for i := 0; i < n; i += 1 {
|
||||
ae.elemEnc(e, v.Index(i), opts)
|
||||
}
|
||||
}
|
||||
|
||||
func newArrayEncoder(t reflect.Type) encoderFunc {
|
||||
enc := &arrayEncoder{typeEncoder(t.Elem())}
|
||||
return enc.encode
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type sliceEncoder struct {
|
||||
ae *arrayEncoder
|
||||
}
|
||||
|
||||
func (se *sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
arrayState := &encodeState{}
|
||||
se.ae.encode(arrayState, v, opts)
|
||||
|
||||
n := uint(arrayState.Len())
|
||||
if opts.head == 0 {
|
||||
panic(fmt.Errorf("Cannot encode a slice without a header length"))
|
||||
}
|
||||
|
||||
if opts.max > 0 && n > opts.max {
|
||||
panic(fmt.Errorf("Encoded length more than max [%d > %d]", n, opts.max))
|
||||
}
|
||||
if n < opts.min {
|
||||
panic(fmt.Errorf("Encoded length less than min [%d < %d]", n, opts.min))
|
||||
}
|
||||
|
||||
switch opts.head {
|
||||
case headValueNoHead:
|
||||
// None.
|
||||
case headValueVarint:
|
||||
writeVarint(e, uint64(n))
|
||||
default:
|
||||
if n>>(8*opts.head) > 0 {
|
||||
panic(fmt.Errorf("Encoded length too long for header length [%d, %d]", n, opts.head))
|
||||
}
|
||||
|
||||
writeUint(e, uint64(n), int(opts.head))
|
||||
}
|
||||
|
||||
e.Write(arrayState.Bytes())
|
||||
}
|
||||
|
||||
func newSliceEncoder(t reflect.Type) encoderFunc {
|
||||
enc := &sliceEncoder{&arrayEncoder{typeEncoder(t.Elem())}}
|
||||
return enc.encode
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type structEncoder struct {
|
||||
fieldOpts []encOpts
|
||||
fieldEncs []encoderFunc
|
||||
}
|
||||
|
||||
func (se *structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
for i := range se.fieldEncs {
|
||||
se.fieldEncs[i](e, v.Field(i), se.fieldOpts[i])
|
||||
}
|
||||
}
|
||||
|
||||
func newStructEncoder(t reflect.Type) encoderFunc {
|
||||
n := t.NumField()
|
||||
se := structEncoder{
|
||||
fieldOpts: make([]encOpts, n),
|
||||
fieldEncs: make([]encoderFunc, n),
|
||||
}
|
||||
|
||||
for i := 0; i < n; i += 1 {
|
||||
f := t.Field(i)
|
||||
tag := f.Tag.Get("tls")
|
||||
tagOpts := parseTag(tag)
|
||||
|
||||
se.fieldOpts[i] = encOpts{
|
||||
head: tagOpts["head"],
|
||||
max: tagOpts["max"],
|
||||
min: tagOpts["min"],
|
||||
varint: tagOpts[varintOption] > 0,
|
||||
}
|
||||
se.fieldEncs[i] = typeEncoder(f.Type)
|
||||
}
|
||||
|
||||
return se.encode
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type pointerEncoder struct {
|
||||
base encoderFunc
|
||||
}
|
||||
|
||||
func (pe pointerEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
if v.IsNil() {
|
||||
panic(fmt.Errorf("Cannot marshal a struct containing a nil pointer"))
|
||||
}
|
||||
|
||||
pe.base(e, v.Elem(), opts)
|
||||
}
|
||||
|
||||
func newPointerEncoder(t reflect.Type) encoderFunc {
|
||||
baseEncoder := typeEncoder(t.Elem())
|
||||
pe := pointerEncoder{base: baseEncoder}
|
||||
return pe.encode
|
||||
}
|
||||
50
vendor/github.com/bifurcation/mint/syntax/tags.go
generated
vendored
Normal file
50
vendor/github.com/bifurcation/mint/syntax/tags.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
package syntax
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// `tls:"head=2,min=2,max=255,varint"`
|
||||
|
||||
type tagOptions map[string]uint
|
||||
|
||||
var (
|
||||
varintOption = "varint"
|
||||
|
||||
headOptionNone = "none"
|
||||
headOptionVarint = "varint"
|
||||
headValueNoHead = uint(255)
|
||||
headValueVarint = uint(254)
|
||||
)
|
||||
|
||||
// parseTag parses a struct field's "tls" tag as a comma-separated list of
|
||||
// name=value pairs, where the values MUST be unsigned integers, or in
|
||||
// the special case of head, "none" or "varint"
|
||||
func parseTag(tag string) tagOptions {
|
||||
opts := tagOptions{}
|
||||
for _, token := range strings.Split(tag, ",") {
|
||||
if token == varintOption {
|
||||
opts[varintOption] = 1
|
||||
continue
|
||||
}
|
||||
|
||||
parts := strings.Split(token, "=")
|
||||
if len(parts[0]) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(parts) == 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
if parts[0] == "head" && parts[1] == headOptionNone {
|
||||
opts[parts[0]] = headValueNoHead
|
||||
} else if parts[0] == "head" && parts[1] == headOptionVarint {
|
||||
opts[parts[0]] = headValueVarint
|
||||
} else if val, err := strconv.Atoi(parts[1]); err == nil && val >= 0 {
|
||||
opts[parts[0]] = uint(val)
|
||||
}
|
||||
}
|
||||
return opts
|
||||
}
|
||||
Reference in New Issue
Block a user