@ton.js/core
Version:
TonWeb - JavaScript API for TON blockchain
343 lines • 10.7 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BitString = void 0;
const bn_js_1 = __importDefault(require("bn.js"));
const text_encoding_1 = require("../utils/text-encoding");
const common_1 = require("../utils/common");
class BitString {
constructor(
/**
* A length of bit string in bits.
*
* @todo: length shouldn't be public and mutable,
* but this is required by clone() method
*/
length) {
this.length = length;
// @todo: rename and make this private
this.array = Uint8Array.from({
length: Math.ceil(this.length / 8)
}, () => 0);
// @todo: make this private
this.cursor = 0;
}
/**
* Returns number of unfilled bits in the bit-string.
*/
getFreeBits() {
return this.length - this.cursor;
}
/**
* Returns number of filled bits in the bit-string.
*/
getUsedBits() {
return this.cursor;
}
/**
* Returns number of bytes actually used by the bit-string.
* Rounds up to a whole byte.
*/
getUsedBytes() {
return Math.ceil(this.cursor / 8);
}
/**
* Returns the bit value at the specified index
* in the bit-string.
*/
get(index) {
return (this.array[(index / 8) | 0] & (1 << (7 - (index % 8)))) > 0;
}
/**
* Sets the bit value to one at the specified index.
*
* @todo: should rename this method to `set()`
*/
on(index) {
this.checkIndexOrThrow(index);
this.array[(index / 8) | 0] |= 1 << (7 - (index % 8));
}
/**
* Sets the bit value to zero at the specified index.
*
* @todo: should rename this method to `clear()`
*/
off(index) {
this.checkIndexOrThrow(index);
this.array[(index / 8) | 0] &= ~(1 << (7 - (index % 8)));
}
/**
* Toggles the bit value at the specified index,
* turns one into zero and zero into one.
*/
toggle(index) {
this.checkIndexOrThrow(index);
this.array[(index / 8) | 0] ^= 1 << (7 - (index % 8));
}
/**
* Iterates the bit-string and calls the specified
* user function for each bit, passing in the bit value.
*
* @todo: implement the iterator protocol
* by using the generator function
*/
forEach(callback) {
const max = this.cursor;
for (let i = 0; i < max; i++) {
callback(this.get(i));
}
}
/**
* Writes the specified bit value to the bit-string
* at the current index and advances the current index
* cursor.
*/
writeBit(value) {
if (value && value > 0) {
this.on(this.cursor);
}
else {
this.off(this.cursor);
}
this.cursor++;
}
/**
* Writes the specified array of bit values to the
* bit-string, starting at the current index and advances
* the current index cursor by the number of bits written.
*/
writeBitArray(values) {
for (let i = 0; i < values.length; i++) {
this.writeBit(values[i]);
}
}
/**
* Writes the specified unsigned integer of the specified
* length in bits to the bit-string, starting at the
* current index and advances the current index cursor
* by the number of bits written.
*/
writeUint(value, bitLength) {
value = new bn_js_1.default(value);
if (bitLength === 0 ||
(value.toString(2).length > bitLength)) {
if (value.isZero())
return;
throw Error(`Specified bit-length: ${bitLength} is ` +
`too small for the specified number: ${value}`);
}
const numberString = value.toString(2, bitLength);
for (let i = 0; i < bitLength; i++) {
this.writeBit(numberString[i] === '1');
}
}
/**
* Writes the specified signed integer of the specified
* length in bits to the bit-string, starting at the
* current index and advances the current index cursor
* by the number of bits written.
*/
writeInt(value, bitLength) {
value = new bn_js_1.default(value);
if (bitLength === 1) {
if (value.eqn(-1)) {
this.writeBit(true);
return;
}
if (value.isZero()) {
this.writeBit(false);
return;
}
throw Error('Specified bit-length is too small ' +
'for the specified number');
}
else {
if (value.isNeg()) {
this.writeBit(true);
const b = new bn_js_1.default(2);
const nb = b.pow(new bn_js_1.default(bitLength - 1));
this.writeUint(nb.add(value), bitLength - 1);
}
else {
this.writeBit(false);
this.writeUint(value, bitLength - 1);
}
}
}
/**
* Writes the specified unsigned 8-bit integer to the
* bit-string, starting at the current index and advances
* the current index cursor by the number of bits written.
*/
writeUint8(value) {
this.writeUint(value, 8);
}
/**
* Writes the specified array of the unsigned 8-bit integers
* to the bit-string, starting at the current index and advances
* the current index cursor by the number of bits written.
*/
writeBytes(values) {
for (const value of values) {
this.writeUint8(value);
}
}
/**
* Represents the specified multibyte string as bytes and writes
* them to the bit-string, starting at the current index and
* advances the current index cursor by the number of bits written.
*/
writeString(text) {
this.writeBytes((0, text_encoding_1.stringToBytes)(text));
}
/**
* Writes the specified amount in nanograms to the
* bit-string, starting at the current index and advances
* the current index cursor by the number of bits written.
*/
writeGrams(nanograms) {
nanograms = new bn_js_1.default(nanograms);
if (nanograms.isZero()) {
this.writeUint(0, 4);
}
else {
const length = Math.ceil((nanograms.toString(16).length) / 2);
this.writeUint(length, 4);
this.writeUint(nanograms, length * 8);
}
}
/**
* Writes the specified TON amount in nanotons to the
* bit-string, starting at the current index and advances
* the current index cursor by the number of bits written.
*/
writeCoins(nanotons) {
return this.writeGrams(nanotons);
}
/**
* Writes the specified address to the bit-string,
* starting at the current index and advances the
* current index cursor by the number of bits written.
*/
writeAddress(address) {
// addr_none$00 = MsgAddressExt;
// addr_std$10 anycast:(Maybe Anycast)
// workchain_id:int8 address:uint256 = MsgAddressInt;
if (!address) {
this.writeUint(0, 2);
}
else {
this.writeUint(2, 2);
this.writeUint(0, 1); // TODO split addresses (anycast)
this.writeInt(address.wc, 8);
this.writeBytes(address.hashPart);
}
}
/**
* Appends the specified bit-string to the bit-string,
* starting at the current index and advances the
* current index cursor by the number of bits written.
*/
writeBitString(bitString) {
bitString.forEach(bit => this.writeBit(bit));
}
/**
* Creates a cloned instance of the bit-string.
*/
clone() {
const bitString = new BitString(0);
bitString.array = this.array.slice(0);
bitString.length = this.length;
bitString.cursor = this.cursor;
return bitString;
}
/**
* Returns the bit-string represented as HEX-string.
*/
toString() {
return this.toHex();
}
/**
* @todo: provide meaningful method description
*/
getTopUppedArray() {
const ret = this.clone();
let tu = Math.ceil(ret.cursor / 8) * 8 - ret.cursor;
if (tu > 0) {
tu = tu - 1;
ret.writeBit(true);
while (tu > 0) {
tu = tu - 1;
ret.writeBit(false);
}
}
ret.array = ret.array.slice(0, Math.ceil(ret.cursor / 8));
return ret.array;
}
/**
* Returns the bit-string represented as HEX-string (like in Fift).
*/
toHex() {
if (this.cursor % 4 === 0) {
const s = (0, common_1.bytesToHex)(this.array.slice(0, Math.ceil(this.cursor / 8))).toUpperCase();
if (this.cursor % 8 === 0) {
return s;
}
else {
// @todo: don't use non-standard `substr()` function,
// use slice() instead?
return s.substr(0, s.length - 1);
}
}
else {
const temp = this.clone();
temp.writeBit(1);
while (temp.cursor % 4 !== 0) {
temp.writeBit(0);
}
const hex = temp.toHex().toUpperCase();
return hex + '_';
}
}
/**
* Sets this cell data to match provided topUppedArray.
*
* @todo: provide a more meaningful method description
*/
setTopUppedArray(bytes, fulfilledBytes = true) {
this.length = bytes.length * 8;
this.array = bytes;
this.cursor = this.length;
if (fulfilledBytes || !this.length) {
return;
}
else {
let foundEndBit = false;
for (let c = 0; c < 7; c++) {
this.cursor -= 1;
if (this.get(this.cursor)) {
foundEndBit = true;
this.off(this.cursor);
break;
}
}
if (!foundEndBit) {
throw new Error('Incorrect TopUppedArray');
}
}
}
/**
* Checks if the specified index is allowed for
* the bit string, throws error in case of overflow.
*/
checkIndexOrThrow(index) {
// @todo: probably off-by-one error
if (index > this.length) {
throw Error('BitString overflow');
}
}
}
exports.BitString = BitString;
//# sourceMappingURL=bit-string.js.map