blob: 34f262a1e30f858b69a0cc09030ca456e91db717 [file] [log] [blame]
import endian
type
uoffset* = uint32 ## offset in to the buffer
soffset* = int32 ## offset from start of table, to a vtable
voffset* = uint16 ## offset from start of table to value
type Offsets* = uoffset | soffset | voffset
type Vtable* = object
Bytes*: seq[byte]
Pos*: uoffset
using this: Vtable
func GetVal*[T](b: ptr seq[byte]): T {.inline.} =
when T is float64:
result = cast[T](GetVal[uint64](b))
elif T is float32:
result = cast[T](GetVal[uint32](b))
elif T is string:
result = cast[T](b[])
else:
if b[].len < T.sizeof:
b[].setLen T.sizeof
result = cast[ptr T](unsafeAddr b[][0])[]
template Get*[T](this; off: uoffset): T =
var seq = this.Bytes[off..^1]
GetVal[T](addr seq)
template Get*[T](this; off: soffset): T =
var seq = this.Bytes[off..^1]
GetVal[T](addr seq)
template Get*[T](this; off: voffset): T =
var seq = this.Bytes[off..^1]
GetVal[T](addr seq)
func WriteVal*[T: not SomeFloat](b: var openArray[byte]; off: uoffset;
n: T) {.inline.} =
when sizeof(T) == 8:
littleEndianX(addr b[off], unsafeAddr n, T.sizeof)
elif sizeof(T) == 4:
littleEndianX(addr b[off], unsafeAddr n, T.sizeof)
elif sizeof(T) == 2:
littleEndianX(addr b[off], unsafeAddr n, T.sizeof)
elif sizeof(T) == 1:
b[off] = n.uint8
else:
discard
#littleEndianX(addr b[off], unsafeAddr n, T.sizeof)
#{.error:"shouldnt appear".}
func WriteVal*[T: not SomeFloat](b: var seq[byte]; off: uoffset;
n: T) {.inline.} =
when sizeof(T) == 8:
littleEndianX(addr b[off], unsafeAddr n, T.sizeof)
elif sizeof(T) == 4:
littleEndianX(addr b[off], unsafeAddr n, T.sizeof)
elif sizeof(T) == 2:
littleEndianX(addr b[off], unsafeAddr n, T.sizeof)
elif sizeof(T) == 1:
b[off] = n.uint8
else:
discard
#littleEndianX(addr b[off], unsafeAddr n, T.sizeof)
#{.error:"shouldnt appear".}
func WriteVal*[T: SomeFloat](b: var openArray[byte]; off: uoffset;
n: T) {.inline.} =
when T is float64:
WriteVal(b, off, cast[uint64](n))
elif T is float32:
WriteVal(b, off, cast[uint32](n))
func WriteVal*[T: SomeFloat](b: var seq[byte]; off: uoffset; n: T) {.inline.} =
when T is float64:
WriteVal(b, off, cast[uint64](n))
elif T is float32:
WriteVal(b, off, cast[uint32](n))
func Offset*(this; off: voffset): voffset =
let vtable = (this.Pos - this.Get[:uoffset](this.Pos)).voffset
let vtableEnd = this.Get[:voffset](vtable)
if off < vtableEnd:
return this.Get[:voffset](vtable + off)
return 0
func Indirect*(this; off: uoffset): uoffset =
result = off + this.Get[:uoffset](off)
func VectorLen*(this; off: uoffset): int =
var newoff: uoffset = off + this.Pos
newoff += this.Get[:uoffset](newoff)
return this.Get[:uoffset](newoff).int
func Vector*(this; off: uoffset): uoffset =
let newoff: uoffset = off + this.Pos
var x: uoffset = newoff + this.Get[:uoffset](newoff)
x += (uoffset.sizeof).uoffset
result = x
func Union*(this; off: uoffset): Vtable =
let newoff: uoffset = off + this.Pos
result.Pos = newoff + this.Get[:uoffset](newoff)
result.Bytes = this.Bytes
func GetSlot*[T](this; slot: voffset; d: T): T =
let off = this.Offset(slot)
if off == 0:
return d
return this.Get[T](this.Pos + off)
func GetOffsetSlot*[T: Offsets](this; slot: voffset; d: T): T =
let off = this.Offset(slot)
if off == 0:
return d
return off
func ByteVector*(this; off: uoffset): seq[byte] =
let
newoff: uoffset = off + this.Get[:uoffset](off)
start = newoff + (uoffset.sizeof).uoffset
var newseq = this.Bytes[newoff..^1]
let
length = GetVal[uoffset](addr newseq)
result = this.Bytes[start..<start+length]
func String*(this; off: uoffset): string =
var byte_seq = this.ByteVector(off)
result = GetVal[string](addr byte_seq)
using this: var Vtable
proc Mutate*[T](this; off: uoffset; n: T): bool =
WriteVal(this.Bytes, off, n)
return true
func MutateSlot*[T](this; slot: voffset; n: T): bool =
let off: voffset = this.Offset(slot)
if off != 0:
return this.Mutate(this.Pos + off.uoffset, n)
return false