mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 15:09:42 +00:00
Types: Switch convert.StringToFloat64 to types.Number (#1415)
* Types: Add Number type * Types: Switch StringToFloat64 for Number This change mostly just renames the type. convert package and StringToFloat64 represent actions, not types, and make it misleading to use outside of the API context, especially when using it for a Float64ToString operation. * Common: Remove StringToFloat64 Replaced by types.Number * fixup! Types: Switch StringToFloat64 for Number Second pass at Okx * Spellcheck: Fix whitespace handling for okx line
This commit is contained in:
@@ -1,9 +1,7 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
@@ -13,10 +11,6 @@ import (
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
const jsonStringIdent = `"` // immutable byte sequence
|
||||
|
||||
var errUnhandledType = errors.New("unhandled type")
|
||||
|
||||
// FloatFromString format
|
||||
func FloatFromString(raw interface{}) (float64, error) {
|
||||
str, ok := raw.(string)
|
||||
@@ -195,55 +189,6 @@ func InterfaceToStringOrZeroValue(r interface{}) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// StringToFloat64 is a float64 that unmarshals from a string. This is useful
|
||||
// for APIs that return numbers as strings and return an empty string instead of
|
||||
// 0.
|
||||
type StringToFloat64 float64
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
// This implementation is slightly more performant than calling json.Unmarshal
|
||||
// again.
|
||||
func (f *StringToFloat64) UnmarshalJSON(data []byte) error {
|
||||
if !bytes.HasPrefix(data, []byte(jsonStringIdent)) {
|
||||
return fmt.Errorf("%w: %s", errUnhandledType, string(data))
|
||||
}
|
||||
|
||||
data = data[1 : len(data)-1] // Remove quotes
|
||||
if len(data) == 0 {
|
||||
*f = StringToFloat64(0)
|
||||
return nil
|
||||
}
|
||||
|
||||
val, err := strconv.ParseFloat(string(data), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*f = StringToFloat64(val)
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (f StringToFloat64) MarshalJSON() ([]byte, error) {
|
||||
if f == 0 {
|
||||
return []byte(jsonStringIdent + jsonStringIdent), nil
|
||||
}
|
||||
val := strconv.FormatFloat(float64(f), 'f', -1, 64)
|
||||
return []byte(jsonStringIdent + val + jsonStringIdent), nil
|
||||
}
|
||||
|
||||
// Float64 returns the float64 value of the FloatString.
|
||||
func (f StringToFloat64) Float64() float64 {
|
||||
return float64(f)
|
||||
}
|
||||
|
||||
// Decimal returns the decimal value of the FloatString
|
||||
// Warning: this does not handle big numbers as the underlying
|
||||
// is still a float
|
||||
func (f StringToFloat64) Decimal() decimal.Decimal {
|
||||
return decimal.NewFromFloat(float64(f))
|
||||
}
|
||||
|
||||
// ExchangeTime provides timestamp to time conversion method.
|
||||
type ExchangeTime time.Time
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package convert
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -318,89 +317,6 @@ func TestInterfaceToStringOrZeroValue(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringToFloat64(t *testing.T) {
|
||||
t.Parallel()
|
||||
resp := struct {
|
||||
Data StringToFloat64 `json:"data"`
|
||||
}{}
|
||||
|
||||
err := json.Unmarshal([]byte(`{"data":"0.00000001"}`), &resp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if resp.Data.Float64() != 1e-8 {
|
||||
t.Fatalf("expected 1e-8, got %v", resp.Data.Float64())
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(`{"data":""}`), &resp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(`{"data":1337.37}`), &resp)
|
||||
if !errors.Is(err, errUnhandledType) {
|
||||
t.Fatalf("received %v but expected %v", err, errUnhandledType)
|
||||
}
|
||||
|
||||
// Demonstrates that a suffix check is not needed.
|
||||
err = json.Unmarshal([]byte(`{"data":"1337.37}`), &resp)
|
||||
if err == nil {
|
||||
t.Fatal("error cannot be nil")
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(`{"data":"MEOW"}`), &resp)
|
||||
if err == nil {
|
||||
t.Fatal("error cannot be nil")
|
||||
}
|
||||
|
||||
data, err := json.Marshal(StringToFloat64(0))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if string(data) != `""` {
|
||||
t.Fatalf("expected empty string, got %v", string(data))
|
||||
}
|
||||
|
||||
data, err = json.Marshal(StringToFloat64(1337.1337))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if string(data) != `"1337.1337"` {
|
||||
t.Fatalf("expected \"1337.1337\" string, got %v", string(data))
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringToFloat64Decimal(t *testing.T) {
|
||||
t.Parallel()
|
||||
resp := struct {
|
||||
Data StringToFloat64 `json:"data"`
|
||||
}{}
|
||||
err := json.Unmarshal([]byte(`{"data":"0.00000001"}`), &resp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !resp.Data.Decimal().Equal(decimal.NewFromFloat(0.00000001)) {
|
||||
t.Errorf("received '%v' expected '%v'", resp.Data.Decimal(), 0.00000001)
|
||||
}
|
||||
}
|
||||
|
||||
// 2677173 428.9 ns/op 240 B/op 5 allocs/op
|
||||
func BenchmarkStringToFloat64(b *testing.B) {
|
||||
resp := struct {
|
||||
Data StringToFloat64 `json:"data"`
|
||||
}{}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := json.Unmarshal([]byte(`{"data":"0.00000001"}`), &resp)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExchangeTimeUnmarshalJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
unmarshaledResult := &struct {
|
||||
|
||||
Reference in New Issue
Block a user