mirror of
https://github.com/status-im/nim-rlp.git
synced 2025-02-16 16:06:38 +00:00
Add support for float64
This commit is contained in:
parent
def016260a
commit
2b28b1a236
28
rlp.nim
28
rlp.nim
@ -176,10 +176,10 @@ proc isInt*(self: Rlp): bool =
|
||||
return bytes[offset] != 0
|
||||
return false
|
||||
|
||||
template maxBytes*(o: typedesc[Ordinal | uint64 | uint]): int = sizeof(o)
|
||||
template maxBytes*(o: type[Ordinal | uint64 | uint]): int = sizeof(o)
|
||||
|
||||
proc toInt*(self: Rlp, IntType: typedesc): IntType =
|
||||
# XXX: work-around a Nim issue with typedesc parameters
|
||||
proc toInt*(self: Rlp, IntType: type): IntType =
|
||||
# XXX: work-around a Nim issue with type parameters
|
||||
type OutputType = IntType
|
||||
mixin maxBytes, to
|
||||
|
||||
@ -289,14 +289,22 @@ proc readImpl(rlp: var Rlp, T: type Integer): Integer =
|
||||
result = rlp.toInt(T)
|
||||
rlp.skipElem
|
||||
|
||||
proc readImpl(rlp: var Rlp, T: typedesc[enum]): T =
|
||||
proc readImpl(rlp: var Rlp, T: type[enum]): T =
|
||||
result = type(result)(rlp.toInt(int))
|
||||
rlp.skipElem
|
||||
|
||||
proc readImpl(rlp: var Rlp, T: typedesc[bool]): T =
|
||||
proc readImpl(rlp: var Rlp, T: type bool): T =
|
||||
result = rlp.toInt(int) != 0
|
||||
rlp.skipElem
|
||||
|
||||
proc readImpl(rlp: var Rlp, T: type float64): T =
|
||||
# This is not covered in the RLP spec, but Geth uses Go's
|
||||
# `math.Float64bits`, which is defined here:
|
||||
# https://github.com/gopherjs/gopherjs/blob/master/compiler/natives/src/math/math.go
|
||||
let uint64bits = rlp.toInt(uint64)
|
||||
var uint32parts = [uint32(uint64bits), uint32(uint64bits shr 32)]
|
||||
return cast[ptr float64](unsafeAddr uint32parts)[]
|
||||
|
||||
proc readImpl[R, E](rlp: var Rlp, T: type array[R, E]): T =
|
||||
mixin read
|
||||
|
||||
@ -345,7 +353,7 @@ proc readImpl[E](rlp: var Rlp, T: type seq[E]): T =
|
||||
proc readImpl[E](rlp: var Rlp, T: type openarray[E]): seq[E] =
|
||||
result = readImpl(rlp, seq[E])
|
||||
|
||||
proc readImpl(rlp: var Rlp, T: typedesc[object|tuple],
|
||||
proc readImpl(rlp: var Rlp, T: type[object|tuple],
|
||||
wrappedInList = wrapObjectsInList): T =
|
||||
mixin enumerateRlpFields, read
|
||||
|
||||
@ -380,7 +388,7 @@ proc toNodes*(self: var Rlp): RlpNode =
|
||||
|
||||
# We define a single `read` template with a pretty low specifity
|
||||
# score in order to facilitate easier overloading with user types:
|
||||
template read*(rlp: var Rlp, T: typedesc): auto =
|
||||
template read*(rlp: var Rlp, T: type): auto =
|
||||
readImpl(rlp, T)
|
||||
|
||||
proc decode*(bytes: openarray[byte]): RlpNode =
|
||||
@ -389,16 +397,16 @@ proc decode*(bytes: openarray[byte]): RlpNode =
|
||||
rlp = rlpFromBytes(bytesCopy.toRange())
|
||||
return rlp.toNodes
|
||||
|
||||
template decode*(bytes: BytesRange, T: typedesc): untyped =
|
||||
template decode*(bytes: BytesRange, T: type): untyped =
|
||||
mixin read
|
||||
var rlp = rlpFromBytes(bytes)
|
||||
rlp.read(T)
|
||||
|
||||
template decode*(bytes: openarray[byte], T: typedesc): T =
|
||||
template decode*(bytes: openarray[byte], T: type): T =
|
||||
var bytesCopy = @bytes
|
||||
decode(bytesCopy.toRange, T)
|
||||
|
||||
template decode*(bytes: seq[byte], T: typedesc): untyped =
|
||||
template decode*(bytes: seq[byte], T: type): untyped =
|
||||
decode(bytes.toRange, T)
|
||||
|
||||
proc append*(writer: var RlpWriter; rlp: Rlp) =
|
||||
|
@ -185,6 +185,14 @@ proc appendInt(self; i: Integer) =
|
||||
|
||||
self.maybeClosePendingLists()
|
||||
|
||||
proc appendFloat(self; data: float64) =
|
||||
# This is not covered in the RLP spec, but Geth uses Go's
|
||||
# `math.Float64bits`, which is defined here:
|
||||
# https://github.com/gopherjs/gopherjs/blob/master/compiler/natives/src/math/math.go
|
||||
let uintWords = cast[ptr UncheckedArray[uint32]](unsafeAddr data)
|
||||
let uint64bits = (uint64(uintWords[1]) shl 32) or uint64(uintWords[0])
|
||||
self.appendInt(uint64bits)
|
||||
|
||||
template appendImpl(self; i: Integer) =
|
||||
appendInt(self, i)
|
||||
|
||||
@ -238,7 +246,14 @@ proc appendImpl(self; data: tuple, wrapInList = wrapObjectsInList) {.inline.} =
|
||||
|
||||
# We define a single `append` template with a pretty low specifity
|
||||
# score in order to facilitate easier overloading with user types:
|
||||
template append*[T](self; data: T) = appendImpl(self, data)
|
||||
template append*[T](self; data: T) =
|
||||
when data is float64:
|
||||
# XXX: This works around an overloading bug.
|
||||
# Apparently, integer literals will be converted to `float64`
|
||||
# values with higher precedence than the generic match to Integer
|
||||
appendFloat(self, data)
|
||||
else:
|
||||
appendImpl(self, data)
|
||||
|
||||
proc initRlpList*(listSize: int): RlpWriter =
|
||||
result = initRlpWriter()
|
||||
|
@ -1,5 +1,5 @@
|
||||
import
|
||||
unittest, strutils,
|
||||
math, unittest, strutils,
|
||||
rlp, util/json_testing
|
||||
|
||||
proc q(s: string): string = "\"" & s & "\""
|
||||
@ -172,3 +172,21 @@ test "empty byte arrays":
|
||||
rlp = rlpFromBytes rlp.encode("").toRange
|
||||
b = rlp.toBytes
|
||||
check $b == "R[]"
|
||||
|
||||
test "encode/decode floats":
|
||||
for f in [high(float64), low(float64), 0.1, 122.23,
|
||||
103487315.128934,
|
||||
1943935743563457201.391754032785692,
|
||||
0, -0,
|
||||
Inf, NegInf, NaN]:
|
||||
|
||||
template isNaN(n): bool =
|
||||
classify(n) == fcNaN
|
||||
|
||||
template chk(input) =
|
||||
let restored = decode(encode(input), float64)
|
||||
check restored == input or (input.isNaN and restored.isNaN)
|
||||
|
||||
chk f
|
||||
chk -f
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user