diff --git a/syntax/decode.go b/syntax/decode.go index 1735840..771ba32 100644 --- a/syntax/decode.go +++ b/syntax/decode.go @@ -32,6 +32,7 @@ type decOpts struct { min uint // minimum size in bytes max uint // maximum size in bytes varint bool // whether to decode as a varint + none bool // whether to decode at all } type decodeState struct { @@ -287,6 +288,10 @@ func newSliceDecoder(t reflect.Type) decoderFunc { ////////// +func noopDecoder(d *decodeState, v reflect.Value, opts decOpts) int { + return 0 +} + type structDecoder struct { fieldOpts []decOpts fieldDecs []decoderFunc @@ -318,6 +323,12 @@ func newStructDecoder(t reflect.Type) decoderFunc { max: tagOpts["max"], min: tagOpts["min"], varint: tagOpts[varintOption] > 0, + none: tagOpts[noneOption] > 0, + } + + if sd.fieldOpts[i].none { + sd.fieldDecs[i] = noopDecoder + continue } sd.fieldDecs[i] = typeDecoder(f.Type) diff --git a/syntax/decode_test.go b/syntax/decode_test.go index e1fc5d4..89629bb 100644 --- a/syntax/decode_test.go +++ b/syntax/decode_test.go @@ -20,6 +20,28 @@ func TestDecodeUnsupported(t *testing.T) { } } +func TestDecodeNone(t *testing.T) { + template := struct { + A uint16 + B uint16 `tls:"none"` + C uint16 + }{} + encoding := unhex("AAAACCCC") + + template.B = 0xBBBB + n, err := Unmarshal(encoding, &template) + if n != len(encoding) { + t.Fatalf("Failed to use all of the encoded value") + } + if err != nil { + t.Fatalf("Error in unmarshal: %v", err) + } + if template.B != 0xBBBB { + t.Fatalf("Overwrote value of unencoded field") + } + +} + func TestDecodeErrors(t *testing.T) { vector0x20 := append([]byte{0x20}, buffer(0x20)...) errorCases := map[string]struct { diff --git a/syntax/encode.go b/syntax/encode.go index 54fea59..b277289 100644 --- a/syntax/encode.go +++ b/syntax/encode.go @@ -29,6 +29,7 @@ type encOpts struct { min uint // minimum size in bytes max uint // maximum size in bytes varint bool // whether to encode as a varint + none bool // whether to encode at all } type encodeState struct { @@ -220,6 +221,8 @@ func newSliceEncoder(t reflect.Type) encoderFunc { ////////// +func noopEncoder(e *encodeState, v reflect.Value, opts encOpts) {} + type structEncoder struct { fieldOpts []encOpts fieldEncs []encoderFunc @@ -248,7 +251,14 @@ func newStructEncoder(t reflect.Type) encoderFunc { max: tagOpts["max"], min: tagOpts["min"], varint: tagOpts[varintOption] > 0, + none: tagOpts[noneOption] > 0, + } + + if se.fieldOpts[i].none { + se.fieldEncs[i] = noopEncoder + continue } + se.fieldEncs[i] = typeEncoder(f.Type) } diff --git a/syntax/success_test.go b/syntax/success_test.go index bb28f20..77adad8 100644 --- a/syntax/success_test.go +++ b/syntax/success_test.go @@ -174,6 +174,18 @@ func TestSuccessCases(t *testing.T) { value: struct{ V *uint16 }{V: &dummyUint16}, encoding: unhex("B0A0"), }, + "struct-none": { + value: struct { + A uint16 + B uint16 `tls:"none"` + C uint16 + }{ + A: 0xAAAA, + B: 0x0000, // must be zero value in order for tests to pass + C: 0xCCCC, + }, + encoding: unhex("AAAACCCC"), + }, // Marshaler "marshaler": { diff --git a/syntax/tags.go b/syntax/tags.go index e06f8ec..cdcaf0d 100644 --- a/syntax/tags.go +++ b/syntax/tags.go @@ -10,6 +10,7 @@ import ( type tagOptions map[string]uint var ( + noneOption = "none" varintOption = "varint" headOptionNone = "none" @@ -24,6 +25,11 @@ var ( func parseTag(tag string) tagOptions { opts := tagOptions{} for _, token := range strings.Split(tag, ",") { + if token == noneOption { + opts[noneOption] = 1 + continue + } + if token == varintOption { opts[varintOption] = 1 continue