Skip to content

Commit

Permalink
fix: properly support negative numerator for CBOR rational numbers (#793
Browse files Browse the repository at this point in the history
)
  • Loading branch information
agaffney authored Nov 16, 2024
1 parent 68d9395 commit 128b731
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 10 deletions.
49 changes: 39 additions & 10 deletions cbor/tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package cbor

import (
"fmt"
"math/big"
"reflect"

Expand Down Expand Up @@ -93,29 +94,57 @@ type Rat struct {
}

func (r *Rat) UnmarshalCBOR(cborData []byte) error {
tmpRat := []uint64{}
tmpRat := []any{}
if _, err := Decode(cborData, &tmpRat); err != nil {
return err
}
// Convert numerator and denominator to big.Int
// It's necessary to do this to support num/denom larger than int64 (up to uint64)
// Convert numerator to big.Int
tmpNum := new(big.Int)
tmpNum.SetUint64(tmpRat[0])
switch v := tmpRat[0].(type) {
case int64:
tmpNum.SetInt64(v)
case uint64:
tmpNum.SetUint64(v)
default:
return fmt.Errorf("unsupported numerator type for cbor.Rat: %T", v)
}
// Convert denominator to big.Int
tmpDenom := new(big.Int)
tmpDenom.SetUint64(tmpRat[1])
switch v := tmpRat[1].(type) {
case int64:
tmpDenom.SetInt64(v)
case uint64:
tmpDenom.SetUint64(v)
default:
return fmt.Errorf("unsupported demoninator type for cbor.Rat: %T", v)
}
// Create new big.Rat with num/denom set to big.Int values above
r.Rat = new(big.Rat)
r.Rat.SetFrac(tmpNum, tmpDenom)
return nil
}

func (r *Rat) MarshalCBOR() ([]byte, error) {
tmpContent := make([]any, 2)
// Numerator
if r.Num().IsUint64() {
tmpContent[0] = r.Num().Uint64()
} else if r.Num().IsInt64() {
tmpContent[0] = r.Num().Int64()
} else {
return nil, fmt.Errorf("numerator cannot be represented at int64/uint64")
}
// Denominator
if r.Denom().IsUint64() {
tmpContent[1] = r.Denom().Uint64()
} else if r.Denom().IsInt64() {
tmpContent[1] = r.Denom().Int64()
} else {
return nil, fmt.Errorf("numerator cannot be represented at int64/uint64")
}
tmpData := _cbor.Tag{
Number: CborTagRational,
Content: []uint64{
r.Num().Uint64(),
r.Denom().Uint64(),
},
Number: CborTagRational,
Content: tmpContent,
}
return Encode(&tmpData)
}
Expand Down
8 changes: 8 additions & 0 deletions cbor/tags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ var tagsTestDefs = []struct {
},
),
},
// 30([9223372036854775809, 10000000000000000000])
{
cborHex: "d81e821b80000000000000011b8ac7230489e80000",
object: cbor.Rat{
Expand All @@ -63,6 +64,13 @@ var tagsTestDefs = []struct {
),
},
},
// 30([-1, 2])
{
cborHex: "d81e822002",
object: cbor.Rat{
Rat: big.NewRat(-1, 2),
},
},
}

func TestTagsDecode(t *testing.T) {
Expand Down

0 comments on commit 128b731

Please sign in to comment.