Skip to content

Commit

Permalink
Introduce type ScalarValue and rename function scalarDefaultValue
Browse files Browse the repository at this point in the history
  • Loading branch information
timostamm committed Feb 12, 2024
1 parent ff30b9b commit d72b06a
Show file tree
Hide file tree
Showing 22 changed files with 211 additions and 190 deletions.
2 changes: 1 addition & 1 deletion packages/protobuf-bench/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ server would usually do.

| code generator | bundle size | minified | compressed |
|---------------------|------------------------:|-----------------------:|-------------------:|
| protobuf-es | 97,101 b | 41,461 b | 10,746 b |
| protobuf-es | 97,081 b | 41,461 b | 10,754 b |
| protobuf-javascript | 394,384 b | 288,654 b | 45,122 b |
19 changes: 14 additions & 5 deletions packages/protobuf/src/codegen-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
safeObjectProperty,
} from "./private/names.js";
import { getUnwrappedFieldType } from "./private/field-wrapper.js";
import { scalarDefaultValue } from "./private/scalars.js";
import { scalarZeroValue } from "./private/scalars.js";
import { reifyWkt } from "./private/reify-wkt.js";
import type {
DescEnum,
Expand All @@ -30,7 +30,8 @@ import type {
DescOneof,
DescService,
} from "./descriptor-set.js";
import { LongType, ScalarType } from "./field.js";
import type { ScalarValue } from "./scalar.js";
import { LongType, ScalarType } from "./scalar.js";

interface CodegenInfo {
/**
Expand All @@ -53,7 +54,14 @@ interface CodegenInfo {
field: DescField | DescExtension,
) => ScalarType | undefined;
readonly wktSourceFiles: readonly string[];
/**
* @deprecated please use scalarZeroValue instead
*/
readonly scalarDefaultValue: (type: ScalarType, longType: LongType) => any; // eslint-disable-line @typescript-eslint/no-explicit-any
readonly scalarZeroValue: <T extends ScalarType, L extends LongType>(
type: T,
longType: L,
) => ScalarValue<T, L>;
/**
* @deprecated please use reifyWkt from @bufbuild/protoplugin/ecmascript instead
*/
Expand Down Expand Up @@ -98,7 +106,8 @@ export const codegenInfo: CodegenInfo = {
localName,
reifyWkt,
getUnwrappedFieldType,
scalarDefaultValue,
scalarDefaultValue: scalarZeroValue,
scalarZeroValue,
safeIdentifier,
safeObjectProperty,
// prettier-ignore
Expand All @@ -119,8 +128,8 @@ export const codegenInfo: CodegenInfo = {
JsonObject: {typeOnly: true, privateImportPath: "./json-format.js", publicImportPath: packageName},
protoDouble: {typeOnly: false, privateImportPath: "./proto-double.js", publicImportPath: packageName},
protoInt64: {typeOnly: false, privateImportPath: "./proto-int64.js", publicImportPath: packageName},
ScalarType: {typeOnly: false, privateImportPath: "./field.js", publicImportPath: packageName},
LongType: {typeOnly: false, privateImportPath: "./field.js", publicImportPath: packageName},
ScalarType: {typeOnly: false, privateImportPath: "./scalar.js", publicImportPath: packageName},
LongType: {typeOnly: false, privateImportPath: "./scalar.js", publicImportPath: packageName},
MethodKind: {typeOnly: false, privateImportPath: "./service-type.js", publicImportPath: packageName},
MethodIdempotency: {typeOnly: false, privateImportPath: "./service-type.js", publicImportPath: packageName},
IMessageTypeRegistry: {typeOnly: true, privateImportPath: "./type-registry.js", publicImportPath: packageName},
Expand Down
2 changes: 1 addition & 1 deletion packages/protobuf/src/create-descriptor-set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ import type {
DescriptorSet,
DescService,
} from "./descriptor-set.js";
import { LongType, ScalarType } from "./field.js";
import { MethodIdempotency, MethodKind } from "./service-type.js";
import { fieldJsonName, findEnumSharedPrefix } from "./private/names.js";
import {
Expand All @@ -55,6 +54,7 @@ import {
import type { BinaryReadOptions, BinaryWriteOptions } from "./binary-format.js";
import type { FeatureResolverFn } from "./private/feature-set.js";
import { createFeatureResolver } from "./private/feature-set.js";
import { LongType, ScalarType } from "./scalar.js";

/**
* Create a DescriptorSet, a convenient interface for working with a set of
Expand Down
2 changes: 1 addition & 1 deletion packages/protobuf/src/create-registry-from-desc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type { MessageType } from "./message-type.js";
import { proto3 } from "./proto3.js";
import { proto2 } from "./proto2.js";
import type { FieldInfo } from "./field.js";
import { ScalarType } from "./field.js";
import { ScalarType } from "./scalar.js";
import type { EnumType, EnumValueInfo } from "./enum.js";
import type {
IEnumTypeRegistry,
Expand Down
2 changes: 1 addition & 1 deletion packages/protobuf/src/descriptor-set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import type {
OneofDescriptorProto,
ServiceDescriptorProto,
} from "./google/protobuf/descriptor_pb.js";
import type { LongType, ScalarType } from "./field.js";
import { LongType, ScalarType } from "./scalar.js";
import type { MethodIdempotency, MethodKind } from "./service-type.js";
import type { MergedFeatureSet } from "./private/feature-set.js";

Expand Down
68 changes: 1 addition & 67 deletions packages/protobuf/src/field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import type { EnumType } from "./enum.js";
import type { MessageType } from "./message-type.js";
import type { LongType, ScalarType } from "./scalar.js";

/* eslint-disable @typescript-eslint/no-explicit-any */

Expand Down Expand Up @@ -322,70 +323,3 @@ type fiPartialRules<T extends fiScalar|fiMap|fiEnum|fiMessage> = Omit<T, "jsonNa
| { readonly jsonName?: string; readonly repeated?: false; readonly packed?: false; readonly opt: true; readonly req?: false; readonly oneof?: undefined; default?: T["default"]; L?: LongType; delimited?: boolean; }
| { readonly jsonName?: string; readonly repeated?: boolean; readonly packed?: boolean; readonly opt?: false; readonly req?: boolean; readonly oneof?: undefined; default?: T["default"]; L?: LongType; delimited?: boolean; }
| { readonly jsonName?: string; readonly repeated?: false; readonly packed?: false; readonly opt?: false; readonly req?: false; readonly oneof: string; default?: T["default"]; L?: LongType; delimited?: boolean; });

/**
* Scalar value types. This is a subset of field types declared by protobuf
* enum google.protobuf.FieldDescriptorProto.Type The types GROUP and MESSAGE
* are omitted, but the numerical values are identical.
*/
export enum ScalarType {
// 0 is reserved for errors.
// Order is weird for historical reasons.
DOUBLE = 1,
FLOAT = 2,
// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if
// negative values are likely.
INT64 = 3,
UINT64 = 4,
// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if
// negative values are likely.
INT32 = 5,
FIXED64 = 6,
FIXED32 = 7,
BOOL = 8,
STRING = 9,
// Tag-delimited aggregate.
// Group type is deprecated and not supported in proto3. However, Proto3
// implementations should still be able to parse the group wire format and
// treat group fields as unknown fields.
// TYPE_GROUP = 10,
// TYPE_MESSAGE = 11, // Length-delimited aggregate.

// New in version 2.
BYTES = 12,
UINT32 = 13,
// TYPE_ENUM = 14,
SFIXED32 = 15,
SFIXED64 = 16,
SINT32 = 17, // Uses ZigZag encoding.
SINT64 = 18, // Uses ZigZag encoding.
}

/**
* JavaScript representation of fields with 64 bit integral types (int64, uint64,
* sint64, fixed64, sfixed64).
*
* This is a subset of google.protobuf.FieldOptions.JSType, which defines JS_NORMAL,
* JS_STRING, and JS_NUMBER. Protobuf-ES uses BigInt by default, but will use
* String if `[jstype = JS_STRING]` is specified.
*
* ```protobuf
* uint64 field_a = 1; // BigInt
* uint64 field_b = 2 [jstype = JS_NORMAL]; // BigInt
* uint64 field_b = 2 [jstype = JS_NUMBER]; // BigInt
* uint64 field_b = 2 [jstype = JS_STRING]; // String
* ```
*/
export enum LongType {
/**
* Use JavaScript BigInt.
*/
BIGINT = 0,

/**
* Use JavaScript String.
*
* Field option `[jstype = JS_STRING]`.
*/
STRING = 1,
}
2 changes: 1 addition & 1 deletion packages/protobuf/src/google/protobuf/wrappers_pb.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/protobuf/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export type { AnyMessage, PartialMessage, PlainMessage } from "./message.js";

export type { FieldInfo } from "./field.js";
export type { FieldList } from "./field-list.js";
export { ScalarType, LongType } from "./field.js";
export { LongType, ScalarType } from "./scalar.js";
export type { ScalarValue } from "./scalar.js";

export type { MessageType } from "./message-type.js";
export type { EnumType, EnumValueInfo } from "./enum.js";
Expand Down
3 changes: 1 addition & 2 deletions packages/protobuf/src/json-format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@

import type { Message } from "./message.js";
import type { MessageType } from "./message-type.js";
import type { ScalarType } from "./field.js";
import { LongType } from "./field.js";
import type { ScalarType, LongType } from "./scalar.js";
import type {
IExtensionRegistry,
IMessageTypeRegistry,
Expand Down
58 changes: 53 additions & 5 deletions packages/protobuf/src/private/binary-format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ import type {
} from "../binary-format.js";
import { type AnyMessage, Message } from "../message.js";
import type { FieldInfo } from "../field.js";
import { LongType, ScalarType } from "../field.js";
import { wrapField } from "./field-wrapper.js";
import { scalarDefaultValue, scalarTypeInfo } from "./scalars.js";
import type { ScalarValue } from "./scalars.js";
import { isScalarZeroValue, scalarZeroValue } from "./scalars.js";
import { assert } from "./assert.js";
import { isFieldSet } from "./reflect.js";
import type { ScalarValue } from "../scalar.js";
import { LongType, ScalarType } from "../scalar.js";

/* eslint-disable prefer-const,no-case-declarations,@typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-return */

Expand Down Expand Up @@ -286,15 +286,15 @@ function readMapEntry(
}
}
if (key === undefined) {
key = scalarDefaultValue(field.K, LongType.BIGINT) as ScalarValue;
key = scalarZeroValue(field.K, LongType.BIGINT);
}
if (typeof key != "string" && typeof key != "number") {
key = key.toString();
}
if (val === undefined) {
switch (field.V.kind) {
case "scalar":
val = scalarDefaultValue(field.V.T, LongType.BIGINT) as ScalarValue;
val = scalarZeroValue(field.V.T, LongType.BIGINT);
break;
case "enum":
val = field.V.T.values[0].no;
Expand Down Expand Up @@ -492,3 +492,51 @@ function writePacked(
}
writer.join();
}

/**
* Get information for writing a scalar value.
*
* Returns tuple:
* [0]: appropriate WireType
* [1]: name of the appropriate method of IBinaryWriter
* [2]: whether the given value is a default value for proto3 semantics
*
* If argument `value` is omitted, [2] is always false.
*/
// TODO replace call-sites writeScalar() and writePacked(), then remove
function scalarTypeInfo(
type: ScalarType,
value?: unknown,
): [
WireType,
Exclude<keyof IBinaryWriter, "tag" | "raw" | "fork" | "join" | "finish">,
boolean,
] {
let wireType = WireType.Varint;
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- INT32, UINT32, SINT32 are covered by the defaults
switch (type) {
case ScalarType.BYTES:
case ScalarType.STRING:
wireType = WireType.LengthDelimited;
break;
case ScalarType.DOUBLE:
case ScalarType.FIXED64:
case ScalarType.SFIXED64:
wireType = WireType.Bit64;
break;
case ScalarType.FIXED32:
case ScalarType.SFIXED32:
case ScalarType.FLOAT:
wireType = WireType.Bit32;
break;
}
const method = ScalarType[type].toLowerCase() as Exclude<
keyof IBinaryWriter,
"tag" | "raw" | "fork" | "join" | "finish"
>;
return [
wireType,
method,
value === undefined || isScalarZeroValue(type, value),
];
}
4 changes: 2 additions & 2 deletions packages/protobuf/src/private/extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { scalarDefaultValue } from "./scalars.js";
import { scalarZeroValue } from "./scalars.js";
import type { Extension } from "../extension.js";
import type { AnyMessage, Message } from "../message.js";
import type { FieldInfo, OneofInfo, PartialFieldInfo } from "../field.js";
Expand Down Expand Up @@ -88,7 +88,7 @@ function initExtensionField(ext: Extension): unknown {
case "enum":
return field.T.values[0].no;
case "scalar":
return scalarDefaultValue(field.T, field.L);
return scalarZeroValue(field.T, field.L);
case "message":
// eslint-disable-next-line no-case-declarations
const T = field.T,
Expand Down
2 changes: 1 addition & 1 deletion packages/protobuf/src/private/field-normalize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@

import type { FieldListSource } from "./field-list.js";
import type { FieldInfo } from "../field.js";
import { LongType, ScalarType } from "../field.js";
import { InternalOneofInfo } from "./field.js";
import { fieldJsonName, localFieldName } from "./names.js";
import { LongType, ScalarType } from "../scalar.js";

/**
* Convert a collection of field info to an array of normalized FieldInfo.
Expand Down
2 changes: 1 addition & 1 deletion packages/protobuf/src/private/field-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import { Message } from "../message.js";
import type { MessageType } from "../message-type.js";
import type { DescExtension, DescField } from "../descriptor-set.js";
import { ScalarType } from "../field.js";
import { ScalarType } from "../scalar.js";

/* eslint-disable @typescript-eslint/no-explicit-any -- unknown fields are represented with any */

Expand Down
9 changes: 5 additions & 4 deletions packages/protobuf/src/private/json-format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import type { AnyMessage } from "../message.js";
import { Message } from "../message.js";
import type { MessageType } from "../message-type.js";
import type { FieldInfo, OneofInfo } from "../field.js";
import { LongType, ScalarType } from "../field.js";
import { assert, assertFloat32, assertInt32, assertUInt32 } from "./assert.js";
import { protoInt64 } from "../proto-int64.js";
import { protoBase64 } from "../proto-base64.js";
Expand All @@ -42,8 +41,10 @@ import type {
} from "../binary-format.js";
import { clearField, isFieldSet } from "./reflect.js";
import { wrapField } from "./field-wrapper.js";
import type { ScalarValue } from "./scalars.js";
import { scalarDefaultValue, isScalarZeroValue } from "./scalars.js";
import { scalarZeroValue } from "./scalars.js";
import { isScalarZeroValue } from "./scalars.js";
import type { ScalarValue } from "../scalar.js";
import { LongType, ScalarType } from "../scalar.js";

/* eslint-disable no-case-declarations,@typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call */

Expand Down Expand Up @@ -475,7 +476,7 @@ function readScalar(
): ScalarValue | typeof tokenNull {
if (json === null) {
if (nullAsZeroValue) {
return scalarDefaultValue(type, longType) as ScalarValue;
return scalarZeroValue(type, longType);
}
return tokenNull;
}
Expand Down
5 changes: 2 additions & 3 deletions packages/protobuf/src/private/reflect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.

import type { FieldInfo } from "../field.js";
import { isScalarZeroValue, scalarDefaultValue } from "./scalars.js";
import { isScalarZeroValue, scalarZeroValue } from "./scalars.js";

/**
* Returns true if the field is set.
Expand Down Expand Up @@ -70,9 +70,8 @@ export function clearField(
target[localName] = implicitPresence ? field.T.values[0].no : undefined;
break;
case "scalar":
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
target[localName] = implicitPresence
? scalarDefaultValue(field.T, field.L)
? scalarZeroValue(field.T, field.L)
: undefined;
break;
case "message":
Expand Down
2 changes: 1 addition & 1 deletion packages/protobuf/src/private/reify-wkt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.

import type { DescField, DescMessage, DescOneof } from "../descriptor-set.js";
import { ScalarType } from "../field.js";
import { ScalarType } from "../scalar.js";

type DescWkt =
| {
Expand Down
Loading

0 comments on commit d72b06a

Please sign in to comment.