Skip to content

Commit

Permalink
update docs and add float16 conv test
Browse files Browse the repository at this point in the history
  • Loading branch information
lucix-aws committed Feb 19, 2024
1 parent 7ed8c15 commit e61c9bb
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 25 deletions.
74 changes: 50 additions & 24 deletions encoding/cbor/cbor.go
Original file line number Diff line number Diff line change
@@ -1,34 +1,50 @@
// Package cbor implements partial encoding/decoding of concise binary object
// representation (CBOR) described in RFC 8949.
// representation (CBOR) described in [RFC 8949].
//
// This package implements a subset of the specification required to support
// the Smithy RPCv2-CBOR protocol and is NOT suitable for general application
// use.
// This package is intended for use only by the smithy client runtime. The
// exported API therein is not considered stable and is subject to breaking
// changes without notice. More specifically, this package implements a subset
// of the RFC 8949 specification required to support the Smithy RPCv2-CBOR
// protocol and is NOT suitable for general application use.
//
// As the encoding API operates strictly off of a constructed syntax tree, the
// length of each data item in a Value will always be known and the encoder
// will always generate definite-length encodings of container types (byte/text
// string, list, map).
// The following principal restrictions apply:
// - Map (major type 5) keys can only be strings.
// - Float16 (major type 7, 25) values can be read but not encoded. Any
// float16 encountered during decode is converted to float32.
// - Indefinite-length values can be read but not encoded. Since the encoding
// API operates strictly off of a constructed syntax tree, the length of each
// data item in a Value will always be known and the encoder will always
// generate definite-length variants.
//
// Conversely, the decoding API will handle both definite and indefinite
// variations of encoded containers.
// It is the responsibility of the caller to determine whether a decoded CBOR
// integral or floating-point Value is suitable for its target (e.g. whether
// the value of a CBOR Uint fits into a field modeled as a Smithy short).
//
// All CBOR tags (major type 6) are implicitly supported since the
// encoder/decoder does not attempt to interpret a tag's contents. It is the
// responsibility of the caller to both provide valid Tag values to encode and
// to assert that a decoded Tag's contents are valid for its tag ID (e.g.
// ensuring whether a Tag with ID 1, indicating an enclosed epoch timestamp,
// actually contains a valid integral or floating-point CBOR Value).
//
// [RFC 8949]: https://www.rfc-editor.org/rfc/rfc8949.html
package cbor

// Value describes a CBOR data item.
//
// The following types implement Value:
// - Uint
// - NegInt
// - Slice
// - String
// - List
// - Map
// - Tag
// - Bool
// - Nil
// - Undefined
// - Float32
// - Float64
// - [Uint]
// - [NegInt]
// - [Slice]
// - [String]
// - [List]
// - [Map]
// - [Tag]
// - [Bool]
// - [Nil]
// - [Undefined]
// - [Float32]
// - [Float64]
type Value interface {
len() int
encode(p []byte) int
Expand All @@ -49,10 +65,20 @@ var (
_ Value = Float64(0)
)

// Uint describes a CBOR uint (major type 0).
// Uint describes a CBOR uint (major type 0) in the range [0, 2^64-1].
type Uint uint64

// NegInt describes a CBOR negative int (major type 1).
// NegInt describes a CBOR negative int (major type 1) in the range [-2^64, -1].
//
// The "true negative" value of a type 1 is specified by RFC 8949 to be -1
// minus the encoded value. The encoder/decoder applies this bias
// automatically, e.g. the integral -100 is represented as NegInt(100), which
// will which encode to/from hex 3863 (major 1, minor 24, argument 99).
//
// This implicitly means that the lower bound of this type -2^64 is represented
// as the wraparound value NegInt(0). Deserializer implementations should take
// care to guard against this case when deriving a value for a signed integral
// type which was encoded as NegInt.
type NegInt uint64

// Slice describes a CBOR byte slice (major type 2).
Expand Down
2 changes: 1 addition & 1 deletion encoding/cbor/float16.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func splitf16(f uint16) (sign, exp, mantissa uint32) {
// float32 where the hidden bit is 1, e.g.
//
// f16: 0 00000 0001010000 = 0.000101 * 2^(-14), which is equal to
// f32: 0 00000000 00100000000000000000000 = 1.01 * 2^(-18)
// f32: 0 01101101 01000000000000000000000 = 1.01 * 2^(-18)
//
// this is achieved by shifting the mantissa to the right until the leading bit
// that == 1 reaches position 24, then the number of positions shifted over is
Expand Down
41 changes: 41 additions & 0 deletions encoding/cbor/float16_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cbor

import (
"testing"
)

func TestFloat16To32(t *testing.T) {
for name, c := range map[string]struct {
In uint16
Expect uint32
}{
"+infinity": {
0b0_11111_0000000000,
0b0_11111111_00000000000000000000000,
},
"-infinity": {
0b1_11111_0000000000,
0b1_11111111_00000000000000000000000,
},
"NaN": {
0b0_11111_0101010101,
0b0_11111111_01010101010000000000000,
},
"absolute zero": {0, 0},
"subnormal": {
0b0_00000_0001010000,
0b0_01101101_01000000000000000000000,
},
"normal": {
0b0_00001_0001010000,
0b0_0001110001_00010100000000000000000,
},
} {
t.Run(name, func(t *testing.T) {
if actual := float16to32(c.In); c.Expect != actual {
t.Errorf("%x != %x", c.Expect, actual)
}
})
}

}

0 comments on commit e61c9bb

Please sign in to comment.