All files / src/encoders array.ts

100% Statements 42/42
100% Branches 16/16
100% Functions 4/4
100% Lines 40/40

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                    31x   31x 30x 30x 30x   30x 1152x 1152x 1152x 1100x 52x 13x   39x 39x         31x       31x 39x 39x 39x 39x 22x 14x 14x 14x 14x             31x   31x 31x   31x 55x 55x   55x 4x   51x               51x 1155x         31x       28x 28x 28x    
import { EncodeContext } from '../encode';
import { isBooleanType, ValueType } from '../types';
import { detectValue } from '../detectors/index';
 
interface ArrayGroup {
	type: ValueType;
	items: any[];
}
 
function getGroups(value: any[], context: EncodeContext): ArrayGroup[] {
	const groups: ArrayGroup[] = [];
 
	if (value.length) {
		const first = value[0];
		let group: ArrayGroup = { type: detectValue(first, context), items: [first] };
		groups.push(group);
 
		for (let i = 1; i < value.length; i++) {
			const item = value[i];
			const type = detectValue(item, context);
			if (group.type === type) {
				group.items.push(item);
			} else if (isBooleanType(group.type) && isBooleanType(type)) {
				group.items.push(item);
			} else {
				group = { type: detectValue(item, context), items: [item] };
				groups.push(group);
			}
		}
	}
 
	return groups;
}
 
function optimizeGroups(groups: ArrayGroup[]) {
	for (let i = 0; i < groups.length - 1; i++) {
		const j = i + 1;
		const group0 = groups[i];
		const group1 = groups[j];
		if (group0.type === ValueType.ANY || group0.items.length === 1) {
			if (group1.items.length === 1) {
				group0.type = ValueType.ANY;
				group0.items.push(...group1.items);
				groups.splice(j, 1);
				i--;
			}
		}
	}
}
 
export function encodeArrayGroups(value: any[], context: EncodeContext): void {
	const { writer, encoders } = context;
 
	const groups = getGroups(value, context);
	optimizeGroups(groups);
 
	for (const group of groups) {
		writer.writeUintVar(group.type);
		writer.writeUintVar(group.items.length);
 
		if (isBooleanType(group.type)) {
			writer.writeBitset(group.items);
		} else {
			const encodeMethod = encoders.get(group.type);
 
			/* istanbul ignore next */
			if (!encodeMethod) {
				/* istanbul ignore next */
				throw `Encoder method not found for object type: ${group.type} in array encoding`;
			}
 
			for (const item of group.items) {
				encodeMethod(item, context);
			}
		}
	}
 
	writer.writeUintVar(ValueType.END);
}
 
export function encodeArray(value: any[], context: EncodeContext): void {
	const { links } = context;
	links.push(value);
	encodeArrayGroups(value, context);
}