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