mirror of
https://github.com/zap-proto/nim.git
synced 2026-10-30 15:04:34 +00:00
Rename the capnp/ module set to zap/ and the capnpc compiler to zapc; rename all .capnp schemas and fixtures to .zap; update every import, include guard (isInZap), generated-code emission, exception type (ZapFormatError), and the macro-generated zapUnpackStructImpl/ zapPackStructImpl identifiers to the ZAP brand. Zero capnp/Cap'n Proto references remain in source or build files; upstream MIT attribution (Sandstorm, Michał Zieliński) is preserved. Raise the nimble nim floor from the fictional 0.12.0 to the locked, verified 0.15.2 (matches nimenv.cfg/build.sh; code carries fixes through Nim 0.18). Rewrite TODO.md as honest, source-anchored known-limitations (two-word intersegment pointers, nested/named-union codegen, RPC interface inheritance) instead of a bare wishlist.
214 lines
6.3 KiB
Nim
214 lines
6.3 KiB
Nim
# included from zap.nim
|
|
when not compiles(isInZap): {.error: "do not import this file directly".}
|
|
import collections
|
|
|
|
type Packer* = ref object
|
|
buffer*: string
|
|
capToIndex*: (proc(cap: CapServer): RawCapValue)
|
|
|
|
proc packPointer*[T](p: Packer, offset: int, value: T)
|
|
|
|
proc packScalar*[T: SomeInt](v: var string, offset: int, value: T, defaultValue: T) =
|
|
pack(v, offset, value xor defaultValue)
|
|
|
|
proc packScalar*(v: var string, offset: int, value: float32, defaultValue: float32) =
|
|
packScalar(v, offset, cast[uint32](value), cast[uint32](defaultValue))
|
|
|
|
proc packScalar*(v: var string, offset: int, value: float64, defaultValue: float64) =
|
|
packScalar(v, offset, cast[uint64](value), cast[uint64](defaultValue))
|
|
|
|
proc packScalar*[T: enum](v: var string, offset: int, value: T, defaultValue: T) =
|
|
packScalar(v, offset, cast[uint16](value), cast[uint16](defaultValue))
|
|
|
|
proc packBool*(v: var string, bitOffset: int, value: bool, defaultValue: bool) =
|
|
let offset = bitOffset div 8
|
|
let bit = bitOffset mod 8
|
|
if value xor defaultValue:
|
|
v[offset] = (v[offset].uint8 or (1 shl bit).uint8).char
|
|
else:
|
|
v[offset] = (v[offset].uint8 and (not (1 shl bit).uint8)).char
|
|
|
|
proc getSizeTag(s: int): int {.compiletime.} =
|
|
case s:
|
|
of 1: return 2
|
|
of 2: return 3
|
|
of 4: return 4
|
|
of 8: return 5
|
|
else: doAssert(false, "bad size")
|
|
|
|
proc packScalarList[T, R](p: Packer, offset: int, value: T, typ: typedesc[R]) =
|
|
assert p.buffer != nil
|
|
let bodyOffset = p.buffer.len
|
|
assert bodyOffset mod 8 == 0
|
|
|
|
p.buffer.setLen bodyOffset + value.len * sizeof(typ)
|
|
|
|
if value.len != 0:
|
|
copyMem(addr p.buffer[bodyOffset], unsafeAddr value[0], value.len * sizeof(typ))
|
|
|
|
when cpuEndian == bigEndian:
|
|
{.error: "TODO: swap items on list".}
|
|
|
|
p.buffer.padWords
|
|
|
|
let itemSizeTag = getSizeTag(sizeof(typ))
|
|
|
|
let deltaOffset = (bodyOffset - offset - 8) div 8
|
|
pack(p.buffer, offset,
|
|
1.uint64 or
|
|
(deltaOffset.uint64 shl 2) or
|
|
(itemSizeTag.uint64 shl 32) or
|
|
(value.len.uint64 shl 35))
|
|
|
|
proc packPointerList[R](p: Packer, offset: int, value: seq[R], typ: typedesc[R]) =
|
|
mixin packPointer
|
|
|
|
let bodyOffset = p.buffer.len
|
|
assert bodyOffset mod 8 == 0
|
|
|
|
p.buffer.setLen bodyOffset + value.len * 8
|
|
|
|
for i, item in value:
|
|
packPointer(p, bodyOffset + i * 8, item)
|
|
|
|
let itemSizeTag = 6
|
|
let deltaOffset = (bodyOffset - offset - 8) div 8
|
|
pack(p.buffer, offset,
|
|
1.uint64 or
|
|
(deltaOffset.uint64 shl 2) or
|
|
(itemSizeTag.uint64 shl 32) or
|
|
(value.len.uint64 shl 35))
|
|
|
|
proc packNil(p: Packer, offset: int) =
|
|
if offset + 8 <= p.buffer.len:
|
|
pack(p.buffer, offset, 0.uint64)
|
|
|
|
proc packCompositeList[R](p: Packer, offset: int, value: seq[R], typ: typedesc[R]) =
|
|
if value.len == 0:
|
|
packNil(p, offset)
|
|
return
|
|
|
|
mixin zapPackStructImpl
|
|
|
|
var dataSize = 0
|
|
var pointerCount = 0
|
|
|
|
for item in value:
|
|
var fakeBuffer: string = nil
|
|
let info = zapPackStructImpl(p, fakeBuffer, item, 0)
|
|
dataSize = max(dataSize, info.dataSize)
|
|
pointerCount = max(pointerCount, info.pointerCount)
|
|
|
|
let structLength = (dataSize + pointerCount) * 8
|
|
let wordCount = (dataSize + pointerCount) * value.len
|
|
|
|
let bodyOffset = p.buffer.len
|
|
p.buffer.add newZeroString(8)
|
|
let dataOffset = p.buffer.len
|
|
p.buffer.add newZeroString(structLength * value.len)
|
|
|
|
for i, item in value:
|
|
discard zapPackStructImpl(p, p.buffer, item, dataOffset + i * structLength, minDataSize=dataSize)
|
|
|
|
let deltaOffset = (bodyOffset - offset - 8) div 8
|
|
pack(p.buffer, offset,
|
|
1.uint64 or
|
|
(deltaOffset.uint64 shl 2) or
|
|
(7.uint64 shl 32) or
|
|
(wordCount.uint64 shl 35))
|
|
|
|
pack(p.buffer, bodyOffset,
|
|
0.uint64 or
|
|
(value.len.uint64 shl 2) or
|
|
(dataSize.uint64 shl 32) or
|
|
(pointerCount.uint64 shl 48))
|
|
|
|
proc packListImpl[T, R](p: Packer, offset: int, value: T, typ: typedesc[R]) =
|
|
if value.isNil:
|
|
return
|
|
when typ is ZapScalar:
|
|
packScalarList(p, offset, value, typ)
|
|
elif typ is (seq|string) or compiles(toCapServer(value[0])):
|
|
packPointerList(p, offset, value, typ)
|
|
else:
|
|
packCompositeList(p, offset, value, typ)
|
|
|
|
proc packList*[T](p: Packer, offset: int, value: seq[T]) =
|
|
packListImpl(p, offset, value, T)
|
|
|
|
proc packList*(p: Packer, offset: int, value: string) =
|
|
packListImpl(p, offset, value, byte)
|
|
|
|
proc packStruct[T](p: Packer, offset: int, value: T) =
|
|
mixin zapPackStructImpl
|
|
|
|
let dataOffset = p.buffer.len
|
|
let info = zapPackStructImpl(p, p.buffer, value, dataOffset)
|
|
let deltaOffset = (dataOffset - offset - 8) div 8
|
|
pack(p.buffer, offset,
|
|
(deltaOffset.uint64 shl 2) or
|
|
(info.dataSize.uint64 shl 32) or
|
|
(info.pointerCount.uint64 shl 48))
|
|
|
|
proc packCap(p: Packer, offset: int, value: CapServer) =
|
|
let rawValue = p.capToIndex(value)
|
|
|
|
case rawValue.kind:
|
|
of rawCapNumber:
|
|
let id = rawValue.number
|
|
if id == -1:
|
|
pack(p.buffer, offset, 0)
|
|
else:
|
|
pack(p.buffer, offset,
|
|
3.uint64 or (id.uint64 shl 32))
|
|
of rawCapValue:
|
|
pack(p.buffer, offset, rawValue.value)
|
|
|
|
proc packPointer*[T](p: Packer, offset: int, value: T) =
|
|
when value is (string|seq):
|
|
packList(p, offset, value)
|
|
elif T is CapServer:
|
|
packCap(p, offset, value)
|
|
elif T is SomeInterface:
|
|
packCap(p, offset, toCapServer(value))
|
|
elif T is object|ref object:
|
|
if value.isNil:
|
|
packNil(p, offset)
|
|
else:
|
|
packStruct(p, offset, value)
|
|
else:
|
|
mixin packPointerHook
|
|
packPointerHook(p, offset, value)
|
|
|
|
proc preprocessText(v: string): string =
|
|
if v == nil: return v
|
|
else: return v & "\0"
|
|
|
|
proc preprocessText[T](v: seq[T]): seq[T] =
|
|
if v == nil:
|
|
return v
|
|
else:
|
|
return v.map(x => preprocessText(x))
|
|
|
|
proc packText*[T](p: Packer, offset: int, value: T) =
|
|
packPointer(p, offset, preprocessText(value))
|
|
|
|
proc newPacker*(): Packer =
|
|
let capToIndex = proc(cap: CapServer): RawCapValue =
|
|
raise newException(Exception, "this packer doesn't support capabilities")
|
|
|
|
return Packer(
|
|
buffer: newZeroString(8),
|
|
capToIndex: capToIndex)
|
|
|
|
proc packPointer*[T](value: T): string =
|
|
let packer = newPacker()
|
|
packPointer(packer, 0, value)
|
|
return packer.buffer
|
|
|
|
proc packPointerIgnoringCaps*[T](value: T): string =
|
|
let packer = newPacker()
|
|
packer.capToIndex = proc(cap: CapServer): int = RawCapValue(kind: rawCapNumber, number: 0xBEEF)
|
|
packPointer(packer, 0, value)
|
|
return packer.buffer
|