Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ jobs:
include:
- target:
os: linux
builder: ubuntu-20.04
builder: ubuntu-22.04
- target:
os: macos
builder: macos-11
builder: macos-13
- target:
os: windows
builder: windows-2019
builder: windows-latest

name: '${{ matrix.target.os }}-${{ matrix.target.cpu }}-${{ matrix.test_lang }}'
runs-on: ${{ matrix.builder }}
Expand Down
4 changes: 3 additions & 1 deletion examples/gotchas.nim
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,7 @@ unpack(buf, tom) #magically, it will unpack into a Cat

test "gochas":
check tom.legs == 4
check $tom.kittens == "{\"colt\", \"jilly\"}"
check "jilly" in tom.kittens
check "colt" in tom.kittens
check tom.kittens.len == 2
check $tom.traits == "{color: black, speed: 120mph}"
96 changes: 37 additions & 59 deletions src/msgpack4nim.nim
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ when not declared SomeFloat:
type
SomeFloat = SomeReal

import endians, macros, strutils, streams
import endians, macros, strutils, streams, typetraits

const pack_value_nil* = chr(0xc0)

Expand Down Expand Up @@ -100,52 +100,19 @@ template skipUndistinct* {.pragma, deprecated.}
# no need to use this pragma anymore
# the undistinct macro is more clever now

proc getParamIdent(n: NimNode): NimNode =
n.expectKind({nnkIdent, nnkVarTy, nnkSym})
if n.kind in {nnkIdent, nnkSym}:
result = n
template undistinct_pack*(s, f, x) =
mixin pack_type
when compiles(f(s, x)):
f(s, x)
else:
result = n[0]

proc hasDistinctImpl(w: NimNode, z: NimNode): bool =
for k in w:
let p = k.getImpl()[3][2][1]
if p.kind in {nnkIdent, nnkVarTy, nnkSym}:
let paramIdent = getParamIdent(p)
if eqIdent(paramIdent, z): return true

proc needToSkip(typ: NimNode | typedesc, w: NimNode): bool {.compileTime.} =
let z = getType(typ)[1]

if z.kind == nnkSym:
if hasDistinctImpl(w, z): return true

if z.kind != nnkSym: return false
let impl = getImpl(z)
if impl.kind != nnkTypeDef: return false
if impl[2].kind != nnkDistinctTy: return false
if impl[0].kind != nnkPragmaExpr: return false
let prag = impl[0][1][0]
result = eqIdent("skipUndistinct", prag)

#this macro convert any distinct types to it's base type
macro undistinctImpl*(x: typed, typ: typedesc, w: typed): untyped =
var ty = getType(x)
if needToSkip(typ, w):
result = x
return
var isDistinct = ty.typekind == ntyDistinct
if isDistinct:
let parent = ty[1]
result = quote do: `parent`(`x`)
else:
result = x

template undistinct_pack*(x: typed): untyped =
undistinctImpl(x, type(x), bindSym("pack_type", brForceOpen))
f(s, distinctBase(x))

template undistinct_unpack*(x: typed): untyped =
undistinctImpl(x, type(x), bindSym("unpack_type", brForceOpen))
template undistinct_unpack*(s, f, x) =
mixin unpack_type
when compiles(f(s, x)):
f(s, x)
else:
f(s, distinctBase(x))

when system.cpuEndian == littleEndian:
proc take8_8(val: uint8): uint8 {.inline.} = val
Expand Down Expand Up @@ -663,30 +630,33 @@ proc pack_items_imp*[Stream, T](s: Stream, val: T) {.inline.} =
var ss = MsgStream.init(sizeof(T))
var count = 0
for i in items(val):
ss.pack undistinct_pack(i)
undistinct_pack(ss, pack, i)
inc(count)
s.pack_array(count)
s.write(ss.data)

proc pack_map_imp*[Stream, T](s: Stream, val: T) {.inline.} =
mixin pack_type
s.pack_map(val.len)
for k,v in pairs(val):
s.pack_type undistinct_pack(k)
s.pack_type undistinct_pack(v)
undistinct_pack(s, pack_type, k)
undistinct_pack(s, pack_type, v)

proc pack_type*[Stream, T](s: Stream, val: openArray[T]) =
mixin pack_type
s.pack_array(val.len)
for i in 0..val.len-1: s.pack_type undistinct_pack(val[i])
for i in 0..val.len-1: undistinct_pack(s, pack_type, val[i])

proc pack_type*[Stream, T](s: Stream, val: seq[T]) =
mixin pack_type
when compiles(isNil(val)):
if isNil(val): s.pack_imp_nil()
else:
s.pack_array(val.len)
for i in 0..val.len-1: s.pack_type undistinct_pack(val[i])
for i in 0..val.len-1: undistinct_pack(s, pack_type, val[i])
else:
s.pack_array(val.len)
for i in 0..val.len-1: s.pack_type undistinct_pack(val[i])
for i in 0..val.len-1: undistinct_pack(s, pack_type, val[i])

proc pack_type*[Stream; T: enum|range](s: Stream, val: T) =
when val is range:
Expand All @@ -695,6 +665,7 @@ proc pack_type*[Stream; T: enum|range](s: Stream, val: T) =
pack_int_imp_select(s, val)

proc pack_type*[Stream; T: tuple|object](s: Stream, val: T) =
mixin pack_type
var len = 0
for field in fields(val):
inc(len)
Expand All @@ -704,39 +675,41 @@ proc pack_type*[Stream; T: tuple|object](s: Stream, val: T) =
s.pack_map(len)
for field, value in fieldPairs(val):
s.pack_type field
s.pack_type undistinct_pack(value)
undistinct_pack(s, pack_type, value)
elif defined(msgpack_obj_to_stream):
for field in fields(val):
s.pack_type undistinct_pack(field)
undistinct_pack(s, pack_type, field)
else:
s.pack_array(len)
for field in fields(val):
s.pack_type undistinct_pack(field)
undistinct_pack(s, pack_type, field)

when Stream is MsgStream:
case s.encodingMode
of MSGPACK_OBJ_TO_ARRAY:
s.pack_array(len)
for field in fields(val):
s.pack_type undistinct_pack(field)
undistinct_pack(s, pack_type, field)
of MSGPACK_OBJ_TO_MAP:
s.pack_map(len)
for field, value in fieldPairs(val):
s.pack_type field
s.pack_type undistinct_pack(value)
undistinct_pack(s, pack_type, value)
of MSGPACK_OBJ_TO_STREAM:
for field in fields(val):
s.pack_type undistinct_pack(field)
undistinct_pack(s, pack_type, field)
else:
dry_and_wet()
else:
dry_and_wet()

proc pack_type*[Stream; T: ref](s: Stream, val: T) =
mixin pack_type
if isNil(val): s.pack_imp_nil()
else: s.pack_type(val[])

proc pack_type*[Stream, T](s: Stream, val: ptr T) =
mixin pack_type
if isNil(val): s.pack_imp_nil()
else: s.pack_type(val[])

Expand Down Expand Up @@ -1165,8 +1138,13 @@ proc unpack_type*(s: Stream, val: var pointer) =
discard
#raise conversionError("can't convert pointer type")

proc pack*[Stream, T](s: Stream, val: T) = s.pack_type undistinct_pack(val)
proc unpack*[Stream, T](s: Stream, val: var T) = s.unpack_type undistinct_unpack(val)
proc pack*[Stream, T](s: Stream, val: T) =
mixin pack_type
undistinct_pack(s, pack_type, val)

proc unpack*[Stream, T](s: Stream, val: var T) =
mixin unpack_type
undistinct_unpack(s, unpack_type, val)

proc pack*[T](val: T): string =
var s = MsgStream.init(sizeof(T))
Expand Down
7 changes: 4 additions & 3 deletions src/msgpack4nim/msgpack4collection.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import sequtils, math, ../msgpack4nim
import tables, intsets, lists, deques, sets, strtabs, critbits, streams
import typetraits

{.push gcsafe.}

Expand All @@ -26,15 +27,15 @@ proc pack_type*[Stream, T](s: Stream, val: DoublyLinkedRing[T]) =

proc pack_type*[Stream, T](s: Stream, val: Deque[T]) =
s.pack_array(val.len)
for i in items(val): s.pack_type undistinct_pack(i)
for i in items(val): s.pack_type distinctBase(i)

proc pack_type*[Stream, T](s: Stream, val: HashSet[T]) =
s.pack_array(val.len)
for i in items(val): s.pack_type undistinct_pack(i)
for i in items(val): s.pack_type distinctBase(i)

proc pack_type*[Stream, T](s: Stream, val: OrderedSet[T]) =
s.pack_array(val.len)
for i in items(val): s.pack_type undistinct_pack(i)
for i in items(val): s.pack_type distinctBase(i)

proc pack_type*[Stream, K,V](s: Stream, val: Table[K,V]) =
s.pack_map_imp(val)
Expand Down
1 change: 1 addition & 0 deletions tests/config.nims
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
switch("path", "$projectDir/../src")
switch("outdir", "$projectDir/../build")
switch("define", "nimLegacySprintf")
4 changes: 2 additions & 2 deletions tests/test_codec.nim
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ type

PRESTO = seq[string]

proc pack_type(s: Stream, v: Guid) =
proc pack_type*(s: Stream, v: Guid) =
s.pack_bin(len(v.string))
s.write(v.string)

proc unpack_type(s: Stream, v: var Guid) =
proc unpack_type*(s: Stream, v: var Guid) =
let L = s.unpack_bin()
v = Guid(s.readExactStr(L))

Expand Down
2 changes: 1 addition & 1 deletion tests/test_json.nim
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import std/[json, os, streams, strutils, unittest]
import std/[json, streams, strutils, unittest]

import msgpack4nim
import msgpack4nim/msgpack2json
Expand Down
Loading