diff --git a/src/vs/base/common/buffer.ts b/src/vs/base/common/buffer.ts index b3f2fd17177..f5408cded9f 100644 --- a/src/vs/base/common/buffer.ts +++ b/src/vs/base/common/buffer.ts @@ -94,8 +94,14 @@ export class VSBuffer { return new VSBuffer(this.buffer.subarray(start!/*bad lib.d.ts*/, end)); } - set(array: VSBuffer, offset?: number): void { - this.buffer.set(array.buffer, offset); + set(array: VSBuffer, offset?: number): void; + set(array: Uint8Array, offset?: number): void; + set(array: VSBuffer | Uint8Array, offset?: number): void { + if (array instanceof VSBuffer) { + this.buffer.set(array.buffer, offset); + } else { + this.buffer.set(array, offset); + } } readUInt32BE(offset: number): number { diff --git a/src/vs/workbench/api/common/shared/semanticTokensDto.ts b/src/vs/workbench/api/common/shared/semanticTokensDto.ts index 3e4067c6ad0..d53e18445c1 100644 --- a/src/vs/workbench/api/common/shared/semanticTokensDto.ts +++ b/src/vs/workbench/api/common/shared/semanticTokensDto.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { VSBuffer } from 'vs/base/common/buffer'; +import * as platform from 'vs/base/common/platform'; export interface IFullSemanticTokensDto { id: number; @@ -24,26 +25,45 @@ const enum EncodedSemanticTokensType { Delta = 2 } +function toUint8Array(arr: Uint32Array): Uint8Array { + return new Uint8Array(arr.buffer, arr.byteOffset, arr.length * 4); +} + +function toUint32Array(arr: Uint8Array, byteOffset: number, length: number): Uint32Array { + return new Uint32Array(arr.buffer, arr.byteOffset + byteOffset, length); +} + export function encodeSemanticTokensDto(semanticTokens: ISemanticTokensDto): VSBuffer { + const isLittleEndian = platform.isLittleEndian(); const buff = VSBuffer.alloc(encodeSemanticTokensDtoSize(semanticTokens)); let offset = 0; buff.writeUInt32LE(semanticTokens.id, offset); offset += 4; if (semanticTokens.type === 'full') { - buff.writeUInt8(EncodedSemanticTokensType.Full, offset); offset += 1; + buff.writeUInt32LE(EncodedSemanticTokensType.Full, offset); offset += 4; buff.writeUInt32LE(semanticTokens.data.length, offset); offset += 4; - for (const uint of semanticTokens.data) { - buff.writeUInt32LE(uint, offset); offset += 4; + if (isLittleEndian) { + const uint8Arr = toUint8Array(semanticTokens.data); + buff.set(uint8Arr, offset); offset += uint8Arr.length; + } else { + for (const uint of semanticTokens.data) { + buff.writeUInt32LE(uint, offset); offset += 4; + } } } else { - buff.writeUInt8(EncodedSemanticTokensType.Delta, offset); offset += 1; + buff.writeUInt32LE(EncodedSemanticTokensType.Delta, offset); offset += 4; buff.writeUInt32LE(semanticTokens.deltas.length, offset); offset += 4; for (const delta of semanticTokens.deltas) { buff.writeUInt32LE(delta.start, offset); offset += 4; buff.writeUInt32LE(delta.deleteCount, offset); offset += 4; if (delta.data) { buff.writeUInt32LE(delta.data.length, offset); offset += 4; - for (const uint of delta.data) { - buff.writeUInt32LE(uint, offset); offset += 4; + if (isLittleEndian) { + const uint8Arr = toUint8Array(delta.data); + buff.set(uint8Arr, offset); offset += uint8Arr.length; + } else { + for (const uint of delta.data) { + buff.writeUInt32LE(uint, offset); offset += 4; + } } } else { buff.writeUInt32LE(0, offset); offset += 4; @@ -56,7 +76,7 @@ export function encodeSemanticTokensDto(semanticTokens: ISemanticTokensDto): VSB function encodeSemanticTokensDtoSize(semanticTokens: ISemanticTokensDto): number { let result = 0; result += 4; // id - result += 1; // type + result += 4; // type if (semanticTokens.type === 'full') { result += 4; // data length result += semanticTokens.data.byteLength; @@ -75,14 +95,20 @@ function encodeSemanticTokensDtoSize(semanticTokens: ISemanticTokensDto): number } export function decodeSemanticTokensDto(buff: VSBuffer): ISemanticTokensDto { + const isLittleEndian = platform.isLittleEndian(); let offset = 0; const id = buff.readUInt32LE(offset); offset += 4; - const type: EncodedSemanticTokensType = buff.readUInt8(offset); offset += 1; + const type: EncodedSemanticTokensType = buff.readUInt32LE(offset); offset += 4; if (type === EncodedSemanticTokensType.Full) { const length = buff.readUInt32LE(offset); offset += 4; - const data = new Uint32Array(length); - for (let j = 0; j < length; j++) { - data[j] = buff.readUInt32LE(offset); offset += 4; + let data: Uint32Array; + if (isLittleEndian) { + data = toUint32Array(buff.buffer, offset, length); offset += 4 * length; + } else { + data = new Uint32Array(length); + for (let j = 0; j < length; j++) { + data[j] = buff.readUInt32LE(offset); offset += 4; + } } return { id: id, @@ -98,9 +124,13 @@ export function decodeSemanticTokensDto(buff: VSBuffer): ISemanticTokensDto { const length = buff.readUInt32LE(offset); offset += 4; let data: Uint32Array | undefined; if (length > 0) { - data = new Uint32Array(length); - for (let j = 0; j < length; j++) { - data[j] = buff.readUInt32LE(offset); offset += 4; + if (isLittleEndian) { + data = toUint32Array(buff.buffer, offset, length); offset += 4 * length; + } else { + data = new Uint32Array(length); + for (let j = 0; j < length; j++) { + data[j] = buff.readUInt32LE(offset); offset += 4; + } } } deltas[i] = { start, deleteCount, data }; diff --git a/src/vs/workbench/test/common/api/semanticTokensDto.test.ts b/src/vs/workbench/test/common/api/semanticTokensDto.test.ts index dd58ee04839..3f59943a43b 100644 --- a/src/vs/workbench/test/common/api/semanticTokensDto.test.ts +++ b/src/vs/workbench/test/common/api/semanticTokensDto.test.ts @@ -87,4 +87,24 @@ suite('SemanticTokensDto', () => { }); }); + test('partial array buffer', () => { + const sharedArr = new Uint32Array([ + (1 << 24) + (2 << 16) + (3 << 8) + 4, + 1, 2, 3, 4, 5, (1 << 24) + (2 << 16) + (3 << 8) + 4 + ]); + testRoundTrip({ + id: 12, + type: 'delta', + deltas: [{ + start: 0, + deleteCount: 4, + data: sharedArr.subarray(0, 1) + }, { + start: 15, + deleteCount: 0, + data: sharedArr.subarray(1, sharedArr.length) + }] + }); + }); + });