101 lines
2.6 KiB
Nim
101 lines
2.6 KiB
Nim
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
|
# SPDX-License-Identifier: Unlicense
|
|
|
|
import std/[endians, options, sets, sequtils, streams, tables, typetraits]
|
|
import ./values
|
|
|
|
proc writeVarint(s: Stream; n: Natural) =
|
|
var n = n
|
|
while n > 0x7f:
|
|
s.write(uint8 n or 0x80)
|
|
n = n shr 7
|
|
s.write(uint8 n and 0x7f)
|
|
|
|
proc write*[E](str: Stream; pr: Preserve[E]) =
|
|
## Write the binary-encoding of a Preserves value to a stream.
|
|
if pr.embedded: str.write(0x86'u8)
|
|
case pr.kind:
|
|
of pkBoolean:
|
|
case pr.bool
|
|
of false: str.write(0x80'u8)
|
|
of true: str.write(0x81'u8)
|
|
of pkFloat:
|
|
str.write("\x87\x04")
|
|
when system.cpuEndian == bigEndian:
|
|
str.write(pr.float)
|
|
else:
|
|
var be: float32
|
|
swapEndian32(be.addr, pr.float.unsafeAddr)
|
|
str.write(be)
|
|
of pkDouble:
|
|
str.write("\x87\x08")
|
|
when system.cpuEndian == bigEndian:
|
|
str.write(pr.double)
|
|
else:
|
|
var be: float64
|
|
swapEndian64(be.addr, pr.double.unsafeAddr)
|
|
str.write(be)
|
|
of pkSignedInteger:
|
|
if pr.int == 0:
|
|
str.write("\xb0\x00")
|
|
else:
|
|
var bitCount = 1'u8
|
|
if pr.int < 0:
|
|
while ((not pr.int) shr bitCount) != 0:
|
|
inc(bitCount)
|
|
else:
|
|
while (pr.int shr bitCount) != 0:
|
|
inc(bitCount)
|
|
var byteCount = (bitCount + 8) div 8
|
|
str.write(0xb0'u8)
|
|
str.writeVarint(byteCount)
|
|
proc write(n: uint8; i: BiggestInt) =
|
|
if n > 1:
|
|
write(n.pred, i shr 8)
|
|
str.write(i.uint8)
|
|
write(byteCount, pr.int)
|
|
of pkString:
|
|
str.write(0xb1'u8)
|
|
str.writeVarint(pr.string.len)
|
|
str.write(pr.string)
|
|
of pkByteString:
|
|
str.write(0xb2'u8)
|
|
str.writeVarint(pr.bytes.len)
|
|
str.write(cast[string](pr.bytes))
|
|
of pkSymbol:
|
|
str.write(0xb3'u8)
|
|
str.writeVarint(pr.symbol.len)
|
|
str.write(string pr.symbol)
|
|
of pkRecord:
|
|
assert(pr.record.len > 0)
|
|
str.write(0xb4'u8)
|
|
str.write(pr.record[pr.record.high])
|
|
for i in 0..<pr.record.high:
|
|
str.write(pr.record[i])
|
|
str.write(0x84'u8)
|
|
of pkSequence:
|
|
str.write(0xb5'u8)
|
|
for e in pr.sequence:
|
|
str.write(e)
|
|
str.write(0x84'u8)
|
|
of pkSet:
|
|
str.write(0xb6'u8)
|
|
for val in pr.set.items:
|
|
str.write(val)
|
|
str.write(0x84'u8)
|
|
of pkDictionary:
|
|
str.write(0xb7'u8)
|
|
for (key, value) in pr.dict.items:
|
|
str.write(key)
|
|
str.write(value)
|
|
str.write(0x84'u8)
|
|
of pkEmbedded:
|
|
str.write(0x86'u8)
|
|
str.write(pr.embed.toPreserve)
|
|
|
|
proc encode*[E](pr: Preserve[E]): seq[byte] =
|
|
## Return the binary-encoding of a Preserves value.
|
|
let s = newStringStream()
|
|
s.write pr
|
|
result = cast[seq[byte]](move s.data)
|