Skip to content

Commit b900b27

Browse files
committed
Introduce VSBuffer
1 parent 9bb443d commit b900b27

14 files changed

Lines changed: 432 additions & 211 deletions

File tree

src/vs/base/common/buffer.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
export class VSBuffer {
7+
8+
public static alloc(byteLength: number): VSBuffer {
9+
return new VSBuffer(Buffer.allocUnsafe(byteLength));
10+
}
11+
12+
public static wrap(actual: Buffer): VSBuffer {
13+
return new VSBuffer(actual);
14+
}
15+
16+
public static fromString(source: string): VSBuffer {
17+
return new VSBuffer(Buffer.from(source));
18+
}
19+
20+
public static concat(buffers: VSBuffer[], totalLength?: number): VSBuffer {
21+
if (typeof totalLength === 'undefined') {
22+
totalLength = 0;
23+
for (let i = 0, len = buffers.length; i < len; i++) {
24+
totalLength += buffers[i].byteLength;
25+
}
26+
}
27+
28+
const ret = VSBuffer.alloc(totalLength);
29+
let offset = 0;
30+
for (let i = 0, len = buffers.length; i < len; i++) {
31+
const element = buffers[i];
32+
ret.set(element, offset);
33+
offset += element.byteLength;
34+
}
35+
36+
return ret;
37+
}
38+
39+
private readonly _actual: Buffer;
40+
public readonly byteLength: number;
41+
42+
private constructor(buffer: Buffer) {
43+
this._actual = buffer;
44+
this.byteLength = this._actual.byteLength;
45+
}
46+
47+
public toBuffer(): Buffer {
48+
// TODO@Alex: deprecate this usage
49+
return this._actual;
50+
}
51+
52+
public toString(): string {
53+
return this._actual.toString();
54+
}
55+
56+
public slice(start?: number, end?: number): VSBuffer {
57+
return new VSBuffer(this._actual.slice(start, end));
58+
}
59+
60+
public set(array: VSBuffer, offset?: number): void {
61+
this._actual.set(array._actual, offset);
62+
}
63+
64+
public readUint32BE(offset: number): number {
65+
return readUint32BE(this._actual, offset);
66+
}
67+
68+
public writeUint32BE(value: number, offset: number): void {
69+
writeUint32BE(this._actual, value, offset);
70+
}
71+
72+
public readUint8(offset: number): number {
73+
return readUint8(this._actual, offset);
74+
}
75+
76+
public writeUint8(value: number, offset: number): void {
77+
writeUint8(this._actual, value, offset);
78+
}
79+
80+
}
81+
82+
function readUint32BE(source: Uint8Array, offset: number): number {
83+
return (
84+
source[offset] * 2 ** 24
85+
+ source[offset + 1] * 2 ** 16
86+
+ source[offset + 2] * 2 ** 8
87+
+ source[offset + 3]
88+
);
89+
}
90+
91+
function writeUint32BE(destination: Uint8Array, value: number, offset: number): void {
92+
destination[offset + 3] = value;
93+
value = value >>> 8;
94+
destination[offset + 2] = value;
95+
value = value >>> 8;
96+
destination[offset + 1] = value;
97+
value = value >>> 8;
98+
destination[offset] = value;
99+
}
100+
101+
function readUint8(source: Uint8Array, offset: number): number {
102+
return source[offset];
103+
}
104+
105+
function writeUint8(destination: Uint8Array, value: number, offset: number): void {
106+
destination[offset] = value;
107+
}

src/vs/base/parts/ipc/electron-browser/ipc.electron-browser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ import { IPCClient } from 'vs/base/parts/ipc/node/ipc';
88
import { Protocol } from 'vs/base/parts/ipc/node/ipc.electron';
99
import { ipcRenderer } from 'electron';
1010
import { IDisposable } from 'vs/base/common/lifecycle';
11+
import { VSBuffer } from 'vs/base/common/buffer';
1112

1213
export class Client extends IPCClient implements IDisposable {
1314

1415
private protocol: Protocol;
1516

1617
private static createProtocol(): Protocol {
17-
const onMessage = Event.fromNodeEventEmitter<Buffer>(ipcRenderer, 'ipc:message', (_, message: Buffer) => message);
18+
const onMessage = Event.fromNodeEventEmitter<VSBuffer>(ipcRenderer, 'ipc:message', (_, message: Buffer) => VSBuffer.wrap(message));
1819
ipcRenderer.send('ipc:hello');
1920
return new Protocol(ipcRenderer, onMessage);
2021
}

src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@ import { IPCServer, ClientConnectionEvent } from 'vs/base/parts/ipc/node/ipc';
88
import { Protocol } from 'vs/base/parts/ipc/node/ipc.electron';
99
import { ipcMain } from 'electron';
1010
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
11+
import { VSBuffer } from 'vs/base/common/buffer';
1112

1213
interface IIPCEvent {
1314
event: { sender: Electron.WebContents; };
1415
message: Buffer | null;
1516
}
1617

17-
function createScopedOnMessageEvent(senderId: number, eventName: string): Event<Buffer | null> {
18+
function createScopedOnMessageEvent(senderId: number, eventName: string): Event<VSBuffer | null> {
1819
const onMessage = Event.fromNodeEventEmitter<IIPCEvent>(ipcMain, eventName, (event, message) => ({ event, message }));
1920
const onMessageFromSender = Event.filter(onMessage, ({ event }) => event.sender.id === senderId);
20-
return Event.map(onMessageFromSender, ({ message }) => message);
21+
return Event.map(onMessageFromSender, ({ message }) => message ? VSBuffer.wrap(message) : message);
2122
}
2223

2324
export class Server extends IPCServer {
@@ -38,7 +39,7 @@ export class Server extends IPCServer {
3839
const onDidClientReconnect = new Emitter<void>();
3940
Server.Clients.set(id, toDisposable(() => onDidClientReconnect.fire()));
4041

41-
const onMessage = createScopedOnMessageEvent(id, 'ipc:message') as Event<Buffer>;
42+
const onMessage = createScopedOnMessageEvent(id, 'ipc:message') as Event<VSBuffer>;
4243
const onDidClientDisconnect = Event.any(Event.signal(createScopedOnMessageEvent(id, 'ipc:disconnect')), onDidClientReconnect.event);
4344
const protocol = new Protocol(webContents, onMessage);
4445

src/vs/base/parts/ipc/node/ipc.cp.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { isRemoteConsoleLog, log } from 'vs/base/common/console';
1414
import { CancellationToken } from 'vs/base/common/cancellation';
1515
import * as errors from 'vs/base/common/errors';
1616
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
17+
import { VSBuffer } from 'vs/base/common/buffer';
1718

1819
/**
1920
* This implementation doesn't perform well since it uses base64 encoding for buffers.
@@ -26,11 +27,11 @@ export class Server<TContext extends string> extends IPCServer<TContext> {
2627
send: r => {
2728
try {
2829
if (process.send) {
29-
process.send(r.toString('base64'));
30+
process.send(r.toBuffer().toString('base64'));
3031
}
3132
} catch (e) { /* not much to do */ }
3233
},
33-
onMessage: Event.fromNodeEventEmitter(process, 'message', msg => Buffer.from(msg, 'base64'))
34+
onMessage: Event.fromNodeEventEmitter(process, 'message', msg => VSBuffer.wrap(Buffer.from(msg, 'base64')))
3435
}, ctx);
3536

3637
process.once('disconnect', () => this.dispose());
@@ -199,7 +200,7 @@ export class Client implements IChannelClient, IDisposable {
199200

200201
this.child = fork(this.modulePath, args, forkOpts);
201202

202-
const onMessageEmitter = new Emitter<Buffer>();
203+
const onMessageEmitter = new Emitter<VSBuffer>();
203204
const onRawMessage = Event.fromNodeEventEmitter(this.child, 'message', msg => msg);
204205

205206
onRawMessage(msg => {
@@ -211,11 +212,11 @@ export class Client implements IChannelClient, IDisposable {
211212
}
212213

213214
// Anything else goes to the outside
214-
onMessageEmitter.fire(Buffer.from(msg, 'base64'));
215+
onMessageEmitter.fire(VSBuffer.wrap(Buffer.from(msg, 'base64')));
215216
});
216217

217218
const sender = this.options.useQueue ? createQueuedSender(this.child) : this.child;
218-
const send = (r: Buffer) => this.child && this.child.connected && sender.send(r.toString('base64'));
219+
const send = (r: VSBuffer) => this.child && this.child.connected && sender.send(r.toBuffer().toString('base64'));
219220
const onMessage = onMessageEmitter.event;
220221
const protocol = { send, onMessage };
221222

src/vs/base/parts/ipc/node/ipc.electron.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,19 @@
55

66
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/node/ipc';
77
import { Event } from 'vs/base/common/event';
8+
import { VSBuffer } from 'vs/base/common/buffer';
89

910
export interface Sender {
1011
send(channel: string, msg: Buffer | null): void;
1112
}
1213

1314
export class Protocol implements IMessagePassingProtocol {
1415

15-
constructor(private sender: Sender, readonly onMessage: Event<Buffer>) { }
16+
constructor(private sender: Sender, readonly onMessage: Event<VSBuffer>) { }
1617

17-
send(message: Buffer): void {
18+
send(message: VSBuffer): void {
1819
try {
19-
this.sender.send('ipc:message', message);
20+
this.sender.send('ipc:message', message.toBuffer());
2021
} catch (e) {
2122
// systems are going down
2223
}

0 commit comments

Comments
 (0)