status-go/vendor/github.com/russolsen/transit/value_decoder.go

277 lines
7.3 KiB
Go

// Copyright 2016 Russ Olsen. All Rights Reserved.
//
// This code is a Go port of the Java version created and maintained by Cognitect, therefore:
//
// Copyright 2014 Cognitect. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package transit
import (
"container/list"
"encoding/base64"
"github.com/pborman/uuid"
"github.com/shopspring/decimal"
"math"
"math/big"
"strconv"
"time"
)
// DecodeKeyword decodes ~: style keywords.
func DecodeKeyword(d Decoder, x interface{}) (interface{}, error) {
s := x.(string)
var result = Keyword(s)
return result, nil
}
// DecodeKeyword decodes ~$ style symbols.
func DecodeSymbol(d Decoder, x interface{}) (interface{}, error) {
s := x.(string)
var result = Symbol(s)
return result, nil
}
// DecodeIdentity returns the value unchanged.
func DecodeIdentity(d Decoder, x interface{}) (interface{}, error) {
return x, nil
}
// DecodeCMap decodes maps with composite keys.
func DecodeCMap(d Decoder, x interface{}) (interface{}, error) {
tagged := x.(TaggedValue)
if !IsGenericArray(tagged.Value) {
return nil, NewTransitError("Cmap contents are not an array.", tagged)
}
array := tagged.Value.([]interface{})
if (len(array) % 2) != 0 {
return nil, NewTransitError("Cmap contents must contain an even number of elements.", tagged)
}
var result = NewCMap()
l := len(array)
for i := 0; i < l; i += 2 {
key := array[i]
value := array[i+1]
result.Append(key, value)
}
return result, nil
}
// DecodeSet decodes a transit set into a transit.Set instance.
func DecodeSet(d Decoder, x interface{}) (interface{}, error) {
tagged := x.(TaggedValue)
if !IsGenericArray(tagged.Value) {
return nil, NewTransitError("Set contents are not an array.", tagged)
}
values := (tagged.Value).([]interface{})
result := NewSet(values)
return result, nil
}
// DecodeList decodes a transit list into a Go list.
func DecodeList(d Decoder, x interface{}) (interface{}, error) {
tagged := x.(TaggedValue)
if !IsGenericArray(tagged.Value) {
return nil, NewTransitError("List contents are not an array.", tagged)
}
values := (tagged.Value).([]interface{})
result := list.New()
for _, item := range values {
result.PushBack(item)
}
return result, nil
}
// DecodeQuote decodes a transit quoted value by simply returning the value.
func DecodeQuote(d Decoder, x interface{}) (interface{}, error) {
tagged := x.(TaggedValue)
return tagged.Value, nil
}
// DecodeRFC3339 decodes a time value into a Go time instance.
// TBD not 100% this covers all possible values.
func DecodeRFC3339(d Decoder, x interface{}) (interface{}, error) {
s := x.(string)
var result, err = time.Parse(time.RFC3339Nano, s)
return result, err
}
// DecodeTime decodes a time value represended as millis since 1970.
func DecodeTime(d Decoder, x interface{}) (interface{}, error) {
s := x.(string)
var millis, _ = strconv.ParseInt(s, 10, 64)
seconds := millis / 1000
remainder_millis := millis - (seconds * 1000)
nanos := remainder_millis * 1000000
result := time.Unix(seconds, nanos).UTC()
return result, nil
}
// DecodeBoolean decodes a transit boolean into a Go bool.
func DecodeBoolean(d Decoder, x interface{}) (interface{}, error) {
s := x.(string)
if s == "t" {
return true, nil
} else if s == "f" {
return false, nil
} else {
return nil, &TransitError{Message: "Unknown boolean value."}
}
}
// DecodeBigInteger decodes a transit big integer into a Go big.Int.
func DecodeBigInteger(d Decoder, x interface{}) (interface{}, error) {
s := x.(string)
result := new(big.Int)
_, good := result.SetString(s, 10)
if !good {
return nil, &TransitError{Message: "Unable to part big integer: " + s}
}
return result, nil
}
// DecodeInteger decodes a transit integer into a plain Go int64
func DecodeInteger(d Decoder, x interface{}) (interface{}, error) {
s := x.(string)
result, err := strconv.ParseInt(s, 10, 64)
return result, err
}
func newRational(a, b *big.Int) *big.Rat {
var r = big.NewRat(1, 1)
r.SetFrac(a, b)
return r
}
func toBigInt(x interface{}) (*big.Int, error) {
switch v := x.(type) {
default:
return nil, NewTransitError("Not a numeric value", v)
case *big.Int:
return v, nil
case int64:
return big.NewInt(v), nil
}
}
// DecodeRatio decodes a transit ratio into a Go big.Rat.
func DecodeRatio(d Decoder, x interface{}) (interface{}, error) {
tagged := x.(TaggedValue)
if !IsGenericArray(tagged.Value) {
return nil, NewTransitError("Ratio contents are not an array.", tagged)
}
values := (tagged.Value).([]interface{})
if len(values) != 2 {
return nil, NewTransitError("Ratio contents does not contain 2 elements.", tagged)
}
a, err := toBigInt(values[0])
if err != nil {
return nil, err
}
b, err := toBigInt(values[1])
if err != nil {
return nil, err
}
result := newRational(a, b)
return *result, nil
}
// DecodeRune decodes a transit char.
func DecodeRune(d Decoder, x interface{}) (interface{}, error) {
s := x.(string)
return rune(s[0]), nil
}
// DecodeFloat decodes the value into a float.
func DecodeFloat(d Decoder, x interface{}) (interface{}, error) {
s := x.(string)
return strconv.ParseFloat(s, 64)
}
// DecodeDecimal decodes a transit big decimal into decimal.Decimal.
func DecodeDecimal(d Decoder, x interface{}) (interface{}, error) {
s := x.(string)
return decimal.NewFromString((s))
}
// DecodeRatio decodes a transit null/nil.
func DecodeNil(d Decoder, x interface{}) (interface{}, error) {
return nil, nil
}
// DecodeRatio decodes a transit base64 encoded byte array into a
// Go byte array.
func DecodeByte(d Decoder, x interface{}) (interface{}, error) {
s := x.(string)
return base64.StdEncoding.DecodeString(s)
}
// DecodeLink decodes a transit link into an instance of Link.
func DecodeLink(d Decoder, x interface{}) (interface{}, error) {
tv := x.(TaggedValue)
v := tv.Value.(map[interface{}]interface{})
l := NewLink()
l.Href = v["href"].(*TUri)
l.Name = v["name"].(string)
l.Rel = v["rel"].(string)
l.Prompt = v["prompt"].(string)
l.Render = v["render"].(string)
return l, nil
}
// DecodeURI decodes a transit URI into an instance of TUri.
func DecodeURI(d Decoder, x interface{}) (interface{}, error) {
s := x.(string)
return NewTUri(s), nil
}
// DecodeUUID decodes a transit UUID into an instance of net/UUID
func DecodeUUID(d Decoder, x interface{}) (interface{}, error) {
s := x.(string)
var u = uuid.Parse(s)
if u == nil {
return nil, &TransitError{Message: "Unable to parse uuid [" + s + "]"}
}
return u, nil
}
// DecodeSpecialNumber decodes NaN, INF and -INF into their Go equivalents.
func DecodeSpecialNumber(d Decoder, x interface{}) (interface{}, error) {
tag := x.(string)
if tag == "NaN" {
return math.NaN(), nil
} else if tag == "INF" {
return math.Inf(1), nil
} else if tag == "-INF" {
return math.Inf(-1), nil
} else {
return nil, &TransitError{Message: "Bad special number:"}
}
}