-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathencode.js
More file actions
169 lines (156 loc) · 4.25 KB
/
Copy pathencode.js
File metadata and controls
169 lines (156 loc) · 4.25 KB
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
const varint = require('fast-varint')
const { TAG_SIZE, TAG_MASK } = require('./constants')
const {
STRING,
BUFFER,
INT,
DOUBLE,
ARRAY,
OBJECT,
BOOLNULL,
ALREADY_BIPF,
} = require('./constants')
//sets buffer, and returns length
const encoders = [
function String(string, buffer, start) {
return buffer.write(string, start)
},
function Buffer(b, buffer, start) {
b.copy(buffer, start, 0, b.length)
return b.length
},
function Integer(i, buffer, start) {
buffer.writeInt32LE(i, start)
return 4
},
function Double(d, buffer, start) {
buffer.writeDoubleLE(d, start)
return 8
},
function Array(a, buffer, start) {
let p = start
for (let i = 0; i < a.length; i++) {
p += encode(a[i], buffer, p)
}
return p - start
},
function Object(o, buffer, start) {
let p = start
for (let k in o) {
//TODO filter non json types
p += encode(k, buffer, p)
p += encode(o[k], buffer, p)
}
return p - start
},
function Boolean(b, buffer, start) {
if (b !== null) buffer[start] = b === false ? 0 : b === true ? 1 : 2 // undefined
return b === null ? 0 : 1
},
]
var encodingLengthers = [
function String(string) {
return Buffer.byteLength(string)
},
function Buffer(b) {
return b.length
},
function Integer(i) {
return 4
},
function Double(d) {
return 8
},
function Array(a) {
var bytes = 0
for (var i = 0; i < a.length; i++) bytes += encodingLength(a[i])
return bytes
},
function Object(o) {
var bytes = 0
for (var k in o) bytes += encodingLength(k) + encodingLength(o[k])
return bytes
},
function boolnull(b, buffer, start) {
return b === null ? 0 : 1 // encode null as zero length!
},
]
function getType(value) {
if ('string' === typeof value || value instanceof Date) return STRING
else if (Buffer.isBuffer(value)) {
if (value._IS_BIPF_ENCODED) return ALREADY_BIPF
else return BUFFER
} else if (Number.isInteger(value) && Math.abs(value) <= 2147483647)
return INT
else if ('number' === typeof value && Number.isFinite(value))
//do not support Infinity or NaN (because JSON)
return DOUBLE
else if (Array.isArray(value)) return ARRAY
else if (value && 'object' === typeof value) return OBJECT
else if ('boolean' === typeof value || null == value) return BOOLNULL //boolean, null, undefined
}
function encodingLength(value) {
const type = getType(value)
if (type === void 0) throw new Error('unknown type: ' + JSON.stringify(value))
if (type === ALREADY_BIPF) return value.length
const len = encodingLengthers[type](value)
return varint.encodingLength(len << TAG_SIZE) + len
}
function encode(value, buffer, start, _len) {
start = start | 0
const type = getType(value)
if (type === void 0) throw new Error('unknown type: ' + JSON.stringify(value))
if (type === ALREADY_BIPF) {
value.copy(buffer, start, 0, value.length)
return value.length
}
const len = _len === undefined ? encodingLengthers[type](value) : _len
// if(!buffer)
// buffer = Buffer.allocUnsafe(len)
//throw new Error('buffer must be provided')
varint.encode((len << TAG_SIZE) | type, buffer, start)
const bytes = varint.encode.bytes
return encoders[type](value, buffer, start + bytes) + bytes
}
function encodeIdempotent(value, buffer, start) {
const len = encode(value, buffer, start)
buffer._IS_BIPF_ENCODED = true
return len
}
function markIdempotent(buffer) {
buffer._IS_BIPF_ENCODED = true
return buffer
}
function isIdempotent(buffer) {
return !!buffer._IS_BIPF_ENCODED
}
function getEncodedLength(buffer, start) {
return varint.decode(buffer, start) >> TAG_SIZE
}
function getEncodedType(buffer, start) {
return varint.decode(buffer, start) & TAG_MASK
}
function allocAndEncode(value) {
const len = encodingLength(value)
const buffer = Buffer.allocUnsafe(len)
encode(value, buffer, 0)
return buffer
}
function allocAndEncodeIdempotent(value) {
const len = encodingLength(value)
const buffer = Buffer.allocUnsafe(len)
encodeIdempotent(value, buffer, 0)
return buffer
}
module.exports = {
encode,
encodeIdempotent,
markIdempotent,
isIdempotent,
getType,
getEncodedLength,
getEncodedType,
encodingLength,
allocAndEncode,
allocAndEncodeIdempotent,
}