-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathindex.js
192 lines (149 loc) · 4.44 KB
/
index.js
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
var assert = require('./util').assert
var base = require('./base')
var codecs = require('./codecs')
var bytewise = exports
//
// expose type information
//
var sorts = bytewise.sorts = base.sorts
bytewise.bound = base.bound
bytewise.compare = base.compare
bytewise.equal = base.equal
//
// generate a buffer with type's byte prefix from source value
//
function serialize(type, source, options) {
var codec = type.codec
if (!codec)
return postEncode(new Buffer([ type.byte ]), options)
var buffer = codec.encode(source, bytewise)
if (options && options.nested && codec.escape)
buffer = codec.escape(buffer)
var hint = typeof codec.length === 'number' ? (codec.length + 1) : void 0
var buffers = [ new Buffer([ type.byte ]), buffer ]
return postEncode(Buffer.concat(buffers, hint), options)
}
//
// core encode logic
//
bytewise.encode = function(source, options) {
// check for invalid/incomparable values
assert(!base.invalid(source), 'Invalid value')
// encode bound types (ranges)
var boundary = base.bound.getBoundary(source)
if (boundary)
return boundary.encode(source, bytewise)
// encode standard value-typed sorts
var order = base.order
var sort
for (var i = 0, length = order.length; i < length; ++i) {
sort = sorts[order[i]]
if (sort.is(source)) {
// loop over any subsorts defined on sort
// TODO: clean up
var subsorts = sort.sorts || { '': sort }
for (key in subsorts) {
var subsort = subsorts[key]
if (subsort.is(source))
return serialize(subsort, source, options)
}
// source is an unsupported subsort
assert(false, 'Unsupported sort value')
}
}
// no type descriptor found
assert(false, 'Unknown value')
}
//
// core decode logic
//
bytewise.decode = function (buffer, options) {
// attempt to decode string input using configurable codec
if (typeof buffer === 'string') {
buffer = bytewise.stringCodec.encode(buffer)
}
assert(!buffer || !buffer.undecodable, 'Encoded value not decodable')
var byte = buffer[0]
var type = bytewise.getType(byte)
assert(type, 'Invalid encoding: ' + buffer)
// if type provides a decoder it is passed the base type system as second arg
var codec = type.codec
if (codec) {
var decoded = codec.decode(buffer.slice(1), bytewise)
if (options && options.nested && codec.unescape)
decoded = codec.unescape(decoded)
return postDecode(decoded, options)
}
// nullary types without a codec must provide a value for their decoded form
assert('value' in type, 'Unsupported encoding: ' + buffer)
return postDecode(type.value, options)
}
//
// process top level
//
function postEncode(encoded, options) {
if (options === null)
return encoded
return bytewise.postEncode(encoded, options)
}
//
// invoked after encoding with encoded buffer instance
//
bytewise.postEncode = function (encoded, options) {
// override buffer toString method to default to hex to help coercion issues
// TODO: just return pure buffer, do this toString hackery in bytewise
encoded.toString = function (encoding) {
if (!encoding)
return bytewise.stringCodec.decode(encoded)
return Buffer.prototype.toString.apply(encoded, arguments)
}
return encoded
}
function postDecode(decoded, options) {
if (options === null)
return decoded
return bytewise.postDecode(decoded, options)
}
//
// invoked after decoding with decoded value
//
bytewise.postDecode = function (decoded, options) {
return decoded
}
//
// registry mapping byte prefixes to type descriptors
//
var PREFIX_REGISTRY
function registerType(type) {
var byte = type && type.byte
if (byte == null)
return
if (byte in PREFIX_REGISTRY)
assert.deepEqual(type, PREFIX_REGISTRY[byte], 'Duplicate prefix: ' + byte)
PREFIX_REGISTRY[type.byte] = type
}
function registerTypes(types) {
for (var key in types) {
registerType(types[key])
}
}
//
// look up type descriptor associated with a given byte prefix
//
bytewise.getType = function (byte) {
// construct and memoize byte prefix registry on first run
if (!PREFIX_REGISTRY) {
PREFIX_REGISTRY = {}
// register sorts
var sort
for (var key in sorts) {
sort = sorts[key]
// if sort has subsorts register these instead
sort.sorts ? registerTypes(sort.sorts) : registerType(sort)
}
}
return PREFIX_REGISTRY[byte]
}
bytewise.buffer = true
bytewise.stringCodec = codecs.HEX
bytewise.type = 'bytewise-core'