All files byte-table-builder.ts

100% Statements 40/40
87.5% Branches 14/16
100% Functions 2/2
100% Lines 39/39

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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  1x   1x                   1x           5x 5x 5x 5x 18x 18x               18x 9x 5x 5x 5x 5x 5x     18x 18x 18x 13x   5x                 1x         5x 5x     5x 16x   4x     12x 12x 4x 4x 4x     4x 4x 4x 4x               4x       8x     5x    
import { ProtoTable, ByteShiftProtoTable } from './ProtoTable';
import { byteMap, BINARY } from './types';
 
const SIZE_UNKNOWN = -1;
 
/**
 * Computes byte shift protocol table for static and dynamic types.
 * For dynamic types it reads size from a supplementary UInt32BE field.
 * @param { BinaryMessage } msg0 - binary message.
 * @param { ProtoTable } protoTable - protocol table.
 * @param readAsNumber - binary reader.
 * @param slice - binary slicer.
 */
export function fromBinary<BinaryMessage>(
    msg0: BinaryMessage,
    protoTable: ProtoTable,
    readAsNumber: (m: BinaryMessage, type: string, size: number) => number,
    slice: (m: BinaryMessage, start: number, end: number) => BinaryMessage
): ByteShiftProtoTable {
    let shift: number = 0;
    let size_before:  number = 0;
    let byteShift: ByteShiftProtoTable = [];
    for (let [index, [name, type, origin]] of protoTable.entries()) {
        const isStatic = byteMap.has(type);
        let size: number = isStatic ? byteMap.get(type): SIZE_UNKNOWN;
        /**
         * Example of dynamic:
         * [...
         *  [ 'requestId_SIZE', 'UInt32BE' ],
         *  [ 'requestId',      'requestId_SIZE',   'String' ],
         * ...]
         */
        for(let i = index - 1; size === SIZE_UNKNOWN && i >= 0; i--) {
            if(protoTable[i][0] === type) {
                const msg_shift = byteShift[i][3];
                const msg_size  = byteShift[i][2];
                const msg_type  = byteShift[i][1];
                const msg_slice = slice(msg0, msg_shift, msg_shift + msg_size);
                size = readAsNumber(msg_slice, msg_type, msg_size);
            }
        }
        shift += size_before;
        size_before = size;
        if (origin) byteShift.push([name, origin, size, shift]);
        else        byteShift.push([name, type,   size, shift]);
    }
    return byteShift;
}
 
/**
 * Computes byte table for JavaScript object.
 * @param { Object } obj - target object to be binarified.
 * @param { ProtoTable } protoTable - protocol table.
 * @param { Function } dynamicToBinary - function to convert and calculate dynamic's binary size.
 */
export function toBinary(
    obj: any,
    protoTable: ProtoTable,
    dynamicToBinary: (type: string, val: any) => { byteLength: number, length: number }
) {
    let n = protoTable.length;
    let table = new Array(n).fill([]);
    // Traverse from the end, because for dynamic types
    // companion fields with size usually occur first.
    while (n --> 0) {
        if(table[n].length !== 0) {
            // Non-empty means that it's been processed.
            continue;
        }
 
        const [ fieldName, type, dynamic ] = protoTable[n];
        if (dynamic) {
            const binary = dynamicToBinary(dynamic, obj[fieldName]);
            const dynamicSize = type !== 'Binary' ? binary.byteLength: binary.length;
            table[n] = [ BINARY, dynamicSize, binary ];
 
            // Find companion field and write binary size.
            let j = n; 
            while (j --> 0) {
                Eif (protoTable[j][0] === type) {
                    table[j] = [
                        // Type
                        protoTable[j][1], 
                        // Size
                        byteMap.get(protoTable[j][1]), 
                        // Value
                        dynamicSize
                    ];
                    j = 0;
                }
            }
        } else {
            table[n] = [ type, byteMap.get(type), obj[fieldName] ];
        }
    }
    return table;
}