-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #376 from fxamacker/feature/bytestring
Define ByteString type to support CBOR byte string as map keys and other uses. Go doesn't allow []byte as map key, so ByteString can be used to support data formats having CBOR map with byte string keys. Another use for ByteString is to encode invalid UTF-8 string as CBOR byte string.
- Loading branch information
Showing
5 changed files
with
467 additions
and
118 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// Copyright (c) Faye Amacker. All rights reserved. | ||
// Licensed under the MIT License. See LICENSE in the project root for license information. | ||
|
||
package cbor | ||
|
||
import ( | ||
"errors" | ||
) | ||
|
||
// ByteString represents CBOR byte string (major type 2). ByteString can be used | ||
// when using a Go []byte is not possible or convenient. For example, Go doesn't | ||
// allow []byte as map key, so ByteString can be used to support data formats | ||
// having CBOR map with byte string keys. ByteString can also be used to | ||
// encode invalid UTF-8 string as CBOR byte string. | ||
// See DecOption.MapKeyByteStringMode for more details. | ||
type ByteString string | ||
|
||
// Bytes returns bytes representing ByteString. | ||
func (bs ByteString) Bytes() []byte { | ||
return []byte(bs) | ||
} | ||
|
||
// MarshalCBOR encodes ByteString as CBOR byte string (major type 2). | ||
func (bs ByteString) MarshalCBOR() ([]byte, error) { | ||
e := getEncoderBuffer() | ||
defer putEncoderBuffer(e) | ||
|
||
// Encode length | ||
encodeHead(e, byte(cborTypeByteString), uint64(len(bs))) | ||
|
||
// Encode data | ||
buf := make([]byte, e.Len()+len(bs)) | ||
n := copy(buf, e.Bytes()) | ||
copy(buf[n:], bs) | ||
|
||
return buf, nil | ||
} | ||
|
||
// UnmarshalCBOR decodes CBOR byte string (major type 2) to ByteString. | ||
// Decoding CBOR null and CBOR undefined sets ByteString to be empty. | ||
func (bs *ByteString) UnmarshalCBOR(data []byte) error { | ||
if bs == nil { | ||
return errors.New("cbor.ByteString: UnmarshalCBOR on nil pointer") | ||
} | ||
|
||
// Decoding CBOR null and CBOR undefined to ByteString resets data. | ||
// This behavior is similar to decoding CBOR null and CBOR undefined to []byte. | ||
if len(data) == 1 && (data[0] == 0xf6 || data[0] == 0xf7) { | ||
*bs = "" | ||
return nil | ||
} | ||
|
||
d := decoder{data: data, dm: defaultDecMode} | ||
|
||
// Check if CBOR data type is byte string | ||
if typ := d.nextCBORType(); typ != cborTypeByteString { | ||
return &UnmarshalTypeError{CBORType: typ.String(), GoType: typeByteString.String()} | ||
} | ||
|
||
*bs = ByteString(d.parseByteString()) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// Copyright (c) Faye Amacker. All rights reserved. | ||
// Licensed under the MIT License. See LICENSE in the project root for license information. | ||
|
||
package cbor | ||
|
||
import "testing" | ||
|
||
func TestByteString(t *testing.T) { | ||
type s1 struct { | ||
A ByteString `cbor:"a"` | ||
} | ||
type s2 struct { | ||
A *ByteString `cbor:"a"` | ||
} | ||
type s3 struct { | ||
A ByteString `cbor:"a,omitempty"` | ||
} | ||
type s4 struct { | ||
A *ByteString `cbor:"a,omitempty"` | ||
} | ||
|
||
emptybs := ByteString("") | ||
bs := ByteString("\x01\x02\x03\x04") | ||
|
||
testCases := []roundTripTest{ | ||
{ | ||
name: "empty", | ||
obj: emptybs, | ||
wantCborData: hexDecode("40"), | ||
}, | ||
{ | ||
name: "not empty", | ||
obj: bs, | ||
wantCborData: hexDecode("4401020304"), | ||
}, | ||
{ | ||
name: "array", | ||
obj: []ByteString{bs}, | ||
wantCborData: hexDecode("814401020304"), | ||
}, | ||
{ | ||
name: "map with ByteString key", | ||
obj: map[ByteString]bool{bs: true}, | ||
wantCborData: hexDecode("a14401020304f5"), | ||
}, | ||
{ | ||
name: "empty ByteString field", | ||
obj: s1{}, | ||
wantCborData: hexDecode("a1616140"), | ||
}, | ||
{ | ||
name: "not empty ByteString field", | ||
obj: s1{A: bs}, | ||
wantCborData: hexDecode("a161614401020304"), | ||
}, | ||
{ | ||
name: "nil *ByteString field", | ||
obj: s2{}, | ||
wantCborData: hexDecode("a16161f6"), | ||
}, | ||
{ | ||
name: "empty *ByteString field", | ||
obj: s2{A: &emptybs}, | ||
wantCborData: hexDecode("a1616140"), | ||
}, | ||
{ | ||
name: "not empty *ByteString field", | ||
obj: s2{A: &bs}, | ||
wantCborData: hexDecode("a161614401020304"), | ||
}, | ||
{ | ||
name: "empty ByteString field with omitempty option", | ||
obj: s3{}, | ||
wantCborData: hexDecode("a0"), | ||
}, | ||
{ | ||
name: "not empty ByteString field with omitempty option", | ||
obj: s3{A: bs}, | ||
wantCborData: hexDecode("a161614401020304"), | ||
}, | ||
{ | ||
name: "nil *ByteString field with omitempty option", | ||
obj: s4{}, | ||
wantCborData: hexDecode("a0"), | ||
}, | ||
{ | ||
name: "empty *ByteString field with omitempty option", | ||
obj: s4{A: &emptybs}, | ||
wantCborData: hexDecode("a1616140"), | ||
}, | ||
{ | ||
name: "not empty *ByteString field with omitempty option", | ||
obj: s4{A: &bs}, | ||
wantCborData: hexDecode("a161614401020304"), | ||
}, | ||
} | ||
|
||
em, _ := EncOptions{}.EncMode() | ||
dm, _ := DecOptions{}.DecMode() | ||
testRoundTrip(t, testCases, em, dm) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.