Skip to content

Commit

Permalink
0.1.0: supports variant objects
Browse files Browse the repository at this point in the history
  • Loading branch information
disruptek committed Aug 13, 2020
1 parent c7cab5e commit 208ddaa
Show file tree
Hide file tree
Showing 9 changed files with 2,264 additions and 1,864 deletions.
3,891 changes: 2,087 additions & 1,804 deletions docs/dochack.js

Large diffs are not rendered by default.

21 changes: 6 additions & 15 deletions docs/frosty.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,12 @@

toggleSwitch.addEventListener('change', switchTheme, false);

const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null;
if (currentTheme) {
document.documentElement.setAttribute('data-theme', currentTheme);

if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.setAttribute('data-theme', "dark");
toggleSwitch.checked = true;
} else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) {
document.documentElement.setAttribute('data-theme', "light");
toggleSwitch.checked = false;
} else {
const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null;
if (currentTheme) {
document.documentElement.setAttribute('data-theme', currentTheme);

if (currentTheme === 'dark') {
toggleSwitch.checked = true;
}
if (currentTheme === 'dark') {
toggleSwitch.checked = true;
}
}
}
Expand Down Expand Up @@ -291,7 +282,7 @@ <h1><a class="toc-backref" href="#12">Procs</a></h1>
<div class="twelve-columns footer">
<span class="nim-sprite"></span>
<br/>
<small style="color: var(--hint);">Made with Nim. Generated: 2020-06-03 22:51:15 UTC</small>
<small style="color: var(--hint);">Made with Nim. Generated: 2020-08-13 17:24:32 UTC</small>
</div>
</div>
</div>
Expand Down
9 changes: 5 additions & 4 deletions docs/nimdoc.out.css
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,13 @@ Modified by Boyd Greenfield and narimiran
.theme-switch-wrapper {
display: flex;
align-items: center;
}

em {
margin-left: 10px;
font-size: 1rem;
}
.theme-switch-wrapper em {
margin-left: 10px;
font-size: 1rem;
}

.theme-switch {
display: inline-block;
height: 22px;
Expand Down
21 changes: 6 additions & 15 deletions docs/theindex.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,12 @@

toggleSwitch.addEventListener('change', switchTheme, false);

const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null;
if (currentTheme) {
document.documentElement.setAttribute('data-theme', currentTheme);

if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.setAttribute('data-theme', "dark");
toggleSwitch.checked = true;
} else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) {
document.documentElement.setAttribute('data-theme', "light");
toggleSwitch.checked = false;
} else {
const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null;
if (currentTheme) {
document.documentElement.setAttribute('data-theme', currentTheme);

if (currentTheme === 'dark') {
toggleSwitch.checked = true;
}
if (currentTheme === 'dark') {
toggleSwitch.checked = true;
}
}
}
Expand Down Expand Up @@ -110,7 +101,7 @@ <h1 class="title">Index</h1>
<div class="twelve-columns footer">
<span class="nim-sprite"></span>
<br/>
<small style="color: var(--hint);">Made with Nim. Generated: 2020-06-03 22:51:15 UTC</small>
<small style="color: var(--hint);">Made with Nim. Generated: 2020-08-13 17:24:32 UTC</small>
</div>
</div>
</div>
Expand Down
109 changes: 93 additions & 16 deletions frosty.nim
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import std/macros
import std/net
import std/streams
import std/tables
Expand All @@ -10,6 +11,7 @@ when not defined(release):
const
frostyMagic* {.intdefine.} = 0xBADCAB ##
## A magic file value for our "format".
frostyDebug {.booldefine.} = when defined(release): false else: true

enableLists = false

Expand Down Expand Up @@ -52,6 +54,8 @@ proc write(s: var Serializer[Stream]; o: string)
proc read(s: var Serializer[Stream]; o: var string)
proc write(s: var Serializer[Socket]; o: string)
proc read(s: var Serializer[Socket]; o: var string)
proc readPrimitive[T](s: var Serializer[Stream]; o: var T)
proc readPrimitive[T](s: var Serializer[Socket]; o: var T)

when enableLists:
import std/lists
Expand Down Expand Up @@ -176,6 +180,87 @@ proc write[S, T](s: var Serializer[S]; o: ref T; parent = 0) =
else:
raise

proc readTuple[S, T](s: var Serializer[S]; o: var T; skip = false) =
var skip = skip
for k, val in fieldPairs(o):
if skip:
skip = false
else:
# create a var that we can pass to the read()
var x: typeof(val)
s.read x
val = x

macro readObject[S, T](s: var Serializer[S]; o: var T) =
# do nothing by default
result = newEmptyNode()
let
readTuple = bindSym"readTuple"
reader = bindSym("readPrimitive", rule = brClosed)
typ = o.getTypeImpl
sym = o.getTypeInst
when defined(frostyDebug):
echo typ.treeRepr
echo typ.repr
case typ.kind
of nnkObjectTy:
let fields = typ[^1] # RecList
case fields[0].kind
of nnkIdentDefs:
# named tuple/object
result = newCall(readTuple, s, o)
of nnkRecCase:
# object variant
result = newStmtList()
let disc = fields[0][0] # the first IdentDefs under RecCase

let name = disc[0] # the symbol of the discriminator
let dtyp = disc[1] # the type of the discriminator

when defined(frostyDebug):
echo dtyp.getTypeImpl.treeRepr

# create a variable into which we can read the discriminator
let kind = genSym(nskVar, "kind")

# declare our kind variable with its value type
result.add nnkVarSection.newTree(newIdentDefs(kind, dtyp,
newEmptyNode()))

# read the value of the discriminator into our `kind` variable
result.add newCall(reader, s, kind)

# create an object constructor for the variant object
var ctor = nnkObjConstr.newNimNode

# the first child is the name of the object type
ctor.add ident(sym.strVal)

# add `name: kind` to the variant object constructor
ctor.add newColonExpr(name, kind)

# assign it to the input symbol
result.add newAssignment(o, ctor)

# prepare a skip=true argument to readTuple()
let skip = nnkExprEqExpr.newTree(ident"skip", ident"true")

# read the remaining fields as determined by the discriminator
result.add newCall(readTuple, s, o, skip) # skip 1st field

else:
error "unrecognized type format: \n" & treeRepr(typ)

of nnkTupleTy:
# (name: "jeff", age: 34)
result = newCall(readTuple, s, o)
of nnkTupleConstr:
# ("jeff", 34)
result = newCall(readTuple, s, o)
else:
error "attempt to read unrecognized type: " & $typ.kind


proc read[S, T](s: var Serializer[S]; o: var ref T) =
var
g: Cube
Expand Down Expand Up @@ -229,38 +314,30 @@ proc writePrimitive[T](s: var Serializer[Socket]; o: T) =

proc write[S, T](s: var Serializer[S]; o: T; parent = 0) =
when T is object or T is tuple:
#s.debung $typeof(o)
when defined(frostyDebug):
s.debung $typeof(o)
s.greatenIndent:
for k, val in fieldPairs(o):
when val is ref:
s.write val, parent = parent
else:
s.write val
#let q = repr(val)
#s.debung k & ": " & $typeof(val) & " = " & q[low(q)..min(20, high(q))]
when defined(frostyDebug):
let q = repr(val)
s.debung k & ": " & $typeof(val) & " = " & q[low(q)..min(20, high(q))]
else:
writePrimitive(s, o)

proc readPrimitive[T](s: var Serializer[Stream]; o: var T) =
read(s.stream, o)
streams.read(s.stream, o)

proc readPrimitive[T](s: var Serializer[Socket]; o: var T) =
if recv(s.socket, data = addr o, size = sizeof(o)) != sizeof(o):
if net.recv(s.socket, data = addr o, size = sizeof(o)) != sizeof(o):
raise newException(ThawError, "short read; socket closed?")

proc read[S, T](s: var Serializer[S]; o: var T) =
when T is object or T is tuple:
#s.debung $typeof(o)
s.greatenIndent:
for k, val in fieldPairs(o):
{.push fieldChecks: off.}
# work around variant objects?
var x = val
s.read x
val = x
#let q = repr(val)
#s.debung k & ": " & $typeof(val) & " = " & q[low(q)..min(20, high(q))]
{.pop.}
readObject(s, o)
else:
readPrimitive(s, o)

Expand Down
2 changes: 1 addition & 1 deletion frosty.nimble
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version = "0.0.6"
version = "0.1.0"
author = "disruptek"
description = "marshal native Nim objects via streams, channels"
license = "MIT"
Expand Down
3 changes: 3 additions & 0 deletions tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*
!.*
!*.nim
48 changes: 39 additions & 9 deletions tests/bench.nim
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,29 @@ let
count = if paramCount() < 2: 1 else: parseInt paramStr(2)
echo "benching against " & $count & " units in " & fn

let
tJs = %* {
"goats": ["pigs", "horses"],
"sheep": 11,
"ducks": 12.0,
"dogs": "woof",
"cats": false,
"frogs": { "toads": true, "rats": "yep" },
}
var
tJsA {.compileTime.} = newJArray()
tJsO {.compileTime.} = newJObject()
tJs {.compileTime.} = newJObject()

tJsA.add newJString"pigs"
tJsA.add newJString"horses"

tJsO.add "toads", newJBool(true)
tJsO.add "rats", newJString"yep"

for k, v in {
"goats": tJsA,
"sheep": newJInt(11),
"ducks": newJFloat(12.0),
"dogs": newJString("woof"),
"cats": newJBool(false),
"frogs": tJsO,
}.items:
tJs[k] = v

const
jsSize = len($tJs)

template writeSomething*(ss: Stream; w: typed): untyped =
ss.setPosition 0
Expand Down Expand Up @@ -90,6 +104,22 @@ benchmark cfg:
proc read_intset() {.measure.} =
let r = ss.readSomething tIntset

proc write_json_naive() {.measure.} =
ss.setPosition 0
if count == 1:
ss.write $tJs
else:
for i in 1 .. count:
ss.write $tJs

proc read_json_naive() {.measure.} =
ss.setPosition 0
if count == 1:
discard parseJson(ss.readStr jsSize)
else:
for i in 1 .. count:
discard parseJson(ss.readStr jsSize)

proc write_json() {.measure.} =
ss.writeSomething tJs

Expand Down
24 changes: 24 additions & 0 deletions tests/test.nim
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,20 @@ type
d: MyType
e: G
f: F
g: (string, int)
h: (VType, VType)
j: Table[string, int]
k: TableRef[string, int]
l: IntSet
m: JsonNode

VType = object
case kind: G
of Even:
even: int
of Odd:
odd: bool

proc fileSize(path: string): float =
result = getFileInfo(path).size.float / (1024*1024)

Expand Down Expand Up @@ -80,13 +89,25 @@ proc hash[A, B](t: TableRef[A, B]): Hash =
h = h !& hash(v)
result = !$h

proc hash(t: VType): Hash =
var h: Hash = 0
h = h !& hash(t.kind)
case t.kind
of Even:
h = h !& hash(t.even)
of Odd:
h = h !& hash(t.odd)
result = !$h

proc hash(m: MyType): Hash =
var h: Hash = 0
h = h !& hash(m.a)
h = h !& hash(m.b)
h = h !& hash(m.c)
h = h !& hash(m.e)
h = h !& hash(m.f)
h = h !& hash(m.g)
h = h !& hash(m.h)
h = h !& hash(m.j)
h = h !& hash(m.k)
h = h !& hash(m.l)
Expand Down Expand Up @@ -140,6 +161,9 @@ proc makeChunks(n: int): seq[MyType] =
result.add MyType(a: rand(int n), b: rand(float n),
e: G(n mod 2), #m: tJs,
j: jj, c: $n, f: F(x: 66, y: 77),
g: ("hello", 22),
h: (VType(kind: Even, even: 11),
VType(kind: Odd, odd: true)),
l: l, k: kk)
if len(result) > 1:
# link the last item to the previous item
Expand Down

0 comments on commit 208ddaa

Please sign in to comment.