-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathserialization.nim
168 lines (145 loc) · 6.26 KB
/
serialization.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
import
std/typetraits,
stew/shims/macros, faststreams/[inputs, outputs],
./serialization/[object_serialization, errors, formats]
export
inputs, outputs, object_serialization, errors, formats
template encode*(Format: type, value: auto, params: varargs[untyped]): auto =
mixin init, Writer, writeValue, PreferredOutputType
block: # https://github.com/nim-lang/Nim/issues/22874
{.noSideEffect.}:
# We assume that there is no side-effects here, because we are
# using a `memoryOutput`. The computed side-effects are coming
# from the fact that the dynamic dispatch mechanisms used in
# faststreams may be writing to a file or a network device.
try:
var s = memoryOutput()
type WriterType = Writer(Format)
var writer = unpackArgs(init, [WriterType, s, params])
writeValue writer, value
s.getOutput PreferredOutputType(Format)
except IOError:
raise (ref Defect)() # a memoryOutput cannot have an IOError
# TODO Nim cannot make sense of this initialization by var param?
proc readValue*(reader: var auto, T: type): T {.gcsafe, raises: [SerializationError, IOError].} =
{.warning[ProveInit]: false.}
mixin readValue
result = default(T)
reader.readValue(result)
{.warning[ProveInit]: true.}
template decode*(Format: distinct type,
input: string,
RecordType: distinct type,
params: varargs[untyped]): auto =
# TODO, this is dusplicated only due to a Nim bug:
# If `input` was `string|openArray[byte]`, it won't match `seq[byte]`
mixin init, Reader
block: # https://github.com/nim-lang/Nim/issues/22874
{.noSideEffect.}:
# We assume that there are no side-effects here, because we are
# using a `memoryInput`. The computed side-effects are coming
# from the fact that the dynamic dispatch mechanisms used in
# faststreams may be reading from a file or a network device.
try:
var stream = unsafeMemoryInput(input)
type ReaderType = Reader(Format)
var reader = unpackArgs(init, [ReaderType, stream, params])
reader.readValue(RecordType)
except IOError:
raise (ref Defect)() # memory inputs cannot raise an IOError
template decode*(Format: distinct type,
input: openArray[byte],
RecordType: distinct type,
params: varargs[untyped]): auto =
# TODO, this is dusplicated only due to a Nim bug:
# If `input` was `string|openArray[byte]`, it won't match `seq[byte]`
mixin init, Reader
block: # https://github.com/nim-lang/Nim/issues/22874
{.noSideEffect.}:
# We assume that there are no side-effects here, because we are
# using a `memoryInput`. The computed side-effects are coming
# from the fact that the dynamic dispatch mechanisms used in
# faststreams may be reading from a file or a network device.
try:
var stream = unsafeMemoryInput(input)
type ReaderType = Reader(Format)
var reader = unpackArgs(init, [ReaderType, stream, params])
reader.readValue(RecordType)
except IOError:
raise (ref Defect)() # memory inputs cannot raise an IOError
template loadFile*(Format: distinct type,
filename: string,
RecordType: distinct type,
params: varargs[untyped]): auto =
mixin init, Reader, readValue
var stream = memFileInput(filename)
try:
type ReaderType = Reader(Format)
var reader = unpackArgs(init, [ReaderType, stream, params])
reader.readValue(RecordType)
finally:
close stream
template loadFile*[RecordType](Format: type,
filename: string,
record: var RecordType,
params: varargs[untyped]) =
record = loadFile(Format, filename, RecordType, params)
template saveFile*(Format: type, filename: string, value: auto, params: varargs[untyped]) =
mixin init, Writer, writeValue
var stream = fileOutput(filename)
try:
type WriterType = Writer(Format)
var writer = unpackArgs(init, [WriterType, stream, params])
writer.writeValue(value)
finally:
close stream
template borrowSerialization*(Alias: type) {.dirty.} =
bind distinctBase
proc writeValue*[Writer](
writer: var Writer, value: Alias) {.raises: [IOError].} =
mixin writeValue
writeValue(writer, distinctBase value)
proc readValue*[Reader](reader: var Reader, value: var Alias) =
mixin readValue
value = Alias reader.readValue(distinctBase Alias)
template borrowSerialization*(Alias: distinct type,
OriginalType: distinct type) {.dirty.} =
proc writeValue*[Writer](
writer: var Writer, value: Alias) {.raises: [IOError].} =
mixin writeValue
writeValue(writer, OriginalType value)
proc readValue*[Reader](reader: var Reader, value: var Alias) =
mixin readValue
value = Alias reader.readValue(OriginalType)
template serializesAsBase*(SerializedType: distinct type,
Format: distinct type) =
mixin Reader, Writer
type ReaderType = Reader(Format)
type WriterType = Writer(Format)
template writeValue*(writer: var WriterType, value: SerializedType) =
mixin writeValue
writeValue(writer, distinctBase value)
template readValue*(reader: var ReaderType, value: var SerializedType) =
mixin readValue
value = SerializedType reader.readValue(distinctBase SerializedType)
macro serializesAsBaseIn*(SerializedType: type,
Formats: varargs[untyped]) =
result = newStmtList()
for Fmt in Formats:
result.add newCall(bindSym"serializesAsBase", SerializedType, Fmt)
template readValue*(stream: InputStream,
Format: type,
ValueType: type,
params: varargs[untyped]): untyped =
mixin Reader, init, readValue
type ReaderType = Reader(Format)
var reader = unpackArgs(init, [ReaderType, stream, params])
readValue reader, ValueType
template writeValue*(stream: OutputStream,
Format: type,
value: auto,
params: varargs[untyped]) =
mixin Writer, init, writeValue
type WriterType = Writer(Format)
var writer = unpackArgs(init, [WriterType, stream, params])
writeValue writer, value