Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor NilContainersMode option #377

Merged
merged 1 commit into from
Dec 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,23 +210,6 @@ func (m IndefLengthMode) valid() bool {
return m < maxIndefLengthMode
}

// NilContainersMode specifies how to encode []Type(nil) and map[Key]Type(nil).
type NilContainersMode int

const (
// NullForNil enforces null for []Type(nil)/map[Key]Type(nil).
NullForNil NilContainersMode = iota

// EmptyForNil enforces empty map/list for []Type(nil)/map[Key]Type(nil).
EmptyForNil

maxNilContainersMode
)

func (m NilContainersMode) valid() bool {
return m < maxNilContainersMode
}

// TagsMode specifies whether to allow CBOR tags.
type TagsMode int

Expand Down
27 changes: 23 additions & 4 deletions encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,25 @@ func (bim BigIntConvertMode) valid() bool {
return bim < maxBigIntConvert
}

// NilContainersMode specifies how to encode nil slices and maps.
type NilContainersMode int

const (
// NilContainerAsNull encodes nil slices and maps as CBOR null.
// This is the default.
NilContainerAsNull NilContainersMode = iota

// NilContainerAsEmpty encodes nil slices and maps as
// empty container (CBOR bytestring, array, or map).
NilContainerAsEmpty

maxNilContainersMode
)

func (m NilContainersMode) valid() bool {
return m < maxNilContainersMode
}

// EncOptions specifies encoding options.
type EncOptions struct {
// Sort specifies sorting order.
Expand Down Expand Up @@ -292,7 +311,7 @@ type EncOptions struct {
// IndefLength specifies whether to allow indefinite length CBOR items.
IndefLength IndefLengthMode

// NilContainers specifies how to encode map[Key]Type(nil)/[]Type(nil)
// NilContainers specifies how to encode nil slices and maps.
NilContainers NilContainersMode

// TagsMd specifies whether to allow CBOR tags (major type 6).
Expand Down Expand Up @@ -795,7 +814,7 @@ func encodeFloat64(e *encoderBuffer, f64 float64) error {

func encodeByteString(e *encoderBuffer, em *encMode, v reflect.Value) error {
vk := v.Kind()
if vk == reflect.Slice && v.IsNil() && em.nilContainers == NullForNil {
if vk == reflect.Slice && v.IsNil() && em.nilContainers == NilContainerAsNull {
e.Write(cborNil)
return nil
}
Expand Down Expand Up @@ -832,7 +851,7 @@ type arrayEncodeFunc struct {
}

func (ae arrayEncodeFunc) encode(e *encoderBuffer, em *encMode, v reflect.Value) error {
if v.Kind() == reflect.Slice && v.IsNil() && em.nilContainers == NullForNil {
if v.Kind() == reflect.Slice && v.IsNil() && em.nilContainers == NilContainerAsNull {
e.Write(cborNil)
return nil
}
Expand All @@ -857,7 +876,7 @@ type mapEncodeFunc struct {
}

func (me mapEncodeFunc) encode(e *encoderBuffer, em *encMode, v reflect.Value) error {
if v.IsNil() && em.nilContainers == NullForNil {
if v.IsNil() && em.nilContainers == NilContainerAsNull {
e.Write(cborNil)
return nil
}
Expand Down
19 changes: 10 additions & 9 deletions encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2858,22 +2858,23 @@ func TestInvalidInfConvert(t *testing.T) {
}

func TestNilContainers(t *testing.T) {
nilContainersNull := EncOptions{NilContainers: NullForNil}
nilContainersEmpty := EncOptions{NilContainers: EmptyForNil}
nilContainersNull := EncOptions{NilContainers: NilContainerAsNull}
nilContainersEmpty := EncOptions{NilContainers: NilContainerAsEmpty}

testCases := []struct {
name string
v interface{}
opts EncOptions
wantCborData []byte
}{
{"map(nil) as null", map[string]string(nil), nilContainersNull, hexDecode("f6")},
{"map(nil) as empty map", map[string]string(nil), nilContainersEmpty, hexDecode("a0")},
{"map(nil) as CBOR null", map[string]string(nil), nilContainersNull, hexDecode("f6")},
{"map(nil) as CBOR empty map", map[string]string(nil), nilContainersEmpty, hexDecode("a0")},

{"slice(nil) as null", []int(nil), nilContainersNull, hexDecode("f6")},
{"slice(nil) as empty list", []int(nil), nilContainersEmpty, hexDecode("80")},
{"slice(nil) as CBOR null", []int(nil), nilContainersNull, hexDecode("f6")},
{"slice(nil) as CBOR empty array", []int(nil), nilContainersEmpty, hexDecode("80")},

{"[]byte(nil) as null", []byte(nil), nilContainersNull, hexDecode("f6")},
{"[]byte(nil) as empty bytestring", []byte(nil), nilContainersEmpty, hexDecode("40")},
{"[]byte(nil) as CBOR null", []byte(nil), nilContainersNull, hexDecode("f6")},
{"[]byte(nil) as CBOR empty bytestring", []byte(nil), nilContainersEmpty, hexDecode("40")},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
Expand Down Expand Up @@ -3355,7 +3356,7 @@ func TestEncOptions(t *testing.T) {
Time: TimeRFC3339Nano,
TimeTag: EncTagRequired,
IndefLength: IndefLengthForbidden,
NilContainers: NullForNil,
NilContainers: NilContainerAsNull,
TagsMd: TagsAllowed,
}
em, err := opts1.EncMode()
Expand Down