UNPKG

2.14 kBJavaScriptView Raw
1const JSBI = require('jsbi');
2const { assert, format } = require('../util');
3const BaseCoder = require('./BaseCoder');
4const { UINT_BOUND, padBuffer } = require('./util');
5
6class IntegerCoder extends BaseCoder {
7 static from({ type, name }) {
8 const match = type.match(/^(int|uint)([0-9]*)$/);
9 if (!match) {
10 return undefined;
11 }
12
13 const [, label, bits] = match;
14 return new this({
15 name,
16 type: label,
17 signed: !label.startsWith('u'),
18 bits: bits ? parseInt(bits, 10) : undefined,
19 });
20 }
21
22 constructor({ name, type, signed = false, bits = 256 }) {
23 assert(Number.isInteger(bits) && 0 < bits && bits <= 256 && (bits % 8 === 0), {
24 message: 'invalid bits',
25 expect: 'integer && 0<bits<=256 && bits%8==0',
26 got: bits,
27 coder: { name, type, signed },
28 });
29
30 super({ name });
31 this.type = `${type}${bits}`;
32 this.signed = signed;
33 this.size = bits / 8;
34 this.bound = JSBI.leftShift(JSBI.BigInt(1), JSBI.BigInt(bits - (this.signed ? 1 : 0)));
35 }
36
37 /**
38 * @param value {number|JSBI|string}
39 * @return {Buffer}
40 */
41 encode(value) {
42 let number = format.bigInt(value);
43 let twosComplement = number;
44
45 if (this.signed && JSBI.LT(number, JSBI.BigInt(0))) {
46 twosComplement = JSBI.add(number, this.bound);
47 number = JSBI.add(number, UINT_BOUND);
48 }
49
50 assert(JSBI.LE(JSBI.BigInt(0), twosComplement) && JSBI.LT(twosComplement, this.bound), {
51 message: 'bound error',
52 expect: `0<= && <${this.bound}`,
53 got: twosComplement.toString(),
54 coder: this,
55 value,
56 });
57
58 return padBuffer(format.hex(number));
59 }
60
61 /**
62 * @param stream {HexStream}
63 * @return {JSBI}
64 */
65 decode(stream) {
66 let value = format.bigInt(`0x${stream.read(this.size * 2)}`); // 16: read out naked hex string
67
68 if (this.signed && JSBI.GE(value, this.bound)) {
69 const mask = JSBI.leftShift(JSBI.BigInt(1), JSBI.BigInt(this.size * 8));
70 value = JSBI.subtract(value, mask);
71 }
72
73 return value;
74 }
75}
76
77module.exports = IntegerCoder;