preserves-nim/src/preserves/private/encoding.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)