starpc 0.17.0 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,7 @@ export { Packet, CallStart, CallData } from './rpcproto.pb.js';
8
8
  export { Mux, StaticMux, createMux } from './mux.js';
9
9
  export { BroadcastChannelDuplex, newBroadcastChannelDuplex, BroadcastChannelConn, } from './broadcast-channel.js';
10
10
  export { MessagePortIterable, newMessagePortIterable, MessagePortConn, } from './message-port.js';
11
- export { MessageDefinition, DecodeMessageTransform, buildDecodeMessageTransform, EncodeMessageTransform, buildEncodeMessageTransform, } from './message.js';
11
+ export { MessageDefinition, DecodeMessageTransform, buildDecodeMessageTransform, EncodeMessageTransform, buildEncodeMessageTransform, memoProto, memoProtoDecode, } from './message.js';
12
12
  export { ValueCtr } from './value-ctr.js';
13
13
  export { OpenStreamCtr } from './open-stream-ctr.js';
14
14
  export { writeToPushable } from './pushable';
@@ -7,7 +7,7 @@ export { Packet, CallStart, CallData } from './rpcproto.pb.js';
7
7
  export { StaticMux, createMux } from './mux.js';
8
8
  export { BroadcastChannelDuplex, newBroadcastChannelDuplex, BroadcastChannelConn, } from './broadcast-channel.js';
9
9
  export { MessagePortIterable, newMessagePortIterable, MessagePortConn, } from './message-port.js';
10
- export { buildDecodeMessageTransform, buildEncodeMessageTransform, } from './message.js';
10
+ export { buildDecodeMessageTransform, buildEncodeMessageTransform, memoProto, memoProtoDecode, } from './message.js';
11
11
  export { ValueCtr } from './value-ctr.js';
12
12
  export { OpenStreamCtr } from './open-stream-ctr.js';
13
13
  export { writeToPushable } from './pushable';
@@ -1,10 +1,13 @@
1
1
  import * as pbjs from 'protobufjs/minimal';
2
2
  import type { Source } from 'it-stream-types';
3
3
  export interface MessageDefinition<T> {
4
+ create(msg?: Partial<T>): T;
4
5
  encode(message: T, writer?: pbjs.Writer): pbjs.Writer;
5
6
  decode(input: pbjs.Reader | Uint8Array, length?: number): T;
6
7
  }
8
+ export declare function memoProto<T>(def: MessageDefinition<T>): (msg: Partial<T>) => Uint8Array;
9
+ export declare function memoProtoDecode<T>(def: MessageDefinition<T>): (msg: Uint8Array) => T;
7
10
  export type DecodeMessageTransform<T> = (source: Source<Uint8Array | Uint8Array[]>) => AsyncIterable<T>;
8
- export declare function buildDecodeMessageTransform<T>(def: MessageDefinition<T>): DecodeMessageTransform<T>;
11
+ export declare function buildDecodeMessageTransform<T>(def: MessageDefinition<T>, memoize?: boolean): DecodeMessageTransform<T>;
9
12
  export type EncodeMessageTransform<T> = (source: Source<T | T[]>) => AsyncIterable<Uint8Array>;
10
- export declare function buildEncodeMessageTransform<T>(def: MessageDefinition<T>): EncodeMessageTransform<T>;
13
+ export declare function buildEncodeMessageTransform<T>(def: MessageDefinition<T>, memoize?: boolean): EncodeMessageTransform<T>;
@@ -1,31 +1,53 @@
1
+ import memoize from 'memoize-one';
2
+ // memoProto returns a function that encodes the message and caches the result.
3
+ export function memoProto(def) {
4
+ return memoize((msg) => {
5
+ return def.encode(def.create(msg)).finish();
6
+ });
7
+ }
8
+ // memoProtoDecode returns a function that decodes the message and caches the result.
9
+ export function memoProtoDecode(def) {
10
+ return memoize((msg) => {
11
+ return def.decode(msg);
12
+ });
13
+ }
1
14
  // buildDecodeMessageTransform builds a source of decoded messages.
2
- export function buildDecodeMessageTransform(def) {
15
+ //
16
+ // set memoize if you expect to repeatedly see the same message.
17
+ export function buildDecodeMessageTransform(def, memoize) {
18
+ const decode = memoize ? memoProtoDecode(def) : def.decode.bind(def);
3
19
  // decodeMessageSource unmarshals and async yields encoded Messages.
4
20
  return async function* decodeMessageSource(source) {
5
21
  for await (const pkt of source) {
6
22
  if (Array.isArray(pkt)) {
7
23
  for (const p of pkt) {
8
- yield* [def.decode(p)];
24
+ yield* [decode(p)];
9
25
  }
10
26
  }
11
27
  else {
12
- yield* [def.decode(pkt)];
28
+ yield* [decode(pkt)];
13
29
  }
14
30
  }
15
31
  };
16
32
  }
17
33
  // buildEncodeMessageTransform builds a source of decoded messages.
18
- export function buildEncodeMessageTransform(def) {
34
+ // set memoize if you expect to repeatedly encode the same message.
35
+ export function buildEncodeMessageTransform(def, memoize) {
36
+ const encode = memoize
37
+ ? memoProto(def)
38
+ : (msg) => {
39
+ return def.encode(msg).finish();
40
+ };
19
41
  // encodeMessageSource encodes messages to byte arrays.
20
42
  return async function* encodeMessageSource(source) {
21
43
  for await (const pkt of source) {
22
44
  if (Array.isArray(pkt)) {
23
45
  for (const p of pkt) {
24
- yield* [def.encode(p).finish()];
46
+ yield* [encode(p)];
25
47
  }
26
48
  }
27
49
  else {
28
- yield* [def.encode(pkt).finish()];
50
+ yield* [encode(pkt)];
29
51
  }
30
52
  }
31
53
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starpc",
3
- "version": "0.17.0",
3
+ "version": "0.17.1",
4
4
  "description": "Streaming protobuf RPC service protocol over any two-way channel.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -36,7 +36,7 @@
36
36
  "build": "rimraf ./dist && tsc --project tsconfig.build.json --outDir ./dist/",
37
37
  "check": "npm run typecheck",
38
38
  "typecheck": "tsc --noEmit",
39
- "deps": "depcheck --ignores 'bufferutil,utf-8-validate,ts-proto,@aperturerobotics/ts-common'",
39
+ "deps": "depcheck --ignores 'bufferutil,utf-8-validate,ts-proto,rimraf,@aperturerobotics/ts-common'",
40
40
  "codegen": "npm run gen",
41
41
  "ci": "npm run build && npm run lint:js && npm run lint:go",
42
42
  "format": "prettier --write './{srpc,echo,e2e,integration,rpcstream}/**/(*.ts|*.tsx|*.html|*.css)'",
@@ -88,6 +88,7 @@
88
88
  "it-stream-types": "^1.0.5",
89
89
  "it-ws": "^5.0.6",
90
90
  "long": "^5.2.1",
91
+ "memoize-one": "^6.0.0",
91
92
  "patch-package": "^6.5.1",
92
93
  "protobufjs": "^7.1.2",
93
94
  "uint8arraylist": "^2.4.3",
package/srpc/index.ts CHANGED
@@ -22,6 +22,8 @@ export {
22
22
  buildDecodeMessageTransform,
23
23
  EncodeMessageTransform,
24
24
  buildEncodeMessageTransform,
25
+ memoProto,
26
+ memoProtoDecode,
25
27
  } from './message.js'
26
28
  export { ValueCtr } from './value-ctr.js'
27
29
  export { OpenStreamCtr } from './open-stream-ctr.js'
package/srpc/message.ts CHANGED
@@ -1,23 +1,49 @@
1
1
  import * as pbjs from 'protobufjs/minimal'
2
2
  import type { Source } from 'it-stream-types'
3
+ import memoize from 'memoize-one'
3
4
 
4
5
  // MessageDefinition represents a ts-proto message definition.
5
6
  export interface MessageDefinition<T> {
7
+ // create creates a full message from a partial and/or no message.
8
+ create(msg?: Partial<T>): T
6
9
  // encode encodes the message and returns writer.
7
10
  encode(message: T, writer?: pbjs.Writer): pbjs.Writer
8
11
  // decode decodes the message from the reader
9
12
  decode(input: pbjs.Reader | Uint8Array, length?: number): T
10
13
  }
11
14
 
15
+ // memoProto returns a function that encodes the message and caches the result.
16
+ export function memoProto<T>(
17
+ def: MessageDefinition<T>
18
+ ): (msg: Partial<T>) => Uint8Array {
19
+ return memoize((msg: Partial<T>): Uint8Array => {
20
+ return def.encode(def.create(msg)).finish()
21
+ })
22
+ }
23
+
24
+ // memoProtoDecode returns a function that decodes the message and caches the result.
25
+ export function memoProtoDecode<T>(
26
+ def: MessageDefinition<T>
27
+ ): (msg: Uint8Array) => T {
28
+ return memoize((msg: Uint8Array): T => {
29
+ return def.decode(msg)
30
+ })
31
+ }
32
+
12
33
  // DecodeMessageTransform decodes messages to objects.
13
34
  export type DecodeMessageTransform<T> = (
14
35
  source: Source<Uint8Array | Uint8Array[]>
15
36
  ) => AsyncIterable<T>
16
37
 
17
38
  // buildDecodeMessageTransform builds a source of decoded messages.
39
+ //
40
+ // set memoize if you expect to repeatedly see the same message.
18
41
  export function buildDecodeMessageTransform<T>(
19
- def: MessageDefinition<T>
42
+ def: MessageDefinition<T>,
43
+ memoize?: boolean
20
44
  ): DecodeMessageTransform<T> {
45
+ const decode = memoize ? memoProtoDecode(def) : def.decode.bind(def)
46
+
21
47
  // decodeMessageSource unmarshals and async yields encoded Messages.
22
48
  return async function* decodeMessageSource(
23
49
  source: Source<Uint8Array | Uint8Array[]>
@@ -25,10 +51,10 @@ export function buildDecodeMessageTransform<T>(
25
51
  for await (const pkt of source) {
26
52
  if (Array.isArray(pkt)) {
27
53
  for (const p of pkt) {
28
- yield* [def.decode(p)]
54
+ yield* [decode(p)]
29
55
  }
30
56
  } else {
31
- yield* [def.decode(pkt)]
57
+ yield* [decode(pkt)]
32
58
  }
33
59
  }
34
60
  }
@@ -40,9 +66,17 @@ export type EncodeMessageTransform<T> = (
40
66
  ) => AsyncIterable<Uint8Array>
41
67
 
42
68
  // buildEncodeMessageTransform builds a source of decoded messages.
69
+ // set memoize if you expect to repeatedly encode the same message.
43
70
  export function buildEncodeMessageTransform<T>(
44
- def: MessageDefinition<T>
71
+ def: MessageDefinition<T>,
72
+ memoize?: boolean
45
73
  ): EncodeMessageTransform<T> {
74
+ const encode = memoize
75
+ ? memoProto(def)
76
+ : (msg: T): Uint8Array => {
77
+ return def.encode(msg).finish()
78
+ }
79
+
46
80
  // encodeMessageSource encodes messages to byte arrays.
47
81
  return async function* encodeMessageSource(
48
82
  source: Source<T | T[]>
@@ -50,10 +84,10 @@ export function buildEncodeMessageTransform<T>(
50
84
  for await (const pkt of source) {
51
85
  if (Array.isArray(pkt)) {
52
86
  for (const p of pkt) {
53
- yield* [def.encode(p).finish()]
87
+ yield* [encode(p)]
54
88
  }
55
89
  } else {
56
- yield* [def.encode(pkt).finish()]
90
+ yield* [encode(pkt)]
57
91
  }
58
92
  }
59
93
  }