Files
zeekay 68037f9ca4 Rebrand Cap'n Proto Nim port to ZAP
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.
2026-06-19 23:42:02 -07:00

89 lines
2.7 KiB
Nim

when not compiles(isInZap): {.error: "do not import this file directly".}
import endians, strutils, sequtils, typetraits, collections/reflect, collections/lang, collections/iface, collections/pprint
type ZapFormatError* = object of Exception
type ZapScalar* = uint8 | uint16 | uint32 | uint64 | int8 | int16 | int32 | int64 | float32 | float64 | byte | char | enum
proc convertEndian*(size: static[int], dst: pointer, src: pointer, endian=littleEndian) {.inline.} =
when size == 1:
copyMem(dst, src, 1)
else:
case endian:
of bigEndian:
when size == 2:
bigEndian16(dst, src)
elif size == 4:
bigEndian32(dst, src)
elif size == 8:
bigEndian64(dst, src)
else:
{.error: "Unsupported size".}
of littleEndian:
when size == 2:
littleEndian16(dst, src)
elif size == 4:
littleEndian32(dst, src)
elif size == 8:
littleEndian64(dst, src)
else:
{.error: "Unsupported size".}
proc pack*[T](v: var string, offset: int, value: T, endian=littleEndian) {.inline.} =
let minLength = offset + sizeof(T)
if minLength > v.len or offset > v.len:
raise newException(ZapFormatError, "bad offset")
convertEndian(sizeof(T), addr v[offset], unsafeAddr value)
proc pack*[T](value: T, endian=littleEndian): string {.inline.} =
var s = newString(sizeof(T))
pack(s, 0, value, endian)
return s
proc unpack*[T](v: string, offset: int, t: typedesc[T], endian=littleEndian): T {.inline.} =
if not (offset < v.len and offset + sizeof(t) <= v.len and offset >= 0):
raise newException(ZapFormatError, "bad offset (offset=$1 len=$2)" % [$offset, $v.len])
convertEndian(sizeof(T), addr result, unsafeAddr v[offset])
proc extractBits*(v: uint64|uint32|uint16|uint8, k: Natural, bits: static[int]): int {.inline.} =
assert k + bits <= sizeof(v) * 8
static: assert bits <= 32
return cast[int]((v shr k) and ((1 shl bits) - 1).uint64)
proc newZeroString*(length: int): string =
repeat('\0', length)
proc isZeros(s: string): bool =
for i in s:
if i != '\0': return false
return true
proc padWords*(s: var string) =
if s.len mod 8 != 0:
s &= newZeroString(8 - (s.len mod 8))
proc trimWords*(s: var string, minSize=0) =
while s.len > minSize:
let offset = ((s.len - 1) div 8) * 8
let trailing = s[offset..^1]
if isZeros(trailing):
s.setLen(offset)
else:
break
s.padWords
if s.len < minSize * 8:
s &= newZeroString(minSize - s.len)
proc insertAt*(s: var string, offset: int, data: string) =
assert s != nil
if offset < 0:
raise newException(IndexError, "offset < 0")
if s.len < offset + data.len:
s.setLen offset + data.len
copyMem(addr s[offset], unsafeAddr data[0], data.len)