mirror of
https://github.com/logos-storage/nim-blockstore.git
synced 2026-01-12 04:43:09 +00:00
172 lines
4.7 KiB
Nim
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())
|