nim-blockstore/blockstore/serialization.nim
Chrysostomos Nanakos 7b23545c27
initial commit
Signed-off-by: Chrysostomos Nanakos <chris@include.gr>
2026-01-05 03:05:14 +02:00

172 lines
4.7 KiB
Nim

import std/[streams, endians]
import results
import ./errors
proc writeUint8*(s: Stream, v: uint8) =
s.write(v)
proc readUint8*(s: Stream): uint8 =
s.read(result)
proc writeUint16*(s: Stream, v: uint16) =
var le: uint16
littleEndian16(addr le, unsafeAddr v)
s.write(le)
proc readUint16*(s: Stream): uint16 =
var le: uint16
s.read(le)
littleEndian16(addr result, addr le)
proc writeUint32*(s: Stream, v: uint32) =
var le: uint32
littleEndian32(addr le, unsafeAddr v)
s.write(le)
proc readUint32*(s: Stream): uint32 =
var le: uint32
s.read(le)
littleEndian32(addr result, addr le)
proc writeUint64*(s: Stream, v: uint64) =
var le: uint64
littleEndian64(addr le, unsafeAddr v)
s.write(le)
proc readUint64*(s: Stream): uint64 =
var le: uint64
s.read(le)
littleEndian64(addr result, addr le)
proc writeInt64*(s: Stream, v: int64) =
writeUint64(s, cast[uint64](v))
proc readInt64*(s: Stream): int64 =
cast[int64](readUint64(s))
proc writeBytes*(s: Stream, data: openArray[byte]) =
s.writeUint64(data.len.uint64)
if data.len > 0:
s.writeData(unsafeAddr data[0], data.len)
proc readBytes*(s: Stream): BResult[seq[byte]] =
let len = s.readUint64().int
if len > 0:
var data = newSeq[byte](len)
let bytesRead = s.readData(addr data[0], len)
if bytesRead != len:
return err(ioError("Failed to read " & $len & " bytes, got " & $bytesRead))
ok(data)
else:
ok(newSeq[byte]())
proc writeString*(s: Stream, str: string) =
writeBytes(s, cast[seq[byte]](str))
proc readString*(s: Stream): BResult[string] =
let bytes = ?readBytes(s)
var res = newString(bytes.len)
if bytes.len > 0:
copyMem(addr res[0], unsafeAddr bytes[0], bytes.len)
ok(res)
proc writeBool*(s: Stream, v: bool) =
s.writeUint8(if v: 1 else: 0)
proc readBool*(s: Stream): bool =
s.readUint8() != 0
proc toBytes*[T](obj: T, writer: proc(s: Stream, v: T) {.gcsafe.}): BResult[seq[byte]] {.gcsafe.} =
try:
let s = newStringStream()
{.cast(gcsafe).}:
writer(s, obj)
s.setPosition(0)
ok(cast[seq[byte]](s.readAll()))
except Exception as e:
err(serializationError("serialization failed: " & e.msg))
proc fromBytes*[T](data: openArray[byte], reader: proc(s: Stream): T {.gcsafe.}): BResult[T] {.gcsafe.} =
try:
var str = newString(data.len)
if data.len > 0:
copyMem(addr str[0], unsafeAddr data[0], data.len)
let s = newStringStream(str)
{.cast(gcsafe).}:
ok(reader(s))
except Exception as e:
err(deserializationError("deserialization failed: " & e.msg))
proc fromBytesResult*[T](data: openArray[byte], reader: proc(s: Stream): BResult[T] {.gcsafe.}): BResult[T] {.gcsafe.} =
try:
var str = newString(data.len)
if data.len > 0:
copyMem(addr str[0], unsafeAddr data[0], data.len)
let s = newStringStream(str)
{.cast(gcsafe).}:
reader(s)
except Exception as e:
err(deserializationError("deserialization failed: " & e.msg))
type
BlockInfo* = object
size*: int
refCount*: uint32
proc writeBlockInfo*(s: Stream, info: BlockInfo) {.gcsafe.} =
s.writeUint64(info.size.uint64)
s.writeUint32(info.refCount)
proc readBlockInfo*(s: Stream): BlockInfo {.gcsafe.} =
result.size = s.readUint64().int
result.refCount = s.readUint32()
proc serializeBlockInfo*(info: BlockInfo): BResult[seq[byte]] =
toBytes(info, writeBlockInfo)
proc deserializeBlockInfo*(data: openArray[byte]): BResult[BlockInfo] =
fromBytes(data, readBlockInfo)
type
PendingDeletion* = object
queuedAt*: uint64
blockPath*: string
size*: uint64
proc writePendingDeletion*(s: Stream, pd: PendingDeletion) {.gcsafe.} =
s.writeUint64(pd.queuedAt)
s.writeString(pd.blockPath)
s.writeUint64(pd.size)
proc readPendingDeletion*(s: Stream): BResult[PendingDeletion] {.gcsafe.} =
var pd: PendingDeletion
pd.queuedAt = s.readUint64()
pd.blockPath = ?s.readString()
pd.size = s.readUint64()
ok(pd)
proc serializePendingDeletion*(pd: PendingDeletion): BResult[seq[byte]] =
toBytes(pd, writePendingDeletion)
proc deserializePendingDeletion*(data: openArray[byte]): BResult[PendingDeletion] =
fromBytesResult(data, readPendingDeletion)
proc serializeUint64*(v: uint64): BResult[seq[byte]] =
try:
let s = newStringStream()
s.writeUint64(v)
s.setPosition(0)
ok(cast[seq[byte]](s.readAll()))
except Exception as e:
err(serializationError("serialization failed: " & e.msg))
proc deserializeUint64*(data: openArray[byte]): BResult[uint64] =
if data.len < 8:
return err(deserializationError("Data too short for uint64"))
var str = newString(data.len)
if data.len > 0:
copyMem(addr str[0], unsafeAddr data[0], data.len)
let s = newStringStream(str)
ok(s.readUint64())