Files: 6b34c4eb25f5a0d003d2f5a603b19ae91bf6b375 / treeNode.js
2926 bytesRaw
1 | const leb128 = require('leb128').unsigned |
2 | const LebStream = require('leb128/stream') |
3 | const Uint1Array = require('uint1array') |
4 | const HASH_LEN = 20 |
5 | |
6 | function toTypedArray (array) { |
7 | return new Uint1Array(new Uint8Array(array).buffer) |
8 | } |
9 | |
10 | // helper functions for nodes |
11 | const EXTENSION = exports.EXTENSION = 0 |
12 | const LBRANCH = exports.LBRANCH = 1 |
13 | const RBRANCH = exports.RBRANCH = 2 |
14 | const VALUE = exports.VALUE = 3 |
15 | |
16 | exports.setBranch = function (node, branch) { |
17 | node['/'][LBRANCH] = branch[0] |
18 | node['/'][RBRANCH] = branch[1] |
19 | } |
20 | |
21 | exports.getBranch = function (node) { |
22 | return node['/'].slice(LBRANCH, LBRANCH + 2) |
23 | } |
24 | |
25 | exports.getValue = function (node) { |
26 | return node['/'][VALUE] |
27 | } |
28 | |
29 | exports.deleteValue = function (node) { |
30 | delete node['/'][VALUE] |
31 | } |
32 | |
33 | exports.getExtension = function (node) { |
34 | if (node['/'][EXTENSION]) { |
35 | const len = node['/'][EXTENSION][0] |
36 | const extension = toTypedArray(node['/'][EXTENSION][1]) |
37 | return extension.subarray(0, len) |
38 | } else { |
39 | return [] |
40 | } |
41 | } |
42 | |
43 | exports.setExtension = function (node, ex) { |
44 | if (ex && ex.length) { |
45 | node['/'][EXTENSION] = [ex.length, Buffer.from(ex.buffer)] |
46 | } else { |
47 | delete node['/'][EXTENSION] |
48 | } |
49 | } |
50 | |
51 | exports.setValue = function (node, val) { |
52 | node['/'][VALUE] = val |
53 | } |
54 | |
55 | exports.isEmpty = function (node) { |
56 | const branch = exports.getBranch(node) |
57 | return !node['/'][EXTENSION] && !branch[0] && !branch[1] && node['/'][VALUE] === undefined |
58 | } |
59 | |
60 | // PREFIX := | LBP | RBP | EXT | LB | RB | VALUE | |
61 | // NODE := | PREFIX | LEN | PAYLOAD |
62 | const MASK = { |
63 | EXTENSION: 8, |
64 | LBRANCH: 4, |
65 | RBRANCH: 2, |
66 | VALUE: 1 |
67 | } |
68 | |
69 | exports.encode = function (node, prefix = 0, encodeLen = false) { |
70 | let encoded = [] |
71 | const ext = node[EXTENSION] |
72 | if (ext) { |
73 | const len = leb128.encode(ext[0]) |
74 | encoded.push(len) |
75 | encoded.push(ext[1]) |
76 | prefix += MASK.EXTENSION |
77 | } |
78 | |
79 | const lb = node[LBRANCH] |
80 | if (lb) { |
81 | encoded.push(lb['/']) |
82 | prefix += MASK.LBRANCH |
83 | } |
84 | |
85 | const rb = node[RBRANCH] |
86 | if (rb) { |
87 | encoded.push(rb['/']) |
88 | prefix += MASK.RBRANCH |
89 | } |
90 | |
91 | const val = node[VALUE] |
92 | if (val !== undefined) { |
93 | encoded.push(val) |
94 | prefix += MASK.VALUE |
95 | } |
96 | |
97 | encoded.unshift(Buffer.from([prefix])) |
98 | encoded = Buffer.concat(encoded) |
99 | if (encodeLen) { |
100 | const len = leb128.encode(encoded.length) |
101 | encoded = Buffer.concat([len, encoded]) |
102 | } |
103 | return encoded |
104 | } |
105 | |
106 | exports.decode = function (val) { |
107 | const node = [null, null, null] |
108 | const prefix = val[0] |
109 | const lebStream = new LebStream(val.slice(1)) |
110 | |
111 | if (prefix & MASK.EXTENSION) { |
112 | const len = Number(leb128.read(lebStream)) |
113 | const ext = lebStream.read(Math.ceil(len / 8)) |
114 | node[EXTENSION] = [len, ext] |
115 | } |
116 | |
117 | if (prefix & MASK.LBRANCH) { |
118 | node[LBRANCH] = { |
119 | '/': lebStream.read(HASH_LEN) |
120 | } |
121 | } |
122 | |
123 | if (prefix & MASK.RBRANCH) { |
124 | node[RBRANCH] = { |
125 | '/': lebStream.read(HASH_LEN) |
126 | } |
127 | } |
128 | |
129 | if (prefix & MASK.VALUE) { |
130 | node[VALUE] = lebStream.buffer |
131 | } |
132 | return node |
133 | } |
134 |
Built with git-ssb-web