-
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: decoder on component expansion (#66)
- Loading branch information
Showing
11 changed files
with
340 additions
and
221 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
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
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
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,78 @@ | ||
package decoder | ||
|
||
import ( | ||
"github.com/muktihari/fit/profile/basetype" | ||
) | ||
|
||
const ( | ||
bit = 8 | ||
maxBit = 32 | ||
size = maxBit / bit | ||
) | ||
|
||
// bitsFromValue convert value into 32-bits unsigned integer. | ||
// | ||
// Profile.xlsx (on Bits header's comment) says: Current implementation only supports Bits value of max 32. | ||
func bitsFromValue(value any) (bits uint32, ok bool) { | ||
switch val := value.(type) { | ||
case int8: | ||
return uint32(val), true | ||
case uint8: | ||
return uint32(val), true | ||
case int16: | ||
return uint32(val), true | ||
case uint16: | ||
return uint32(val), true | ||
case int32: | ||
return uint32(val), true | ||
case uint32: | ||
return uint32(val), true | ||
case int64: | ||
return uint32(val), true | ||
case uint64: | ||
return uint32(val), true | ||
case float32: | ||
return uint32(val), true | ||
case float64: | ||
return uint32(val), true | ||
case []byte: | ||
if len(val) > size { | ||
return 0, false | ||
} | ||
for i := range val { | ||
if val[i] == basetype.ByteInvalid { // all values must be valid | ||
return 0, false | ||
} | ||
bits |= uint32(val[i]) << (i * bit) // little-endian | ||
} | ||
return bits, true | ||
} | ||
return 0, false | ||
} | ||
|
||
// valueFromBits cast back bits into it's original value. | ||
func valueFromBits(bits uint32, baseType basetype.BaseType) any { | ||
switch baseType { | ||
case basetype.Sint8: | ||
return int8(bits) | ||
case basetype.Uint8, basetype.Uint8z: | ||
return uint8(bits) | ||
case basetype.Sint16: | ||
return int16(bits) | ||
case basetype.Uint16, basetype.Uint16z: | ||
return uint16(bits) | ||
case basetype.Sint32: | ||
return int32(bits) | ||
case basetype.Uint32, basetype.Uint32z: | ||
return uint32(bits) | ||
case basetype.Float32: | ||
return float32(bits) | ||
case basetype.Float64: | ||
return float64(bits) | ||
case basetype.Sint64: | ||
return int64(bits) | ||
case basetype.Uint64, basetype.Uint64z: | ||
return uint64(bits) | ||
} | ||
return baseType.Invalid() | ||
} |
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,73 @@ | ||
package decoder | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/muktihari/fit/profile/basetype" | ||
) | ||
|
||
func TestBitsFromValue(t *testing.T) { | ||
tt := []struct { | ||
value any | ||
expected uint32 | ||
ok bool | ||
}{ | ||
{value: int8(10), expected: 10, ok: true}, | ||
{value: uint8(10), expected: 10, ok: true}, | ||
{value: int16(10), expected: 10, ok: true}, | ||
{value: uint16(10), expected: 10, ok: true}, | ||
{value: int32(10), expected: 10, ok: true}, | ||
{value: uint32(10), expected: 10, ok: true}, | ||
{value: int64(10), expected: 10, ok: true}, | ||
{value: uint64(10), expected: 10, ok: true}, | ||
{value: float32(10), expected: 10, ok: true}, | ||
{value: float64(10), expected: 10, ok: true}, | ||
{value: []byte{1, 1, 1}, expected: 1<<0 | 1<<8 | 1<<16, ok: true}, | ||
{value: []byte{1, 255, 1}, expected: 0, ok: false}, | ||
{value: make([]byte, 33), expected: 0, ok: false}, | ||
{value: "string value", expected: 0, ok: false}, | ||
} | ||
|
||
for _, tc := range tt { | ||
t.Run(fmt.Sprintf("%v (%T)", tc.value, tc.value), func(t *testing.T) { | ||
res, ok := bitsFromValue(tc.value) | ||
if ok != tc.ok { | ||
t.Fatalf("expected ok: %t, got: %t", tc.ok, ok) | ||
} | ||
if res != tc.expected { | ||
t.Fatalf("expected: %d, got: %d", tc.expected, res) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestValueFromBits(t *testing.T) { | ||
tt := []struct { | ||
sbits uint32 | ||
basetype basetype.BaseType | ||
value any | ||
ok bool | ||
}{ | ||
{sbits: 10, basetype: basetype.Sint8, value: int8(10), ok: true}, | ||
{sbits: 10, basetype: basetype.Uint8, value: uint8(10), ok: true}, | ||
{sbits: 10, basetype: basetype.Sint16, value: int16(10), ok: true}, | ||
{sbits: 10, basetype: basetype.Uint16, value: uint16(10), ok: true}, | ||
{sbits: 10, basetype: basetype.Sint32, value: int32(10), ok: true}, | ||
{sbits: 10, basetype: basetype.Uint32, value: uint32(10), ok: true}, | ||
{sbits: 10, basetype: basetype.Sint64, value: int64(10), ok: true}, | ||
{sbits: 10, basetype: basetype.Uint64, value: uint64(10), ok: true}, | ||
{sbits: 10, basetype: basetype.Float32, value: float32(10), ok: true}, | ||
{sbits: 10, basetype: basetype.Float64, value: float64(10), ok: true}, | ||
{sbits: 10, basetype: basetype.String, value: basetype.StringInvalid, ok: false}, | ||
} | ||
|
||
for _, tc := range tt { | ||
t.Run(fmt.Sprintf("%s %v (%T)", tc.basetype, tc.value, tc.value), func(t *testing.T) { | ||
res := valueFromBits(tc.sbits, tc.basetype) | ||
if res != tc.value { | ||
t.Fatalf("expected: %v, got: %v", tc.value, res) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.