From 5e0b35cdb52317d9ed192ff48de7f967fe19e238 Mon Sep 17 00:00:00 2001 From: Timo Stamm Date: Fri, 21 Jun 2024 16:06:10 +0200 Subject: [PATCH] Add mutable registry (#899) --- packages/bundle-size/README.md | 2 +- packages/bundle-size/chart.svg | 4 +- .../protobuf-test/src/create-registry.test.ts | 9 +++ packages/protobuf/src/create-registry.ts | 81 +++++++++++-------- packages/protobuf/src/index.ts | 2 +- packages/protobuf/src/type-registry.ts | 14 ++++ 6 files changed, 75 insertions(+), 37 deletions(-) diff --git a/packages/bundle-size/README.md b/packages/bundle-size/README.md index 91d06a4e3..9f258ddc0 100644 --- a/packages/bundle-size/README.md +++ b/packages/bundle-size/README.md @@ -15,7 +15,7 @@ usually do. We repeat this for an increasing number of files. | code generator | files | bundle size | minified | compressed | |-----------------|----------|------------------------:|-----------------------:|-------------------:| -| protobuf-es | 1 | 79,463 b | 34,300 b | 9,781 b | +| protobuf-es | 1 | 79,463 b | 34,300 b | 9,786 b | | protobuf-es | 4 | 92,560 b | 37,274 b | 10,114 b | | protobuf-es | 8 | 101,901 b | 41,772 b | 10,808 b | | protobuf-es | 16 | 165,581 b | 67,017 b | 13,320 b | diff --git a/packages/bundle-size/chart.svg b/packages/bundle-size/chart.svg index e38dc5bbf..451e39841 100644 --- a/packages/bundle-size/chart.svg +++ b/packages/bundle-size/chart.svg @@ -43,10 +43,10 @@ 0 KiB - + protobuf-es -protobuf-es 9.55 KiB for 1 files +protobuf-es 9.56 KiB for 1 files protobuf-es 9.88 KiB for 4 files protobuf-es 10.55 KiB for 8 files protobuf-es 13.01 KiB for 16 files diff --git a/packages/protobuf-test/src/create-registry.test.ts b/packages/protobuf-test/src/create-registry.test.ts index bc3ed57bc..392c2c6a8 100644 --- a/packages/protobuf-test/src/create-registry.test.ts +++ b/packages/protobuf-test/src/create-registry.test.ts @@ -15,6 +15,7 @@ import { describe, expect, test } from "@jest/globals"; import { createRegistry, + createMutableRegistry, Int32Value, MethodKind, proto3, @@ -155,3 +156,11 @@ describe("createRegistry()", () => { }); }); }); + +describe("createMutableRegistry()", () => { + test("add() adds message", () => { + const reg = createMutableRegistry(); + reg.add(MessageFieldMessage); + expect(reg.findMessage(MessageFieldMessage.typeName)).toBeDefined(); + }); +}); diff --git a/packages/protobuf/src/create-registry.ts b/packages/protobuf/src/create-registry.ts index 3865c9868..d6bf9a935 100644 --- a/packages/protobuf/src/create-registry.ts +++ b/packages/protobuf/src/create-registry.ts @@ -19,6 +19,7 @@ import type { IEnumTypeRegistry, IExtensionRegistry, IMessageTypeRegistry, + IMutableRegistry, IServiceTypeRegistry, } from "./type-registry.js"; import type { Extension } from "./extension.js"; @@ -33,12 +34,24 @@ export function createRegistry( IEnumTypeRegistry & IExtensionRegistry & IServiceTypeRegistry { + const mutable = createMutableRegistry(...types); + delete (mutable as Partial).add; + return mutable; +} + +/** + * Create a mutable registry from the given types. + */ +export function createMutableRegistry( + ...types: Array +): IMutableRegistry { const messages: Record = {}; const enums: Record = {}; const services: Record = {}; const extensionsByName = new Map(); const extensionsByExtendee = new Map>(); - const registry = { + + const registry: IMutableRegistry = { findMessage(typeName: string): MessageType | undefined { return messages[typeName]; }, @@ -54,49 +67,51 @@ export function createRegistry( findExtension(typeName: string): Extension | undefined { return extensionsByName.get(typeName) ?? undefined; }, - }; - - function addType(type: MessageType | EnumType | ServiceType | Extension) { - if ("fields" in type) { - if (!registry.findMessage(type.typeName)) { - messages[type.typeName] = type; - type.fields.list().forEach(addField); - } - } else if ("methods" in type) { - if (!registry.findService(type.typeName)) { - services[type.typeName] = type; - for (const method of Object.values(type.methods)) { - addType(method.I); - addType(method.O); + add(type: MessageType | EnumType | ServiceType | Extension) { + if ("fields" in type) { + if (!this.findMessage(type.typeName)) { + messages[type.typeName] = type; + type.fields.list().forEach(addField); } - } - } else if ("extendee" in type) { - if (!extensionsByName.has(type.typeName)) { - extensionsByName.set(type.typeName, type); - const extendeeName = type.extendee.typeName; - if (!extensionsByExtendee.has(extendeeName)) { - extensionsByExtendee.set(extendeeName, new Map()); + } else if ("methods" in type) { + if (!this.findService(type.typeName)) { + services[type.typeName] = type; + for (const method of Object.values(type.methods)) { + this.add(method.I); + this.add(method.O); + } } - extensionsByExtendee.get(extendeeName)?.set(type.field.no, type); - addType(type.extendee); - addField(type.field); + } else if ("extendee" in type) { + if (!extensionsByName.has(type.typeName)) { + extensionsByName.set(type.typeName, type); + const extendeeName = type.extendee.typeName; + if (!extensionsByExtendee.has(extendeeName)) { + extensionsByExtendee.set( + extendeeName, + new Map(), + ); + } + extensionsByExtendee.get(extendeeName)?.set(type.field.no, type); + this.add(type.extendee); + addField(type.field); + } + } else { + enums[type.typeName] = type; } - } else { - enums[type.typeName] = type; - } - } + }, + }; function addField(field: FieldInfo) { if (field.kind == "message") { - addType(field.T); + registry.add(field.T); } else if (field.kind == "map" && field.V.kind == "message") { - addType(field.V.T); + registry.add(field.V.T); } else if (field.kind == "enum") { - addType(field.T); + registry.add(field.T); } } for (const type of types) { - addType(type); + registry.add(type); } return registry; } diff --git a/packages/protobuf/src/index.ts b/packages/protobuf/src/index.ts index c109a19fe..0a07feab7 100644 --- a/packages/protobuf/src/index.ts +++ b/packages/protobuf/src/index.ts @@ -84,7 +84,7 @@ export type { IMessageTypeRegistry, IExtensionRegistry, } from "./type-registry.js"; -export { createRegistry } from "./create-registry.js"; +export { createRegistry, createMutableRegistry } from "./create-registry.js"; export { createRegistryFromDescriptors } from "./create-registry-from-desc.js"; export { toPlainMessage } from "./to-plain-message.js"; diff --git a/packages/protobuf/src/type-registry.ts b/packages/protobuf/src/type-registry.ts index bb50b918e..fb6a0b8f7 100644 --- a/packages/protobuf/src/type-registry.ts +++ b/packages/protobuf/src/type-registry.ts @@ -74,3 +74,17 @@ export interface IExtensionRegistry { */ findExtension(typeName: string): Extension | undefined; } + +/** + * A registry that allows + */ +export interface IMutableRegistry + extends IMessageTypeRegistry, + IEnumTypeRegistry, + IServiceTypeRegistry, + IExtensionRegistry { + /** + * Adds the type to the registry. + */ + add(type: MessageType | EnumType | ServiceType | Extension): void; +}