diff --git a/packages/protons-benchmark/src/implementations/protobufjs/rpc.d.ts b/packages/protons-benchmark/src/implementations/protobufjs/rpc.d.ts deleted file mode 100644 index fafe66e..0000000 --- a/packages/protons-benchmark/src/implementations/protobufjs/rpc.d.ts +++ /dev/null @@ -1,1009 +0,0 @@ -/* eslint-disable */ -import * as $protobuf from "protobufjs"; -/** Properties of a RPC. */ -export interface IRPC { - - /** RPC subscriptions */ - subscriptions?: (RPC.ISubOpts[]|null); - - /** RPC messages */ - messages?: (RPC.IMessage[]|null); - - /** RPC control */ - control?: (RPC.IControlMessage|null); -} - -/** Represents a RPC. */ -export class RPC implements IRPC { - - /** - * Constructs a new RPC. - * @param [properties] Properties to set - */ - constructor(properties?: IRPC); - - /** RPC subscriptions. */ - public subscriptions: RPC.ISubOpts[]; - - /** RPC messages. */ - public messages: RPC.IMessage[]; - - /** RPC control. */ - public control?: (RPC.IControlMessage|null); - - /** RPC _control. */ - public _control?: "control"; - - /** - * Creates a new RPC instance using the specified properties. - * @param [properties] Properties to set - * @returns RPC instance - */ - public static create(properties?: IRPC): RPC; - - /** - * Encodes the specified RPC message. Does not implicitly {@link RPC.verify|verify} messages. - * @param message RPC message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: IRPC, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified RPC message, length delimited. Does not implicitly {@link RPC.verify|verify} messages. - * @param message RPC message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: IRPC, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a RPC message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns RPC - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RPC; - - /** - * Decodes a RPC message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns RPC - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RPC; - - /** - * Verifies a RPC message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a RPC message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns RPC - */ - public static fromObject(object: { [k: string]: any }): RPC; - - /** - * Creates a plain object from a RPC message. Also converts values to other types if specified. - * @param message RPC - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: RPC, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this RPC to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; - - /** - * Gets the default type url for RPC - * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns The default type url - */ - public static getTypeUrl(typeUrlPrefix?: string): string; -} - -export namespace RPC { - - /** Properties of a SubOpts. */ - interface ISubOpts { - - /** SubOpts subscribe */ - subscribe?: (boolean|null); - - /** SubOpts topic */ - topic?: (string|null); - } - - /** Represents a SubOpts. */ - class SubOpts implements ISubOpts { - - /** - * Constructs a new SubOpts. - * @param [properties] Properties to set - */ - constructor(properties?: RPC.ISubOpts); - - /** SubOpts subscribe. */ - public subscribe?: (boolean|null); - - /** SubOpts topic. */ - public topic?: (string|null); - - /** SubOpts _subscribe. */ - public _subscribe?: "subscribe"; - - /** SubOpts _topic. */ - public _topic?: "topic"; - - /** - * Creates a new SubOpts instance using the specified properties. - * @param [properties] Properties to set - * @returns SubOpts instance - */ - public static create(properties?: RPC.ISubOpts): RPC.SubOpts; - - /** - * Encodes the specified SubOpts message. Does not implicitly {@link RPC.SubOpts.verify|verify} messages. - * @param message SubOpts message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: RPC.ISubOpts, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified SubOpts message, length delimited. Does not implicitly {@link RPC.SubOpts.verify|verify} messages. - * @param message SubOpts message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: RPC.ISubOpts, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a SubOpts message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns SubOpts - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RPC.SubOpts; - - /** - * Decodes a SubOpts message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns SubOpts - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RPC.SubOpts; - - /** - * Verifies a SubOpts message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a SubOpts message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns SubOpts - */ - public static fromObject(object: { [k: string]: any }): RPC.SubOpts; - - /** - * Creates a plain object from a SubOpts message. Also converts values to other types if specified. - * @param message SubOpts - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: RPC.SubOpts, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this SubOpts to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; - - /** - * Gets the default type url for SubOpts - * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns The default type url - */ - public static getTypeUrl(typeUrlPrefix?: string): string; - } - - /** Properties of a Message. */ - interface IMessage { - - /** Message from */ - from?: (Uint8Array|null); - - /** Message data */ - data?: (Uint8Array|null); - - /** Message seqno */ - seqno?: (Uint8Array|null); - - /** Message topic */ - topic: string; - - /** Message signature */ - signature?: (Uint8Array|null); - - /** Message key */ - key?: (Uint8Array|null); - } - - /** Represents a Message. */ - class Message implements IMessage { - - /** - * Constructs a new Message. - * @param [properties] Properties to set - */ - constructor(properties?: RPC.IMessage); - - /** Message from. */ - public from?: (Uint8Array|null); - - /** Message data. */ - public data?: (Uint8Array|null); - - /** Message seqno. */ - public seqno?: (Uint8Array|null); - - /** Message topic. */ - public topic: string; - - /** Message signature. */ - public signature?: (Uint8Array|null); - - /** Message key. */ - public key?: (Uint8Array|null); - - /** Message _from. */ - public _from?: "from"; - - /** Message _data. */ - public _data?: "data"; - - /** Message _seqno. */ - public _seqno?: "seqno"; - - /** Message _signature. */ - public _signature?: "signature"; - - /** Message _key. */ - public _key?: "key"; - - /** - * Creates a new Message instance using the specified properties. - * @param [properties] Properties to set - * @returns Message instance - */ - public static create(properties?: RPC.IMessage): RPC.Message; - - /** - * Encodes the specified Message message. Does not implicitly {@link RPC.Message.verify|verify} messages. - * @param message Message message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: RPC.IMessage, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified Message message, length delimited. Does not implicitly {@link RPC.Message.verify|verify} messages. - * @param message Message message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: RPC.IMessage, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a Message message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns Message - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RPC.Message; - - /** - * Decodes a Message message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns Message - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RPC.Message; - - /** - * Verifies a Message message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a Message message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns Message - */ - public static fromObject(object: { [k: string]: any }): RPC.Message; - - /** - * Creates a plain object from a Message message. Also converts values to other types if specified. - * @param message Message - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: RPC.Message, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this Message to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; - - /** - * Gets the default type url for Message - * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns The default type url - */ - public static getTypeUrl(typeUrlPrefix?: string): string; - } - - /** Properties of a ControlMessage. */ - interface IControlMessage { - - /** ControlMessage ihave */ - ihave?: (RPC.IControlIHave[]|null); - - /** ControlMessage iwant */ - iwant?: (RPC.IControlIWant[]|null); - - /** ControlMessage graft */ - graft?: (RPC.IControlGraft[]|null); - - /** ControlMessage prune */ - prune?: (RPC.IControlPrune[]|null); - } - - /** Represents a ControlMessage. */ - class ControlMessage implements IControlMessage { - - /** - * Constructs a new ControlMessage. - * @param [properties] Properties to set - */ - constructor(properties?: RPC.IControlMessage); - - /** ControlMessage ihave. */ - public ihave: RPC.IControlIHave[]; - - /** ControlMessage iwant. */ - public iwant: RPC.IControlIWant[]; - - /** ControlMessage graft. */ - public graft: RPC.IControlGraft[]; - - /** ControlMessage prune. */ - public prune: RPC.IControlPrune[]; - - /** - * Creates a new ControlMessage instance using the specified properties. - * @param [properties] Properties to set - * @returns ControlMessage instance - */ - public static create(properties?: RPC.IControlMessage): RPC.ControlMessage; - - /** - * Encodes the specified ControlMessage message. Does not implicitly {@link RPC.ControlMessage.verify|verify} messages. - * @param message ControlMessage message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: RPC.IControlMessage, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified ControlMessage message, length delimited. Does not implicitly {@link RPC.ControlMessage.verify|verify} messages. - * @param message ControlMessage message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: RPC.IControlMessage, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a ControlMessage message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns ControlMessage - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RPC.ControlMessage; - - /** - * Decodes a ControlMessage message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns ControlMessage - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RPC.ControlMessage; - - /** - * Verifies a ControlMessage message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a ControlMessage message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns ControlMessage - */ - public static fromObject(object: { [k: string]: any }): RPC.ControlMessage; - - /** - * Creates a plain object from a ControlMessage message. Also converts values to other types if specified. - * @param message ControlMessage - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: RPC.ControlMessage, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this ControlMessage to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; - - /** - * Gets the default type url for ControlMessage - * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns The default type url - */ - public static getTypeUrl(typeUrlPrefix?: string): string; - } - - /** Properties of a ControlIHave. */ - interface IControlIHave { - - /** ControlIHave topicID */ - topicID?: (string|null); - - /** ControlIHave messageIDs */ - messageIDs?: (Uint8Array[]|null); - } - - /** Represents a ControlIHave. */ - class ControlIHave implements IControlIHave { - - /** - * Constructs a new ControlIHave. - * @param [properties] Properties to set - */ - constructor(properties?: RPC.IControlIHave); - - /** ControlIHave topicID. */ - public topicID?: (string|null); - - /** ControlIHave messageIDs. */ - public messageIDs: Uint8Array[]; - - /** ControlIHave _topicID. */ - public _topicID?: "topicID"; - - /** - * Creates a new ControlIHave instance using the specified properties. - * @param [properties] Properties to set - * @returns ControlIHave instance - */ - public static create(properties?: RPC.IControlIHave): RPC.ControlIHave; - - /** - * Encodes the specified ControlIHave message. Does not implicitly {@link RPC.ControlIHave.verify|verify} messages. - * @param message ControlIHave message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: RPC.IControlIHave, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified ControlIHave message, length delimited. Does not implicitly {@link RPC.ControlIHave.verify|verify} messages. - * @param message ControlIHave message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: RPC.IControlIHave, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a ControlIHave message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns ControlIHave - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RPC.ControlIHave; - - /** - * Decodes a ControlIHave message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns ControlIHave - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RPC.ControlIHave; - - /** - * Verifies a ControlIHave message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a ControlIHave message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns ControlIHave - */ - public static fromObject(object: { [k: string]: any }): RPC.ControlIHave; - - /** - * Creates a plain object from a ControlIHave message. Also converts values to other types if specified. - * @param message ControlIHave - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: RPC.ControlIHave, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this ControlIHave to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; - - /** - * Gets the default type url for ControlIHave - * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns The default type url - */ - public static getTypeUrl(typeUrlPrefix?: string): string; - } - - /** Properties of a ControlIWant. */ - interface IControlIWant { - - /** ControlIWant messageIDs */ - messageIDs?: (Uint8Array[]|null); - } - - /** Represents a ControlIWant. */ - class ControlIWant implements IControlIWant { - - /** - * Constructs a new ControlIWant. - * @param [properties] Properties to set - */ - constructor(properties?: RPC.IControlIWant); - - /** ControlIWant messageIDs. */ - public messageIDs: Uint8Array[]; - - /** - * Creates a new ControlIWant instance using the specified properties. - * @param [properties] Properties to set - * @returns ControlIWant instance - */ - public static create(properties?: RPC.IControlIWant): RPC.ControlIWant; - - /** - * Encodes the specified ControlIWant message. Does not implicitly {@link RPC.ControlIWant.verify|verify} messages. - * @param message ControlIWant message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: RPC.IControlIWant, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified ControlIWant message, length delimited. Does not implicitly {@link RPC.ControlIWant.verify|verify} messages. - * @param message ControlIWant message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: RPC.IControlIWant, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a ControlIWant message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns ControlIWant - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RPC.ControlIWant; - - /** - * Decodes a ControlIWant message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns ControlIWant - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RPC.ControlIWant; - - /** - * Verifies a ControlIWant message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a ControlIWant message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns ControlIWant - */ - public static fromObject(object: { [k: string]: any }): RPC.ControlIWant; - - /** - * Creates a plain object from a ControlIWant message. Also converts values to other types if specified. - * @param message ControlIWant - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: RPC.ControlIWant, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this ControlIWant to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; - - /** - * Gets the default type url for ControlIWant - * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns The default type url - */ - public static getTypeUrl(typeUrlPrefix?: string): string; - } - - /** Properties of a ControlGraft. */ - interface IControlGraft { - - /** ControlGraft topicID */ - topicID?: (string|null); - } - - /** Represents a ControlGraft. */ - class ControlGraft implements IControlGraft { - - /** - * Constructs a new ControlGraft. - * @param [properties] Properties to set - */ - constructor(properties?: RPC.IControlGraft); - - /** ControlGraft topicID. */ - public topicID?: (string|null); - - /** ControlGraft _topicID. */ - public _topicID?: "topicID"; - - /** - * Creates a new ControlGraft instance using the specified properties. - * @param [properties] Properties to set - * @returns ControlGraft instance - */ - public static create(properties?: RPC.IControlGraft): RPC.ControlGraft; - - /** - * Encodes the specified ControlGraft message. Does not implicitly {@link RPC.ControlGraft.verify|verify} messages. - * @param message ControlGraft message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: RPC.IControlGraft, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified ControlGraft message, length delimited. Does not implicitly {@link RPC.ControlGraft.verify|verify} messages. - * @param message ControlGraft message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: RPC.IControlGraft, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a ControlGraft message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns ControlGraft - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RPC.ControlGraft; - - /** - * Decodes a ControlGraft message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns ControlGraft - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RPC.ControlGraft; - - /** - * Verifies a ControlGraft message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a ControlGraft message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns ControlGraft - */ - public static fromObject(object: { [k: string]: any }): RPC.ControlGraft; - - /** - * Creates a plain object from a ControlGraft message. Also converts values to other types if specified. - * @param message ControlGraft - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: RPC.ControlGraft, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this ControlGraft to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; - - /** - * Gets the default type url for ControlGraft - * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns The default type url - */ - public static getTypeUrl(typeUrlPrefix?: string): string; - } - - /** Properties of a ControlPrune. */ - interface IControlPrune { - - /** ControlPrune topicID */ - topicID?: (string|null); - - /** ControlPrune peers */ - peers?: (RPC.IPeerInfo[]|null); - - /** ControlPrune backoff */ - backoff?: (number|Long|null); - } - - /** Represents a ControlPrune. */ - class ControlPrune implements IControlPrune { - - /** - * Constructs a new ControlPrune. - * @param [properties] Properties to set - */ - constructor(properties?: RPC.IControlPrune); - - /** ControlPrune topicID. */ - public topicID?: (string|null); - - /** ControlPrune peers. */ - public peers: RPC.IPeerInfo[]; - - /** ControlPrune backoff. */ - public backoff?: (number|Long|null); - - /** ControlPrune _topicID. */ - public _topicID?: "topicID"; - - /** ControlPrune _backoff. */ - public _backoff?: "backoff"; - - /** - * Creates a new ControlPrune instance using the specified properties. - * @param [properties] Properties to set - * @returns ControlPrune instance - */ - public static create(properties?: RPC.IControlPrune): RPC.ControlPrune; - - /** - * Encodes the specified ControlPrune message. Does not implicitly {@link RPC.ControlPrune.verify|verify} messages. - * @param message ControlPrune message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: RPC.IControlPrune, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified ControlPrune message, length delimited. Does not implicitly {@link RPC.ControlPrune.verify|verify} messages. - * @param message ControlPrune message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: RPC.IControlPrune, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a ControlPrune message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns ControlPrune - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RPC.ControlPrune; - - /** - * Decodes a ControlPrune message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns ControlPrune - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RPC.ControlPrune; - - /** - * Verifies a ControlPrune message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a ControlPrune message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns ControlPrune - */ - public static fromObject(object: { [k: string]: any }): RPC.ControlPrune; - - /** - * Creates a plain object from a ControlPrune message. Also converts values to other types if specified. - * @param message ControlPrune - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: RPC.ControlPrune, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this ControlPrune to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; - - /** - * Gets the default type url for ControlPrune - * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns The default type url - */ - public static getTypeUrl(typeUrlPrefix?: string): string; - } - - /** Properties of a PeerInfo. */ - interface IPeerInfo { - - /** PeerInfo peerID */ - peerID?: (Uint8Array|null); - - /** PeerInfo signedPeerRecord */ - signedPeerRecord?: (Uint8Array|null); - } - - /** Represents a PeerInfo. */ - class PeerInfo implements IPeerInfo { - - /** - * Constructs a new PeerInfo. - * @param [properties] Properties to set - */ - constructor(properties?: RPC.IPeerInfo); - - /** PeerInfo peerID. */ - public peerID?: (Uint8Array|null); - - /** PeerInfo signedPeerRecord. */ - public signedPeerRecord?: (Uint8Array|null); - - /** PeerInfo _peerID. */ - public _peerID?: "peerID"; - - /** PeerInfo _signedPeerRecord. */ - public _signedPeerRecord?: "signedPeerRecord"; - - /** - * Creates a new PeerInfo instance using the specified properties. - * @param [properties] Properties to set - * @returns PeerInfo instance - */ - public static create(properties?: RPC.IPeerInfo): RPC.PeerInfo; - - /** - * Encodes the specified PeerInfo message. Does not implicitly {@link RPC.PeerInfo.verify|verify} messages. - * @param message PeerInfo message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: RPC.IPeerInfo, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified PeerInfo message, length delimited. Does not implicitly {@link RPC.PeerInfo.verify|verify} messages. - * @param message PeerInfo message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: RPC.IPeerInfo, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a PeerInfo message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns PeerInfo - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RPC.PeerInfo; - - /** - * Decodes a PeerInfo message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns PeerInfo - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RPC.PeerInfo; - - /** - * Verifies a PeerInfo message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a PeerInfo message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns PeerInfo - */ - public static fromObject(object: { [k: string]: any }): RPC.PeerInfo; - - /** - * Creates a plain object from a PeerInfo message. Also converts values to other types if specified. - * @param message PeerInfo - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: RPC.PeerInfo, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this PeerInfo to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; - - /** - * Gets the default type url for PeerInfo - * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns The default type url - */ - public static getTypeUrl(typeUrlPrefix?: string): string; - } -} diff --git a/packages/protons-benchmark/src/implementations/protobufjs/rpc.js b/packages/protons-benchmark/src/implementations/protobufjs/rpc.js deleted file mode 100644 index 9f6c59a..0000000 --- a/packages/protons-benchmark/src/implementations/protobufjs/rpc.js +++ /dev/null @@ -1,2643 +0,0 @@ -/*eslint-disable*/ -// @ts-nocheck - -import $protobuf from "protobufjs/minimal.js"; - -// Common aliases -const $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util; - -// Exported root namespace -const $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {}); - -export const RPC = $root.RPC = (() => { - - /** - * Properties of a RPC. - * @exports IRPC - * @interface IRPC - * @property {Array.|null} [subscriptions] RPC subscriptions - * @property {Array.|null} [messages] RPC messages - * @property {RPC.IControlMessage|null} [control] RPC control - */ - - /** - * Constructs a new RPC. - * @exports RPC - * @classdesc Represents a RPC. - * @implements IRPC - * @constructor - * @param {IRPC=} [properties] Properties to set - */ - function RPC(properties) { - this.subscriptions = []; - this.messages = []; - if (properties) - for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * RPC subscriptions. - * @member {Array.} subscriptions - * @memberof RPC - * @instance - */ - RPC.prototype.subscriptions = $util.emptyArray; - - /** - * RPC messages. - * @member {Array.} messages - * @memberof RPC - * @instance - */ - RPC.prototype.messages = $util.emptyArray; - - /** - * RPC control. - * @member {RPC.IControlMessage|null|undefined} control - * @memberof RPC - * @instance - */ - RPC.prototype.control = null; - - // OneOf field names bound to virtual getters and setters - let $oneOfFields; - - /** - * RPC _control. - * @member {"control"|undefined} _control - * @memberof RPC - * @instance - */ - Object.defineProperty(RPC.prototype, "_control", { - get: $util.oneOfGetter($oneOfFields = ["control"]), - set: $util.oneOfSetter($oneOfFields) - }); - - /** - * Creates a new RPC instance using the specified properties. - * @function create - * @memberof RPC - * @static - * @param {IRPC=} [properties] Properties to set - * @returns {RPC} RPC instance - */ - RPC.create = function create(properties) { - return new RPC(properties); - }; - - /** - * Encodes the specified RPC message. Does not implicitly {@link RPC.verify|verify} messages. - * @function encode - * @memberof RPC - * @static - * @param {IRPC} message RPC message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - RPC.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.subscriptions != null && message.subscriptions.length) - for (let i = 0; i < message.subscriptions.length; ++i) - $root.RPC.SubOpts.encode(message.subscriptions[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); - if (message.messages != null && message.messages.length) - for (let i = 0; i < message.messages.length; ++i) - $root.RPC.Message.encode(message.messages[i], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); - if (message.control != null && Object.hasOwnProperty.call(message, "control")) - $root.RPC.ControlMessage.encode(message.control, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); - return writer; - }; - - /** - * Encodes the specified RPC message, length delimited. Does not implicitly {@link RPC.verify|verify} messages. - * @function encodeDelimited - * @memberof RPC - * @static - * @param {IRPC} message RPC message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - RPC.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a RPC message from the specified reader or buffer. - * @function decode - * @memberof RPC - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {RPC} RPC - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - RPC.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - let end = length === undefined ? reader.len : reader.pos + length, message = new $root.RPC(); - while (reader.pos < end) { - let tag = reader.uint32(); - switch (tag >>> 3) { - case 1: { - if (!(message.subscriptions && message.subscriptions.length)) - message.subscriptions = []; - message.subscriptions.push($root.RPC.SubOpts.decode(reader, reader.uint32())); - break; - } - case 2: { - if (!(message.messages && message.messages.length)) - message.messages = []; - message.messages.push($root.RPC.Message.decode(reader, reader.uint32())); - break; - } - case 3: { - message.control = $root.RPC.ControlMessage.decode(reader, reader.uint32()); - break; - } - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a RPC message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof RPC - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {RPC} RPC - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - RPC.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a RPC message. - * @function verify - * @memberof RPC - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - RPC.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - let properties = {}; - if (message.subscriptions != null && message.hasOwnProperty("subscriptions")) { - if (!Array.isArray(message.subscriptions)) - return "subscriptions: array expected"; - for (let i = 0; i < message.subscriptions.length; ++i) { - let error = $root.RPC.SubOpts.verify(message.subscriptions[i]); - if (error) - return "subscriptions." + error; - } - } - if (message.messages != null && message.hasOwnProperty("messages")) { - if (!Array.isArray(message.messages)) - return "messages: array expected"; - for (let i = 0; i < message.messages.length; ++i) { - let error = $root.RPC.Message.verify(message.messages[i]); - if (error) - return "messages." + error; - } - } - if (message.control != null && message.hasOwnProperty("control")) { - properties._control = 1; - { - let error = $root.RPC.ControlMessage.verify(message.control); - if (error) - return "control." + error; - } - } - return null; - }; - - /** - * Creates a RPC message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof RPC - * @static - * @param {Object.} object Plain object - * @returns {RPC} RPC - */ - RPC.fromObject = function fromObject(object) { - if (object instanceof $root.RPC) - return object; - let message = new $root.RPC(); - if (object.subscriptions) { - if (!Array.isArray(object.subscriptions)) - throw TypeError(".RPC.subscriptions: array expected"); - message.subscriptions = []; - for (let i = 0; i < object.subscriptions.length; ++i) { - if (typeof object.subscriptions[i] !== "object") - throw TypeError(".RPC.subscriptions: object expected"); - message.subscriptions[i] = $root.RPC.SubOpts.fromObject(object.subscriptions[i]); - } - } - if (object.messages) { - if (!Array.isArray(object.messages)) - throw TypeError(".RPC.messages: array expected"); - message.messages = []; - for (let i = 0; i < object.messages.length; ++i) { - if (typeof object.messages[i] !== "object") - throw TypeError(".RPC.messages: object expected"); - message.messages[i] = $root.RPC.Message.fromObject(object.messages[i]); - } - } - if (object.control != null) { - if (typeof object.control !== "object") - throw TypeError(".RPC.control: object expected"); - message.control = $root.RPC.ControlMessage.fromObject(object.control); - } - return message; - }; - - /** - * Creates a plain object from a RPC message. Also converts values to other types if specified. - * @function toObject - * @memberof RPC - * @static - * @param {RPC} message RPC - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - RPC.toObject = function toObject(message, options) { - if (!options) - options = {}; - let object = {}; - if (options.arrays || options.defaults) { - object.subscriptions = []; - object.messages = []; - } - if (message.subscriptions && message.subscriptions.length) { - object.subscriptions = []; - for (let j = 0; j < message.subscriptions.length; ++j) - object.subscriptions[j] = $root.RPC.SubOpts.toObject(message.subscriptions[j], options); - } - if (message.messages && message.messages.length) { - object.messages = []; - for (let j = 0; j < message.messages.length; ++j) - object.messages[j] = $root.RPC.Message.toObject(message.messages[j], options); - } - if (message.control != null && message.hasOwnProperty("control")) { - object.control = $root.RPC.ControlMessage.toObject(message.control, options); - if (options.oneofs) - object._control = "control"; - } - return object; - }; - - /** - * Converts this RPC to JSON. - * @function toJSON - * @memberof RPC - * @instance - * @returns {Object.} JSON object - */ - RPC.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - /** - * Gets the default type url for RPC - * @function getTypeUrl - * @memberof RPC - * @static - * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns {string} The default type url - */ - RPC.getTypeUrl = function getTypeUrl(typeUrlPrefix) { - if (typeUrlPrefix === undefined) { - typeUrlPrefix = "type.googleapis.com"; - } - return typeUrlPrefix + "/RPC"; - }; - - RPC.SubOpts = (function() { - - /** - * Properties of a SubOpts. - * @memberof RPC - * @interface ISubOpts - * @property {boolean|null} [subscribe] SubOpts subscribe - * @property {string|null} [topic] SubOpts topic - */ - - /** - * Constructs a new SubOpts. - * @memberof RPC - * @classdesc Represents a SubOpts. - * @implements ISubOpts - * @constructor - * @param {RPC.ISubOpts=} [properties] Properties to set - */ - function SubOpts(properties) { - if (properties) - for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * SubOpts subscribe. - * @member {boolean|null|undefined} subscribe - * @memberof RPC.SubOpts - * @instance - */ - SubOpts.prototype.subscribe = null; - - /** - * SubOpts topic. - * @member {string|null|undefined} topic - * @memberof RPC.SubOpts - * @instance - */ - SubOpts.prototype.topic = null; - - // OneOf field names bound to virtual getters and setters - let $oneOfFields; - - /** - * SubOpts _subscribe. - * @member {"subscribe"|undefined} _subscribe - * @memberof RPC.SubOpts - * @instance - */ - Object.defineProperty(SubOpts.prototype, "_subscribe", { - get: $util.oneOfGetter($oneOfFields = ["subscribe"]), - set: $util.oneOfSetter($oneOfFields) - }); - - /** - * SubOpts _topic. - * @member {"topic"|undefined} _topic - * @memberof RPC.SubOpts - * @instance - */ - Object.defineProperty(SubOpts.prototype, "_topic", { - get: $util.oneOfGetter($oneOfFields = ["topic"]), - set: $util.oneOfSetter($oneOfFields) - }); - - /** - * Creates a new SubOpts instance using the specified properties. - * @function create - * @memberof RPC.SubOpts - * @static - * @param {RPC.ISubOpts=} [properties] Properties to set - * @returns {RPC.SubOpts} SubOpts instance - */ - SubOpts.create = function create(properties) { - return new SubOpts(properties); - }; - - /** - * Encodes the specified SubOpts message. Does not implicitly {@link RPC.SubOpts.verify|verify} messages. - * @function encode - * @memberof RPC.SubOpts - * @static - * @param {RPC.ISubOpts} message SubOpts message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - SubOpts.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.subscribe != null && Object.hasOwnProperty.call(message, "subscribe")) - writer.uint32(/* id 1, wireType 0 =*/8).bool(message.subscribe); - if (message.topic != null && Object.hasOwnProperty.call(message, "topic")) - writer.uint32(/* id 2, wireType 2 =*/18).string(message.topic); - return writer; - }; - - /** - * Encodes the specified SubOpts message, length delimited. Does not implicitly {@link RPC.SubOpts.verify|verify} messages. - * @function encodeDelimited - * @memberof RPC.SubOpts - * @static - * @param {RPC.ISubOpts} message SubOpts message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - SubOpts.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a SubOpts message from the specified reader or buffer. - * @function decode - * @memberof RPC.SubOpts - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {RPC.SubOpts} SubOpts - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - SubOpts.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - let end = length === undefined ? reader.len : reader.pos + length, message = new $root.RPC.SubOpts(); - while (reader.pos < end) { - let tag = reader.uint32(); - switch (tag >>> 3) { - case 1: { - message.subscribe = reader.bool(); - break; - } - case 2: { - message.topic = reader.string(); - break; - } - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a SubOpts message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof RPC.SubOpts - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {RPC.SubOpts} SubOpts - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - SubOpts.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a SubOpts message. - * @function verify - * @memberof RPC.SubOpts - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - SubOpts.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - let properties = {}; - if (message.subscribe != null && message.hasOwnProperty("subscribe")) { - properties._subscribe = 1; - if (typeof message.subscribe !== "boolean") - return "subscribe: boolean expected"; - } - if (message.topic != null && message.hasOwnProperty("topic")) { - properties._topic = 1; - if (!$util.isString(message.topic)) - return "topic: string expected"; - } - return null; - }; - - /** - * Creates a SubOpts message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof RPC.SubOpts - * @static - * @param {Object.} object Plain object - * @returns {RPC.SubOpts} SubOpts - */ - SubOpts.fromObject = function fromObject(object) { - if (object instanceof $root.RPC.SubOpts) - return object; - let message = new $root.RPC.SubOpts(); - if (object.subscribe != null) - message.subscribe = Boolean(object.subscribe); - if (object.topic != null) - message.topic = String(object.topic); - return message; - }; - - /** - * Creates a plain object from a SubOpts message. Also converts values to other types if specified. - * @function toObject - * @memberof RPC.SubOpts - * @static - * @param {RPC.SubOpts} message SubOpts - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - SubOpts.toObject = function toObject(message, options) { - if (!options) - options = {}; - let object = {}; - if (message.subscribe != null && message.hasOwnProperty("subscribe")) { - object.subscribe = message.subscribe; - if (options.oneofs) - object._subscribe = "subscribe"; - } - if (message.topic != null && message.hasOwnProperty("topic")) { - object.topic = message.topic; - if (options.oneofs) - object._topic = "topic"; - } - return object; - }; - - /** - * Converts this SubOpts to JSON. - * @function toJSON - * @memberof RPC.SubOpts - * @instance - * @returns {Object.} JSON object - */ - SubOpts.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - /** - * Gets the default type url for SubOpts - * @function getTypeUrl - * @memberof RPC.SubOpts - * @static - * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns {string} The default type url - */ - SubOpts.getTypeUrl = function getTypeUrl(typeUrlPrefix) { - if (typeUrlPrefix === undefined) { - typeUrlPrefix = "type.googleapis.com"; - } - return typeUrlPrefix + "/RPC.SubOpts"; - }; - - return SubOpts; - })(); - - RPC.Message = (function() { - - /** - * Properties of a Message. - * @memberof RPC - * @interface IMessage - * @property {Uint8Array|null} [from] Message from - * @property {Uint8Array|null} [data] Message data - * @property {Uint8Array|null} [seqno] Message seqno - * @property {string} topic Message topic - * @property {Uint8Array|null} [signature] Message signature - * @property {Uint8Array|null} [key] Message key - */ - - /** - * Constructs a new Message. - * @memberof RPC - * @classdesc Represents a Message. - * @implements IMessage - * @constructor - * @param {RPC.IMessage=} [properties] Properties to set - */ - function Message(properties) { - if (properties) - for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * Message from. - * @member {Uint8Array|null|undefined} from - * @memberof RPC.Message - * @instance - */ - Message.prototype.from = null; - - /** - * Message data. - * @member {Uint8Array|null|undefined} data - * @memberof RPC.Message - * @instance - */ - Message.prototype.data = null; - - /** - * Message seqno. - * @member {Uint8Array|null|undefined} seqno - * @memberof RPC.Message - * @instance - */ - Message.prototype.seqno = null; - - /** - * Message topic. - * @member {string} topic - * @memberof RPC.Message - * @instance - */ - Message.prototype.topic = ""; - - /** - * Message signature. - * @member {Uint8Array|null|undefined} signature - * @memberof RPC.Message - * @instance - */ - Message.prototype.signature = null; - - /** - * Message key. - * @member {Uint8Array|null|undefined} key - * @memberof RPC.Message - * @instance - */ - Message.prototype.key = null; - - // OneOf field names bound to virtual getters and setters - let $oneOfFields; - - /** - * Message _from. - * @member {"from"|undefined} _from - * @memberof RPC.Message - * @instance - */ - Object.defineProperty(Message.prototype, "_from", { - get: $util.oneOfGetter($oneOfFields = ["from"]), - set: $util.oneOfSetter($oneOfFields) - }); - - /** - * Message _data. - * @member {"data"|undefined} _data - * @memberof RPC.Message - * @instance - */ - Object.defineProperty(Message.prototype, "_data", { - get: $util.oneOfGetter($oneOfFields = ["data"]), - set: $util.oneOfSetter($oneOfFields) - }); - - /** - * Message _seqno. - * @member {"seqno"|undefined} _seqno - * @memberof RPC.Message - * @instance - */ - Object.defineProperty(Message.prototype, "_seqno", { - get: $util.oneOfGetter($oneOfFields = ["seqno"]), - set: $util.oneOfSetter($oneOfFields) - }); - - /** - * Message _signature. - * @member {"signature"|undefined} _signature - * @memberof RPC.Message - * @instance - */ - Object.defineProperty(Message.prototype, "_signature", { - get: $util.oneOfGetter($oneOfFields = ["signature"]), - set: $util.oneOfSetter($oneOfFields) - }); - - /** - * Message _key. - * @member {"key"|undefined} _key - * @memberof RPC.Message - * @instance - */ - Object.defineProperty(Message.prototype, "_key", { - get: $util.oneOfGetter($oneOfFields = ["key"]), - set: $util.oneOfSetter($oneOfFields) - }); - - /** - * Creates a new Message instance using the specified properties. - * @function create - * @memberof RPC.Message - * @static - * @param {RPC.IMessage=} [properties] Properties to set - * @returns {RPC.Message} Message instance - */ - Message.create = function create(properties) { - return new Message(properties); - }; - - /** - * Encodes the specified Message message. Does not implicitly {@link RPC.Message.verify|verify} messages. - * @function encode - * @memberof RPC.Message - * @static - * @param {RPC.IMessage} message Message message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - Message.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.from != null && Object.hasOwnProperty.call(message, "from")) - writer.uint32(/* id 1, wireType 2 =*/10).bytes(message.from); - if (message.data != null && Object.hasOwnProperty.call(message, "data")) - writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.data); - if (message.seqno != null && Object.hasOwnProperty.call(message, "seqno")) - writer.uint32(/* id 3, wireType 2 =*/26).bytes(message.seqno); - writer.uint32(/* id 4, wireType 2 =*/34).string(message.topic); - if (message.signature != null && Object.hasOwnProperty.call(message, "signature")) - writer.uint32(/* id 5, wireType 2 =*/42).bytes(message.signature); - if (message.key != null && Object.hasOwnProperty.call(message, "key")) - writer.uint32(/* id 6, wireType 2 =*/50).bytes(message.key); - return writer; - }; - - /** - * Encodes the specified Message message, length delimited. Does not implicitly {@link RPC.Message.verify|verify} messages. - * @function encodeDelimited - * @memberof RPC.Message - * @static - * @param {RPC.IMessage} message Message message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - Message.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a Message message from the specified reader or buffer. - * @function decode - * @memberof RPC.Message - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {RPC.Message} Message - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - Message.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - let end = length === undefined ? reader.len : reader.pos + length, message = new $root.RPC.Message(); - while (reader.pos < end) { - let tag = reader.uint32(); - switch (tag >>> 3) { - case 1: { - message.from = reader.bytes(); - break; - } - case 2: { - message.data = reader.bytes(); - break; - } - case 3: { - message.seqno = reader.bytes(); - break; - } - case 4: { - message.topic = reader.string(); - break; - } - case 5: { - message.signature = reader.bytes(); - break; - } - case 6: { - message.key = reader.bytes(); - break; - } - default: - reader.skipType(tag & 7); - break; - } - } - if (!message.hasOwnProperty("topic")) - throw $util.ProtocolError("missing required 'topic'", { instance: message }); - return message; - }; - - /** - * Decodes a Message message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof RPC.Message - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {RPC.Message} Message - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - Message.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a Message message. - * @function verify - * @memberof RPC.Message - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - Message.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - let properties = {}; - if (message.from != null && message.hasOwnProperty("from")) { - properties._from = 1; - if (!(message.from && typeof message.from.length === "number" || $util.isString(message.from))) - return "from: buffer expected"; - } - if (message.data != null && message.hasOwnProperty("data")) { - properties._data = 1; - if (!(message.data && typeof message.data.length === "number" || $util.isString(message.data))) - return "data: buffer expected"; - } - if (message.seqno != null && message.hasOwnProperty("seqno")) { - properties._seqno = 1; - if (!(message.seqno && typeof message.seqno.length === "number" || $util.isString(message.seqno))) - return "seqno: buffer expected"; - } - if (!$util.isString(message.topic)) - return "topic: string expected"; - if (message.signature != null && message.hasOwnProperty("signature")) { - properties._signature = 1; - if (!(message.signature && typeof message.signature.length === "number" || $util.isString(message.signature))) - return "signature: buffer expected"; - } - if (message.key != null && message.hasOwnProperty("key")) { - properties._key = 1; - if (!(message.key && typeof message.key.length === "number" || $util.isString(message.key))) - return "key: buffer expected"; - } - return null; - }; - - /** - * Creates a Message message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof RPC.Message - * @static - * @param {Object.} object Plain object - * @returns {RPC.Message} Message - */ - Message.fromObject = function fromObject(object) { - if (object instanceof $root.RPC.Message) - return object; - let message = new $root.RPC.Message(); - if (object.from != null) - if (typeof object.from === "string") - $util.base64.decode(object.from, message.from = $util.newBuffer($util.base64.length(object.from)), 0); - else if (object.from.length >= 0) - message.from = object.from; - if (object.data != null) - if (typeof object.data === "string") - $util.base64.decode(object.data, message.data = $util.newBuffer($util.base64.length(object.data)), 0); - else if (object.data.length >= 0) - message.data = object.data; - if (object.seqno != null) - if (typeof object.seqno === "string") - $util.base64.decode(object.seqno, message.seqno = $util.newBuffer($util.base64.length(object.seqno)), 0); - else if (object.seqno.length >= 0) - message.seqno = object.seqno; - if (object.topic != null) - message.topic = String(object.topic); - if (object.signature != null) - if (typeof object.signature === "string") - $util.base64.decode(object.signature, message.signature = $util.newBuffer($util.base64.length(object.signature)), 0); - else if (object.signature.length >= 0) - message.signature = object.signature; - if (object.key != null) - if (typeof object.key === "string") - $util.base64.decode(object.key, message.key = $util.newBuffer($util.base64.length(object.key)), 0); - else if (object.key.length >= 0) - message.key = object.key; - return message; - }; - - /** - * Creates a plain object from a Message message. Also converts values to other types if specified. - * @function toObject - * @memberof RPC.Message - * @static - * @param {RPC.Message} message Message - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - Message.toObject = function toObject(message, options) { - if (!options) - options = {}; - let object = {}; - if (options.defaults) - object.topic = ""; - if (message.from != null && message.hasOwnProperty("from")) { - object.from = options.bytes === String ? $util.base64.encode(message.from, 0, message.from.length) : options.bytes === Array ? Array.prototype.slice.call(message.from) : message.from; - if (options.oneofs) - object._from = "from"; - } - if (message.data != null && message.hasOwnProperty("data")) { - object.data = options.bytes === String ? $util.base64.encode(message.data, 0, message.data.length) : options.bytes === Array ? Array.prototype.slice.call(message.data) : message.data; - if (options.oneofs) - object._data = "data"; - } - if (message.seqno != null && message.hasOwnProperty("seqno")) { - object.seqno = options.bytes === String ? $util.base64.encode(message.seqno, 0, message.seqno.length) : options.bytes === Array ? Array.prototype.slice.call(message.seqno) : message.seqno; - if (options.oneofs) - object._seqno = "seqno"; - } - if (message.topic != null && message.hasOwnProperty("topic")) - object.topic = message.topic; - if (message.signature != null && message.hasOwnProperty("signature")) { - object.signature = options.bytes === String ? $util.base64.encode(message.signature, 0, message.signature.length) : options.bytes === Array ? Array.prototype.slice.call(message.signature) : message.signature; - if (options.oneofs) - object._signature = "signature"; - } - if (message.key != null && message.hasOwnProperty("key")) { - object.key = options.bytes === String ? $util.base64.encode(message.key, 0, message.key.length) : options.bytes === Array ? Array.prototype.slice.call(message.key) : message.key; - if (options.oneofs) - object._key = "key"; - } - return object; - }; - - /** - * Converts this Message to JSON. - * @function toJSON - * @memberof RPC.Message - * @instance - * @returns {Object.} JSON object - */ - Message.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - /** - * Gets the default type url for Message - * @function getTypeUrl - * @memberof RPC.Message - * @static - * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns {string} The default type url - */ - Message.getTypeUrl = function getTypeUrl(typeUrlPrefix) { - if (typeUrlPrefix === undefined) { - typeUrlPrefix = "type.googleapis.com"; - } - return typeUrlPrefix + "/RPC.Message"; - }; - - return Message; - })(); - - RPC.ControlMessage = (function() { - - /** - * Properties of a ControlMessage. - * @memberof RPC - * @interface IControlMessage - * @property {Array.|null} [ihave] ControlMessage ihave - * @property {Array.|null} [iwant] ControlMessage iwant - * @property {Array.|null} [graft] ControlMessage graft - * @property {Array.|null} [prune] ControlMessage prune - */ - - /** - * Constructs a new ControlMessage. - * @memberof RPC - * @classdesc Represents a ControlMessage. - * @implements IControlMessage - * @constructor - * @param {RPC.IControlMessage=} [properties] Properties to set - */ - function ControlMessage(properties) { - this.ihave = []; - this.iwant = []; - this.graft = []; - this.prune = []; - if (properties) - for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * ControlMessage ihave. - * @member {Array.} ihave - * @memberof RPC.ControlMessage - * @instance - */ - ControlMessage.prototype.ihave = $util.emptyArray; - - /** - * ControlMessage iwant. - * @member {Array.} iwant - * @memberof RPC.ControlMessage - * @instance - */ - ControlMessage.prototype.iwant = $util.emptyArray; - - /** - * ControlMessage graft. - * @member {Array.} graft - * @memberof RPC.ControlMessage - * @instance - */ - ControlMessage.prototype.graft = $util.emptyArray; - - /** - * ControlMessage prune. - * @member {Array.} prune - * @memberof RPC.ControlMessage - * @instance - */ - ControlMessage.prototype.prune = $util.emptyArray; - - /** - * Creates a new ControlMessage instance using the specified properties. - * @function create - * @memberof RPC.ControlMessage - * @static - * @param {RPC.IControlMessage=} [properties] Properties to set - * @returns {RPC.ControlMessage} ControlMessage instance - */ - ControlMessage.create = function create(properties) { - return new ControlMessage(properties); - }; - - /** - * Encodes the specified ControlMessage message. Does not implicitly {@link RPC.ControlMessage.verify|verify} messages. - * @function encode - * @memberof RPC.ControlMessage - * @static - * @param {RPC.IControlMessage} message ControlMessage message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - ControlMessage.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.ihave != null && message.ihave.length) - for (let i = 0; i < message.ihave.length; ++i) - $root.RPC.ControlIHave.encode(message.ihave[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); - if (message.iwant != null && message.iwant.length) - for (let i = 0; i < message.iwant.length; ++i) - $root.RPC.ControlIWant.encode(message.iwant[i], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); - if (message.graft != null && message.graft.length) - for (let i = 0; i < message.graft.length; ++i) - $root.RPC.ControlGraft.encode(message.graft[i], writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); - if (message.prune != null && message.prune.length) - for (let i = 0; i < message.prune.length; ++i) - $root.RPC.ControlPrune.encode(message.prune[i], writer.uint32(/* id 4, wireType 2 =*/34).fork()).ldelim(); - return writer; - }; - - /** - * Encodes the specified ControlMessage message, length delimited. Does not implicitly {@link RPC.ControlMessage.verify|verify} messages. - * @function encodeDelimited - * @memberof RPC.ControlMessage - * @static - * @param {RPC.IControlMessage} message ControlMessage message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - ControlMessage.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a ControlMessage message from the specified reader or buffer. - * @function decode - * @memberof RPC.ControlMessage - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {RPC.ControlMessage} ControlMessage - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - ControlMessage.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - let end = length === undefined ? reader.len : reader.pos + length, message = new $root.RPC.ControlMessage(); - while (reader.pos < end) { - let tag = reader.uint32(); - switch (tag >>> 3) { - case 1: { - if (!(message.ihave && message.ihave.length)) - message.ihave = []; - message.ihave.push($root.RPC.ControlIHave.decode(reader, reader.uint32())); - break; - } - case 2: { - if (!(message.iwant && message.iwant.length)) - message.iwant = []; - message.iwant.push($root.RPC.ControlIWant.decode(reader, reader.uint32())); - break; - } - case 3: { - if (!(message.graft && message.graft.length)) - message.graft = []; - message.graft.push($root.RPC.ControlGraft.decode(reader, reader.uint32())); - break; - } - case 4: { - if (!(message.prune && message.prune.length)) - message.prune = []; - message.prune.push($root.RPC.ControlPrune.decode(reader, reader.uint32())); - break; - } - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a ControlMessage message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof RPC.ControlMessage - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {RPC.ControlMessage} ControlMessage - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - ControlMessage.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a ControlMessage message. - * @function verify - * @memberof RPC.ControlMessage - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - ControlMessage.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - if (message.ihave != null && message.hasOwnProperty("ihave")) { - if (!Array.isArray(message.ihave)) - return "ihave: array expected"; - for (let i = 0; i < message.ihave.length; ++i) { - let error = $root.RPC.ControlIHave.verify(message.ihave[i]); - if (error) - return "ihave." + error; - } - } - if (message.iwant != null && message.hasOwnProperty("iwant")) { - if (!Array.isArray(message.iwant)) - return "iwant: array expected"; - for (let i = 0; i < message.iwant.length; ++i) { - let error = $root.RPC.ControlIWant.verify(message.iwant[i]); - if (error) - return "iwant." + error; - } - } - if (message.graft != null && message.hasOwnProperty("graft")) { - if (!Array.isArray(message.graft)) - return "graft: array expected"; - for (let i = 0; i < message.graft.length; ++i) { - let error = $root.RPC.ControlGraft.verify(message.graft[i]); - if (error) - return "graft." + error; - } - } - if (message.prune != null && message.hasOwnProperty("prune")) { - if (!Array.isArray(message.prune)) - return "prune: array expected"; - for (let i = 0; i < message.prune.length; ++i) { - let error = $root.RPC.ControlPrune.verify(message.prune[i]); - if (error) - return "prune." + error; - } - } - return null; - }; - - /** - * Creates a ControlMessage message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof RPC.ControlMessage - * @static - * @param {Object.} object Plain object - * @returns {RPC.ControlMessage} ControlMessage - */ - ControlMessage.fromObject = function fromObject(object) { - if (object instanceof $root.RPC.ControlMessage) - return object; - let message = new $root.RPC.ControlMessage(); - if (object.ihave) { - if (!Array.isArray(object.ihave)) - throw TypeError(".RPC.ControlMessage.ihave: array expected"); - message.ihave = []; - for (let i = 0; i < object.ihave.length; ++i) { - if (typeof object.ihave[i] !== "object") - throw TypeError(".RPC.ControlMessage.ihave: object expected"); - message.ihave[i] = $root.RPC.ControlIHave.fromObject(object.ihave[i]); - } - } - if (object.iwant) { - if (!Array.isArray(object.iwant)) - throw TypeError(".RPC.ControlMessage.iwant: array expected"); - message.iwant = []; - for (let i = 0; i < object.iwant.length; ++i) { - if (typeof object.iwant[i] !== "object") - throw TypeError(".RPC.ControlMessage.iwant: object expected"); - message.iwant[i] = $root.RPC.ControlIWant.fromObject(object.iwant[i]); - } - } - if (object.graft) { - if (!Array.isArray(object.graft)) - throw TypeError(".RPC.ControlMessage.graft: array expected"); - message.graft = []; - for (let i = 0; i < object.graft.length; ++i) { - if (typeof object.graft[i] !== "object") - throw TypeError(".RPC.ControlMessage.graft: object expected"); - message.graft[i] = $root.RPC.ControlGraft.fromObject(object.graft[i]); - } - } - if (object.prune) { - if (!Array.isArray(object.prune)) - throw TypeError(".RPC.ControlMessage.prune: array expected"); - message.prune = []; - for (let i = 0; i < object.prune.length; ++i) { - if (typeof object.prune[i] !== "object") - throw TypeError(".RPC.ControlMessage.prune: object expected"); - message.prune[i] = $root.RPC.ControlPrune.fromObject(object.prune[i]); - } - } - return message; - }; - - /** - * Creates a plain object from a ControlMessage message. Also converts values to other types if specified. - * @function toObject - * @memberof RPC.ControlMessage - * @static - * @param {RPC.ControlMessage} message ControlMessage - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - ControlMessage.toObject = function toObject(message, options) { - if (!options) - options = {}; - let object = {}; - if (options.arrays || options.defaults) { - object.ihave = []; - object.iwant = []; - object.graft = []; - object.prune = []; - } - if (message.ihave && message.ihave.length) { - object.ihave = []; - for (let j = 0; j < message.ihave.length; ++j) - object.ihave[j] = $root.RPC.ControlIHave.toObject(message.ihave[j], options); - } - if (message.iwant && message.iwant.length) { - object.iwant = []; - for (let j = 0; j < message.iwant.length; ++j) - object.iwant[j] = $root.RPC.ControlIWant.toObject(message.iwant[j], options); - } - if (message.graft && message.graft.length) { - object.graft = []; - for (let j = 0; j < message.graft.length; ++j) - object.graft[j] = $root.RPC.ControlGraft.toObject(message.graft[j], options); - } - if (message.prune && message.prune.length) { - object.prune = []; - for (let j = 0; j < message.prune.length; ++j) - object.prune[j] = $root.RPC.ControlPrune.toObject(message.prune[j], options); - } - return object; - }; - - /** - * Converts this ControlMessage to JSON. - * @function toJSON - * @memberof RPC.ControlMessage - * @instance - * @returns {Object.} JSON object - */ - ControlMessage.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - /** - * Gets the default type url for ControlMessage - * @function getTypeUrl - * @memberof RPC.ControlMessage - * @static - * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns {string} The default type url - */ - ControlMessage.getTypeUrl = function getTypeUrl(typeUrlPrefix) { - if (typeUrlPrefix === undefined) { - typeUrlPrefix = "type.googleapis.com"; - } - return typeUrlPrefix + "/RPC.ControlMessage"; - }; - - return ControlMessage; - })(); - - RPC.ControlIHave = (function() { - - /** - * Properties of a ControlIHave. - * @memberof RPC - * @interface IControlIHave - * @property {string|null} [topicID] ControlIHave topicID - * @property {Array.|null} [messageIDs] ControlIHave messageIDs - */ - - /** - * Constructs a new ControlIHave. - * @memberof RPC - * @classdesc Represents a ControlIHave. - * @implements IControlIHave - * @constructor - * @param {RPC.IControlIHave=} [properties] Properties to set - */ - function ControlIHave(properties) { - this.messageIDs = []; - if (properties) - for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * ControlIHave topicID. - * @member {string|null|undefined} topicID - * @memberof RPC.ControlIHave - * @instance - */ - ControlIHave.prototype.topicID = null; - - /** - * ControlIHave messageIDs. - * @member {Array.} messageIDs - * @memberof RPC.ControlIHave - * @instance - */ - ControlIHave.prototype.messageIDs = $util.emptyArray; - - // OneOf field names bound to virtual getters and setters - let $oneOfFields; - - /** - * ControlIHave _topicID. - * @member {"topicID"|undefined} _topicID - * @memberof RPC.ControlIHave - * @instance - */ - Object.defineProperty(ControlIHave.prototype, "_topicID", { - get: $util.oneOfGetter($oneOfFields = ["topicID"]), - set: $util.oneOfSetter($oneOfFields) - }); - - /** - * Creates a new ControlIHave instance using the specified properties. - * @function create - * @memberof RPC.ControlIHave - * @static - * @param {RPC.IControlIHave=} [properties] Properties to set - * @returns {RPC.ControlIHave} ControlIHave instance - */ - ControlIHave.create = function create(properties) { - return new ControlIHave(properties); - }; - - /** - * Encodes the specified ControlIHave message. Does not implicitly {@link RPC.ControlIHave.verify|verify} messages. - * @function encode - * @memberof RPC.ControlIHave - * @static - * @param {RPC.IControlIHave} message ControlIHave message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - ControlIHave.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.topicID != null && Object.hasOwnProperty.call(message, "topicID")) - writer.uint32(/* id 1, wireType 2 =*/10).string(message.topicID); - if (message.messageIDs != null && message.messageIDs.length) - for (let i = 0; i < message.messageIDs.length; ++i) - writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.messageIDs[i]); - return writer; - }; - - /** - * Encodes the specified ControlIHave message, length delimited. Does not implicitly {@link RPC.ControlIHave.verify|verify} messages. - * @function encodeDelimited - * @memberof RPC.ControlIHave - * @static - * @param {RPC.IControlIHave} message ControlIHave message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - ControlIHave.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a ControlIHave message from the specified reader or buffer. - * @function decode - * @memberof RPC.ControlIHave - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {RPC.ControlIHave} ControlIHave - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - ControlIHave.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - let end = length === undefined ? reader.len : reader.pos + length, message = new $root.RPC.ControlIHave(); - while (reader.pos < end) { - let tag = reader.uint32(); - switch (tag >>> 3) { - case 1: { - message.topicID = reader.string(); - break; - } - case 2: { - if (!(message.messageIDs && message.messageIDs.length)) - message.messageIDs = []; - message.messageIDs.push(reader.bytes()); - break; - } - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a ControlIHave message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof RPC.ControlIHave - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {RPC.ControlIHave} ControlIHave - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - ControlIHave.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a ControlIHave message. - * @function verify - * @memberof RPC.ControlIHave - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - ControlIHave.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - let properties = {}; - if (message.topicID != null && message.hasOwnProperty("topicID")) { - properties._topicID = 1; - if (!$util.isString(message.topicID)) - return "topicID: string expected"; - } - if (message.messageIDs != null && message.hasOwnProperty("messageIDs")) { - if (!Array.isArray(message.messageIDs)) - return "messageIDs: array expected"; - for (let i = 0; i < message.messageIDs.length; ++i) - if (!(message.messageIDs[i] && typeof message.messageIDs[i].length === "number" || $util.isString(message.messageIDs[i]))) - return "messageIDs: buffer[] expected"; - } - return null; - }; - - /** - * Creates a ControlIHave message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof RPC.ControlIHave - * @static - * @param {Object.} object Plain object - * @returns {RPC.ControlIHave} ControlIHave - */ - ControlIHave.fromObject = function fromObject(object) { - if (object instanceof $root.RPC.ControlIHave) - return object; - let message = new $root.RPC.ControlIHave(); - if (object.topicID != null) - message.topicID = String(object.topicID); - if (object.messageIDs) { - if (!Array.isArray(object.messageIDs)) - throw TypeError(".RPC.ControlIHave.messageIDs: array expected"); - message.messageIDs = []; - for (let i = 0; i < object.messageIDs.length; ++i) - if (typeof object.messageIDs[i] === "string") - $util.base64.decode(object.messageIDs[i], message.messageIDs[i] = $util.newBuffer($util.base64.length(object.messageIDs[i])), 0); - else if (object.messageIDs[i].length >= 0) - message.messageIDs[i] = object.messageIDs[i]; - } - return message; - }; - - /** - * Creates a plain object from a ControlIHave message. Also converts values to other types if specified. - * @function toObject - * @memberof RPC.ControlIHave - * @static - * @param {RPC.ControlIHave} message ControlIHave - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - ControlIHave.toObject = function toObject(message, options) { - if (!options) - options = {}; - let object = {}; - if (options.arrays || options.defaults) - object.messageIDs = []; - if (message.topicID != null && message.hasOwnProperty("topicID")) { - object.topicID = message.topicID; - if (options.oneofs) - object._topicID = "topicID"; - } - if (message.messageIDs && message.messageIDs.length) { - object.messageIDs = []; - for (let j = 0; j < message.messageIDs.length; ++j) - object.messageIDs[j] = options.bytes === String ? $util.base64.encode(message.messageIDs[j], 0, message.messageIDs[j].length) : options.bytes === Array ? Array.prototype.slice.call(message.messageIDs[j]) : message.messageIDs[j]; - } - return object; - }; - - /** - * Converts this ControlIHave to JSON. - * @function toJSON - * @memberof RPC.ControlIHave - * @instance - * @returns {Object.} JSON object - */ - ControlIHave.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - /** - * Gets the default type url for ControlIHave - * @function getTypeUrl - * @memberof RPC.ControlIHave - * @static - * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns {string} The default type url - */ - ControlIHave.getTypeUrl = function getTypeUrl(typeUrlPrefix) { - if (typeUrlPrefix === undefined) { - typeUrlPrefix = "type.googleapis.com"; - } - return typeUrlPrefix + "/RPC.ControlIHave"; - }; - - return ControlIHave; - })(); - - RPC.ControlIWant = (function() { - - /** - * Properties of a ControlIWant. - * @memberof RPC - * @interface IControlIWant - * @property {Array.|null} [messageIDs] ControlIWant messageIDs - */ - - /** - * Constructs a new ControlIWant. - * @memberof RPC - * @classdesc Represents a ControlIWant. - * @implements IControlIWant - * @constructor - * @param {RPC.IControlIWant=} [properties] Properties to set - */ - function ControlIWant(properties) { - this.messageIDs = []; - if (properties) - for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * ControlIWant messageIDs. - * @member {Array.} messageIDs - * @memberof RPC.ControlIWant - * @instance - */ - ControlIWant.prototype.messageIDs = $util.emptyArray; - - /** - * Creates a new ControlIWant instance using the specified properties. - * @function create - * @memberof RPC.ControlIWant - * @static - * @param {RPC.IControlIWant=} [properties] Properties to set - * @returns {RPC.ControlIWant} ControlIWant instance - */ - ControlIWant.create = function create(properties) { - return new ControlIWant(properties); - }; - - /** - * Encodes the specified ControlIWant message. Does not implicitly {@link RPC.ControlIWant.verify|verify} messages. - * @function encode - * @memberof RPC.ControlIWant - * @static - * @param {RPC.IControlIWant} message ControlIWant message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - ControlIWant.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.messageIDs != null && message.messageIDs.length) - for (let i = 0; i < message.messageIDs.length; ++i) - writer.uint32(/* id 1, wireType 2 =*/10).bytes(message.messageIDs[i]); - return writer; - }; - - /** - * Encodes the specified ControlIWant message, length delimited. Does not implicitly {@link RPC.ControlIWant.verify|verify} messages. - * @function encodeDelimited - * @memberof RPC.ControlIWant - * @static - * @param {RPC.IControlIWant} message ControlIWant message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - ControlIWant.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a ControlIWant message from the specified reader or buffer. - * @function decode - * @memberof RPC.ControlIWant - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {RPC.ControlIWant} ControlIWant - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - ControlIWant.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - let end = length === undefined ? reader.len : reader.pos + length, message = new $root.RPC.ControlIWant(); - while (reader.pos < end) { - let tag = reader.uint32(); - switch (tag >>> 3) { - case 1: { - if (!(message.messageIDs && message.messageIDs.length)) - message.messageIDs = []; - message.messageIDs.push(reader.bytes()); - break; - } - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a ControlIWant message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof RPC.ControlIWant - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {RPC.ControlIWant} ControlIWant - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - ControlIWant.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a ControlIWant message. - * @function verify - * @memberof RPC.ControlIWant - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - ControlIWant.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - if (message.messageIDs != null && message.hasOwnProperty("messageIDs")) { - if (!Array.isArray(message.messageIDs)) - return "messageIDs: array expected"; - for (let i = 0; i < message.messageIDs.length; ++i) - if (!(message.messageIDs[i] && typeof message.messageIDs[i].length === "number" || $util.isString(message.messageIDs[i]))) - return "messageIDs: buffer[] expected"; - } - return null; - }; - - /** - * Creates a ControlIWant message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof RPC.ControlIWant - * @static - * @param {Object.} object Plain object - * @returns {RPC.ControlIWant} ControlIWant - */ - ControlIWant.fromObject = function fromObject(object) { - if (object instanceof $root.RPC.ControlIWant) - return object; - let message = new $root.RPC.ControlIWant(); - if (object.messageIDs) { - if (!Array.isArray(object.messageIDs)) - throw TypeError(".RPC.ControlIWant.messageIDs: array expected"); - message.messageIDs = []; - for (let i = 0; i < object.messageIDs.length; ++i) - if (typeof object.messageIDs[i] === "string") - $util.base64.decode(object.messageIDs[i], message.messageIDs[i] = $util.newBuffer($util.base64.length(object.messageIDs[i])), 0); - else if (object.messageIDs[i].length >= 0) - message.messageIDs[i] = object.messageIDs[i]; - } - return message; - }; - - /** - * Creates a plain object from a ControlIWant message. Also converts values to other types if specified. - * @function toObject - * @memberof RPC.ControlIWant - * @static - * @param {RPC.ControlIWant} message ControlIWant - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - ControlIWant.toObject = function toObject(message, options) { - if (!options) - options = {}; - let object = {}; - if (options.arrays || options.defaults) - object.messageIDs = []; - if (message.messageIDs && message.messageIDs.length) { - object.messageIDs = []; - for (let j = 0; j < message.messageIDs.length; ++j) - object.messageIDs[j] = options.bytes === String ? $util.base64.encode(message.messageIDs[j], 0, message.messageIDs[j].length) : options.bytes === Array ? Array.prototype.slice.call(message.messageIDs[j]) : message.messageIDs[j]; - } - return object; - }; - - /** - * Converts this ControlIWant to JSON. - * @function toJSON - * @memberof RPC.ControlIWant - * @instance - * @returns {Object.} JSON object - */ - ControlIWant.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - /** - * Gets the default type url for ControlIWant - * @function getTypeUrl - * @memberof RPC.ControlIWant - * @static - * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns {string} The default type url - */ - ControlIWant.getTypeUrl = function getTypeUrl(typeUrlPrefix) { - if (typeUrlPrefix === undefined) { - typeUrlPrefix = "type.googleapis.com"; - } - return typeUrlPrefix + "/RPC.ControlIWant"; - }; - - return ControlIWant; - })(); - - RPC.ControlGraft = (function() { - - /** - * Properties of a ControlGraft. - * @memberof RPC - * @interface IControlGraft - * @property {string|null} [topicID] ControlGraft topicID - */ - - /** - * Constructs a new ControlGraft. - * @memberof RPC - * @classdesc Represents a ControlGraft. - * @implements IControlGraft - * @constructor - * @param {RPC.IControlGraft=} [properties] Properties to set - */ - function ControlGraft(properties) { - if (properties) - for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * ControlGraft topicID. - * @member {string|null|undefined} topicID - * @memberof RPC.ControlGraft - * @instance - */ - ControlGraft.prototype.topicID = null; - - // OneOf field names bound to virtual getters and setters - let $oneOfFields; - - /** - * ControlGraft _topicID. - * @member {"topicID"|undefined} _topicID - * @memberof RPC.ControlGraft - * @instance - */ - Object.defineProperty(ControlGraft.prototype, "_topicID", { - get: $util.oneOfGetter($oneOfFields = ["topicID"]), - set: $util.oneOfSetter($oneOfFields) - }); - - /** - * Creates a new ControlGraft instance using the specified properties. - * @function create - * @memberof RPC.ControlGraft - * @static - * @param {RPC.IControlGraft=} [properties] Properties to set - * @returns {RPC.ControlGraft} ControlGraft instance - */ - ControlGraft.create = function create(properties) { - return new ControlGraft(properties); - }; - - /** - * Encodes the specified ControlGraft message. Does not implicitly {@link RPC.ControlGraft.verify|verify} messages. - * @function encode - * @memberof RPC.ControlGraft - * @static - * @param {RPC.IControlGraft} message ControlGraft message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - ControlGraft.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.topicID != null && Object.hasOwnProperty.call(message, "topicID")) - writer.uint32(/* id 1, wireType 2 =*/10).string(message.topicID); - return writer; - }; - - /** - * Encodes the specified ControlGraft message, length delimited. Does not implicitly {@link RPC.ControlGraft.verify|verify} messages. - * @function encodeDelimited - * @memberof RPC.ControlGraft - * @static - * @param {RPC.IControlGraft} message ControlGraft message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - ControlGraft.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a ControlGraft message from the specified reader or buffer. - * @function decode - * @memberof RPC.ControlGraft - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {RPC.ControlGraft} ControlGraft - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - ControlGraft.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - let end = length === undefined ? reader.len : reader.pos + length, message = new $root.RPC.ControlGraft(); - while (reader.pos < end) { - let tag = reader.uint32(); - switch (tag >>> 3) { - case 1: { - message.topicID = reader.string(); - break; - } - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a ControlGraft message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof RPC.ControlGraft - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {RPC.ControlGraft} ControlGraft - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - ControlGraft.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a ControlGraft message. - * @function verify - * @memberof RPC.ControlGraft - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - ControlGraft.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - let properties = {}; - if (message.topicID != null && message.hasOwnProperty("topicID")) { - properties._topicID = 1; - if (!$util.isString(message.topicID)) - return "topicID: string expected"; - } - return null; - }; - - /** - * Creates a ControlGraft message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof RPC.ControlGraft - * @static - * @param {Object.} object Plain object - * @returns {RPC.ControlGraft} ControlGraft - */ - ControlGraft.fromObject = function fromObject(object) { - if (object instanceof $root.RPC.ControlGraft) - return object; - let message = new $root.RPC.ControlGraft(); - if (object.topicID != null) - message.topicID = String(object.topicID); - return message; - }; - - /** - * Creates a plain object from a ControlGraft message. Also converts values to other types if specified. - * @function toObject - * @memberof RPC.ControlGraft - * @static - * @param {RPC.ControlGraft} message ControlGraft - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - ControlGraft.toObject = function toObject(message, options) { - if (!options) - options = {}; - let object = {}; - if (message.topicID != null && message.hasOwnProperty("topicID")) { - object.topicID = message.topicID; - if (options.oneofs) - object._topicID = "topicID"; - } - return object; - }; - - /** - * Converts this ControlGraft to JSON. - * @function toJSON - * @memberof RPC.ControlGraft - * @instance - * @returns {Object.} JSON object - */ - ControlGraft.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - /** - * Gets the default type url for ControlGraft - * @function getTypeUrl - * @memberof RPC.ControlGraft - * @static - * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns {string} The default type url - */ - ControlGraft.getTypeUrl = function getTypeUrl(typeUrlPrefix) { - if (typeUrlPrefix === undefined) { - typeUrlPrefix = "type.googleapis.com"; - } - return typeUrlPrefix + "/RPC.ControlGraft"; - }; - - return ControlGraft; - })(); - - RPC.ControlPrune = (function() { - - /** - * Properties of a ControlPrune. - * @memberof RPC - * @interface IControlPrune - * @property {string|null} [topicID] ControlPrune topicID - * @property {Array.|null} [peers] ControlPrune peers - * @property {number|Long|null} [backoff] ControlPrune backoff - */ - - /** - * Constructs a new ControlPrune. - * @memberof RPC - * @classdesc Represents a ControlPrune. - * @implements IControlPrune - * @constructor - * @param {RPC.IControlPrune=} [properties] Properties to set - */ - function ControlPrune(properties) { - this.peers = []; - if (properties) - for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * ControlPrune topicID. - * @member {string|null|undefined} topicID - * @memberof RPC.ControlPrune - * @instance - */ - ControlPrune.prototype.topicID = null; - - /** - * ControlPrune peers. - * @member {Array.} peers - * @memberof RPC.ControlPrune - * @instance - */ - ControlPrune.prototype.peers = $util.emptyArray; - - /** - * ControlPrune backoff. - * @member {number|Long|null|undefined} backoff - * @memberof RPC.ControlPrune - * @instance - */ - ControlPrune.prototype.backoff = null; - - // OneOf field names bound to virtual getters and setters - let $oneOfFields; - - /** - * ControlPrune _topicID. - * @member {"topicID"|undefined} _topicID - * @memberof RPC.ControlPrune - * @instance - */ - Object.defineProperty(ControlPrune.prototype, "_topicID", { - get: $util.oneOfGetter($oneOfFields = ["topicID"]), - set: $util.oneOfSetter($oneOfFields) - }); - - /** - * ControlPrune _backoff. - * @member {"backoff"|undefined} _backoff - * @memberof RPC.ControlPrune - * @instance - */ - Object.defineProperty(ControlPrune.prototype, "_backoff", { - get: $util.oneOfGetter($oneOfFields = ["backoff"]), - set: $util.oneOfSetter($oneOfFields) - }); - - /** - * Creates a new ControlPrune instance using the specified properties. - * @function create - * @memberof RPC.ControlPrune - * @static - * @param {RPC.IControlPrune=} [properties] Properties to set - * @returns {RPC.ControlPrune} ControlPrune instance - */ - ControlPrune.create = function create(properties) { - return new ControlPrune(properties); - }; - - /** - * Encodes the specified ControlPrune message. Does not implicitly {@link RPC.ControlPrune.verify|verify} messages. - * @function encode - * @memberof RPC.ControlPrune - * @static - * @param {RPC.IControlPrune} message ControlPrune message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - ControlPrune.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.topicID != null && Object.hasOwnProperty.call(message, "topicID")) - writer.uint32(/* id 1, wireType 2 =*/10).string(message.topicID); - if (message.peers != null && message.peers.length) - for (let i = 0; i < message.peers.length; ++i) - $root.RPC.PeerInfo.encode(message.peers[i], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); - if (message.backoff != null && Object.hasOwnProperty.call(message, "backoff")) - writer.uint32(/* id 3, wireType 0 =*/24).uint64(message.backoff); - return writer; - }; - - /** - * Encodes the specified ControlPrune message, length delimited. Does not implicitly {@link RPC.ControlPrune.verify|verify} messages. - * @function encodeDelimited - * @memberof RPC.ControlPrune - * @static - * @param {RPC.IControlPrune} message ControlPrune message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - ControlPrune.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a ControlPrune message from the specified reader or buffer. - * @function decode - * @memberof RPC.ControlPrune - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {RPC.ControlPrune} ControlPrune - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - ControlPrune.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - let end = length === undefined ? reader.len : reader.pos + length, message = new $root.RPC.ControlPrune(); - while (reader.pos < end) { - let tag = reader.uint32(); - switch (tag >>> 3) { - case 1: { - message.topicID = reader.string(); - break; - } - case 2: { - if (!(message.peers && message.peers.length)) - message.peers = []; - message.peers.push($root.RPC.PeerInfo.decode(reader, reader.uint32())); - break; - } - case 3: { - message.backoff = reader.uint64(); - break; - } - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a ControlPrune message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof RPC.ControlPrune - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {RPC.ControlPrune} ControlPrune - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - ControlPrune.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a ControlPrune message. - * @function verify - * @memberof RPC.ControlPrune - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - ControlPrune.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - let properties = {}; - if (message.topicID != null && message.hasOwnProperty("topicID")) { - properties._topicID = 1; - if (!$util.isString(message.topicID)) - return "topicID: string expected"; - } - if (message.peers != null && message.hasOwnProperty("peers")) { - if (!Array.isArray(message.peers)) - return "peers: array expected"; - for (let i = 0; i < message.peers.length; ++i) { - let error = $root.RPC.PeerInfo.verify(message.peers[i]); - if (error) - return "peers." + error; - } - } - if (message.backoff != null && message.hasOwnProperty("backoff")) { - properties._backoff = 1; - if (!$util.isInteger(message.backoff) && !(message.backoff && $util.isInteger(message.backoff.low) && $util.isInteger(message.backoff.high))) - return "backoff: integer|Long expected"; - } - return null; - }; - - /** - * Creates a ControlPrune message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof RPC.ControlPrune - * @static - * @param {Object.} object Plain object - * @returns {RPC.ControlPrune} ControlPrune - */ - ControlPrune.fromObject = function fromObject(object) { - if (object instanceof $root.RPC.ControlPrune) - return object; - let message = new $root.RPC.ControlPrune(); - if (object.topicID != null) - message.topicID = String(object.topicID); - if (object.peers) { - if (!Array.isArray(object.peers)) - throw TypeError(".RPC.ControlPrune.peers: array expected"); - message.peers = []; - for (let i = 0; i < object.peers.length; ++i) { - if (typeof object.peers[i] !== "object") - throw TypeError(".RPC.ControlPrune.peers: object expected"); - message.peers[i] = $root.RPC.PeerInfo.fromObject(object.peers[i]); - } - } - if (object.backoff != null) - if ($util.Long) - (message.backoff = $util.Long.fromValue(object.backoff)).unsigned = true; - else if (typeof object.backoff === "string") - message.backoff = parseInt(object.backoff, 10); - else if (typeof object.backoff === "number") - message.backoff = object.backoff; - else if (typeof object.backoff === "object") - message.backoff = new $util.LongBits(object.backoff.low >>> 0, object.backoff.high >>> 0).toNumber(true); - return message; - }; - - /** - * Creates a plain object from a ControlPrune message. Also converts values to other types if specified. - * @function toObject - * @memberof RPC.ControlPrune - * @static - * @param {RPC.ControlPrune} message ControlPrune - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - ControlPrune.toObject = function toObject(message, options) { - if (!options) - options = {}; - let object = {}; - if (options.arrays || options.defaults) - object.peers = []; - if (message.topicID != null && message.hasOwnProperty("topicID")) { - object.topicID = message.topicID; - if (options.oneofs) - object._topicID = "topicID"; - } - if (message.peers && message.peers.length) { - object.peers = []; - for (let j = 0; j < message.peers.length; ++j) - object.peers[j] = $root.RPC.PeerInfo.toObject(message.peers[j], options); - } - if (message.backoff != null && message.hasOwnProperty("backoff")) { - if (typeof message.backoff === "number") - object.backoff = options.longs === String ? String(message.backoff) : message.backoff; - else - object.backoff = options.longs === String ? $util.Long.prototype.toString.call(message.backoff) : options.longs === Number ? new $util.LongBits(message.backoff.low >>> 0, message.backoff.high >>> 0).toNumber(true) : message.backoff; - if (options.oneofs) - object._backoff = "backoff"; - } - return object; - }; - - /** - * Converts this ControlPrune to JSON. - * @function toJSON - * @memberof RPC.ControlPrune - * @instance - * @returns {Object.} JSON object - */ - ControlPrune.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - /** - * Gets the default type url for ControlPrune - * @function getTypeUrl - * @memberof RPC.ControlPrune - * @static - * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns {string} The default type url - */ - ControlPrune.getTypeUrl = function getTypeUrl(typeUrlPrefix) { - if (typeUrlPrefix === undefined) { - typeUrlPrefix = "type.googleapis.com"; - } - return typeUrlPrefix + "/RPC.ControlPrune"; - }; - - return ControlPrune; - })(); - - RPC.PeerInfo = (function() { - - /** - * Properties of a PeerInfo. - * @memberof RPC - * @interface IPeerInfo - * @property {Uint8Array|null} [peerID] PeerInfo peerID - * @property {Uint8Array|null} [signedPeerRecord] PeerInfo signedPeerRecord - */ - - /** - * Constructs a new PeerInfo. - * @memberof RPC - * @classdesc Represents a PeerInfo. - * @implements IPeerInfo - * @constructor - * @param {RPC.IPeerInfo=} [properties] Properties to set - */ - function PeerInfo(properties) { - if (properties) - for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * PeerInfo peerID. - * @member {Uint8Array|null|undefined} peerID - * @memberof RPC.PeerInfo - * @instance - */ - PeerInfo.prototype.peerID = null; - - /** - * PeerInfo signedPeerRecord. - * @member {Uint8Array|null|undefined} signedPeerRecord - * @memberof RPC.PeerInfo - * @instance - */ - PeerInfo.prototype.signedPeerRecord = null; - - // OneOf field names bound to virtual getters and setters - let $oneOfFields; - - /** - * PeerInfo _peerID. - * @member {"peerID"|undefined} _peerID - * @memberof RPC.PeerInfo - * @instance - */ - Object.defineProperty(PeerInfo.prototype, "_peerID", { - get: $util.oneOfGetter($oneOfFields = ["peerID"]), - set: $util.oneOfSetter($oneOfFields) - }); - - /** - * PeerInfo _signedPeerRecord. - * @member {"signedPeerRecord"|undefined} _signedPeerRecord - * @memberof RPC.PeerInfo - * @instance - */ - Object.defineProperty(PeerInfo.prototype, "_signedPeerRecord", { - get: $util.oneOfGetter($oneOfFields = ["signedPeerRecord"]), - set: $util.oneOfSetter($oneOfFields) - }); - - /** - * Creates a new PeerInfo instance using the specified properties. - * @function create - * @memberof RPC.PeerInfo - * @static - * @param {RPC.IPeerInfo=} [properties] Properties to set - * @returns {RPC.PeerInfo} PeerInfo instance - */ - PeerInfo.create = function create(properties) { - return new PeerInfo(properties); - }; - - /** - * Encodes the specified PeerInfo message. Does not implicitly {@link RPC.PeerInfo.verify|verify} messages. - * @function encode - * @memberof RPC.PeerInfo - * @static - * @param {RPC.IPeerInfo} message PeerInfo message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - PeerInfo.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.peerID != null && Object.hasOwnProperty.call(message, "peerID")) - writer.uint32(/* id 1, wireType 2 =*/10).bytes(message.peerID); - if (message.signedPeerRecord != null && Object.hasOwnProperty.call(message, "signedPeerRecord")) - writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.signedPeerRecord); - return writer; - }; - - /** - * Encodes the specified PeerInfo message, length delimited. Does not implicitly {@link RPC.PeerInfo.verify|verify} messages. - * @function encodeDelimited - * @memberof RPC.PeerInfo - * @static - * @param {RPC.IPeerInfo} message PeerInfo message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - PeerInfo.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a PeerInfo message from the specified reader or buffer. - * @function decode - * @memberof RPC.PeerInfo - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {RPC.PeerInfo} PeerInfo - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - PeerInfo.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - let end = length === undefined ? reader.len : reader.pos + length, message = new $root.RPC.PeerInfo(); - while (reader.pos < end) { - let tag = reader.uint32(); - switch (tag >>> 3) { - case 1: { - message.peerID = reader.bytes(); - break; - } - case 2: { - message.signedPeerRecord = reader.bytes(); - break; - } - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a PeerInfo message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof RPC.PeerInfo - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {RPC.PeerInfo} PeerInfo - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - PeerInfo.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a PeerInfo message. - * @function verify - * @memberof RPC.PeerInfo - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - PeerInfo.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - let properties = {}; - if (message.peerID != null && message.hasOwnProperty("peerID")) { - properties._peerID = 1; - if (!(message.peerID && typeof message.peerID.length === "number" || $util.isString(message.peerID))) - return "peerID: buffer expected"; - } - if (message.signedPeerRecord != null && message.hasOwnProperty("signedPeerRecord")) { - properties._signedPeerRecord = 1; - if (!(message.signedPeerRecord && typeof message.signedPeerRecord.length === "number" || $util.isString(message.signedPeerRecord))) - return "signedPeerRecord: buffer expected"; - } - return null; - }; - - /** - * Creates a PeerInfo message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof RPC.PeerInfo - * @static - * @param {Object.} object Plain object - * @returns {RPC.PeerInfo} PeerInfo - */ - PeerInfo.fromObject = function fromObject(object) { - if (object instanceof $root.RPC.PeerInfo) - return object; - let message = new $root.RPC.PeerInfo(); - if (object.peerID != null) - if (typeof object.peerID === "string") - $util.base64.decode(object.peerID, message.peerID = $util.newBuffer($util.base64.length(object.peerID)), 0); - else if (object.peerID.length >= 0) - message.peerID = object.peerID; - if (object.signedPeerRecord != null) - if (typeof object.signedPeerRecord === "string") - $util.base64.decode(object.signedPeerRecord, message.signedPeerRecord = $util.newBuffer($util.base64.length(object.signedPeerRecord)), 0); - else if (object.signedPeerRecord.length >= 0) - message.signedPeerRecord = object.signedPeerRecord; - return message; - }; - - /** - * Creates a plain object from a PeerInfo message. Also converts values to other types if specified. - * @function toObject - * @memberof RPC.PeerInfo - * @static - * @param {RPC.PeerInfo} message PeerInfo - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - PeerInfo.toObject = function toObject(message, options) { - if (!options) - options = {}; - let object = {}; - if (message.peerID != null && message.hasOwnProperty("peerID")) { - object.peerID = options.bytes === String ? $util.base64.encode(message.peerID, 0, message.peerID.length) : options.bytes === Array ? Array.prototype.slice.call(message.peerID) : message.peerID; - if (options.oneofs) - object._peerID = "peerID"; - } - if (message.signedPeerRecord != null && message.hasOwnProperty("signedPeerRecord")) { - object.signedPeerRecord = options.bytes === String ? $util.base64.encode(message.signedPeerRecord, 0, message.signedPeerRecord.length) : options.bytes === Array ? Array.prototype.slice.call(message.signedPeerRecord) : message.signedPeerRecord; - if (options.oneofs) - object._signedPeerRecord = "signedPeerRecord"; - } - return object; - }; - - /** - * Converts this PeerInfo to JSON. - * @function toJSON - * @memberof RPC.PeerInfo - * @instance - * @returns {Object.} JSON object - */ - PeerInfo.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - /** - * Gets the default type url for PeerInfo - * @function getTypeUrl - * @memberof RPC.PeerInfo - * @static - * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") - * @returns {string} The default type url - */ - PeerInfo.getTypeUrl = function getTypeUrl(typeUrlPrefix) { - if (typeUrlPrefix === undefined) { - typeUrlPrefix = "type.googleapis.com"; - } - return typeUrlPrefix + "/RPC.PeerInfo"; - }; - - return PeerInfo; - })(); - - return RPC; -})(); - -export { $root as default }; diff --git a/packages/protons-benchmark/src/implementations/protons/bench.ts b/packages/protons-benchmark/src/implementations/protons/bench.ts index 0335913..ab6a14f 100644 --- a/packages/protons-benchmark/src/implementations/protons/bench.ts +++ b/packages/protons-benchmark/src/implementations/protons/bench.ts @@ -1,5 +1,7 @@ -import { encodeMessage, decodeMessage, message, enumeration } from 'protons-runtime' -import type { Codec } from 'protons-runtime' +/* eslint-disable require-yield */ + +import { decodeMessage, encodeMessage, enumeration, MaxLengthError, message, streamMessage } from 'protons-runtime' +import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' export interface Foo { @@ -24,7 +26,7 @@ export namespace Foo { if (opts.lengthDelimited !== false) { w.ldelim() } - }, (reader, length) => { + }, (reader, length, opts = {}) => { const obj: any = {} const end = length == null ? reader.len : reader.pos + length @@ -33,28 +35,59 @@ export namespace Foo { const tag = reader.uint32() switch (tag >>> 3) { - case 1: + case 1: { obj.baz = reader.uint32() break - default: + } + default: { reader.skipType(tag & 7) break + } } } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}baz`, + value: reader.uint32() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Foo): Uint8Array => { + export interface FooBazFieldEvent { + field: 'baz' + value: number + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Foo.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList): Foo => { - return decodeMessage(buf, Foo.codec()) + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Foo { + return decodeMessage(buf, Foo.codec(), opts) + } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Foo.codec(), opts) } } @@ -74,15 +107,13 @@ export namespace Bar { if (obj.tmp != null) { w.uint32(10) - Foo.codec().encode(obj.tmp, w, { - writeDefaults: false - }) + Foo.codec().encode(obj.tmp, w) } if (opts.lengthDelimited !== false) { w.ldelim() } - }, (reader, length) => { + }, (reader, length, opts = {}) => { const obj: any = {} const end = length == null ? reader.len : reader.pos + length @@ -91,28 +122,63 @@ export namespace Bar { const tag = reader.uint32() switch (tag >>> 3) { - case 1: - obj.tmp = Foo.codec().decode(reader, reader.uint32()) + case 1: { + obj.tmp = Foo.codec().decode(reader, reader.uint32(), { + limits: opts.limits?.tmp + }) break - default: + } + default: { reader.skipType(tag & 7) break + } } } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}tmp`, + value: Foo.codec().decode(reader, reader.uint32(), { + limits: opts.limits?.tmp + }) + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Bar): Uint8Array => { + export interface BarTmpFooBazFieldEvent { + field: 'baz' + value: number + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Bar.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList): Bar => { - return decodeMessage(buf, Bar.codec()) + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Bar { + return decodeMessage(buf, Bar.codec(), opts) + } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Bar.codec(), opts) } } @@ -133,6 +199,7 @@ export namespace FOO { return enumeration(__FOOValues) } } + export interface Yo { lol: FOO[] } @@ -157,7 +224,7 @@ export namespace Yo { if (opts.lengthDelimited !== false) { w.ldelim() } - }, (reader, length) => { + }, (reader, length, opts = {}) => { const obj: any = { lol: [] } @@ -168,28 +235,71 @@ export namespace Yo { const tag = reader.uint32() switch (tag >>> 3) { - case 1: + case 1: { + if (opts.limits?.lol != null && obj.lol.length === opts.limits.lol) { + throw new MaxLengthError('Decode error - repeated field "lol" had too many elements') + } + obj.lol.push(FOO.codec().decode(reader)) break - default: + } + default: { reader.skipType(tag & 7) break + } } } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + lol: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + if (opts.limits?.lol != null && obj.lol === opts.limits.lol) { + throw new MaxLengthError('Decode error - repeated field "lol" had too many elements') + } + + const value = FOO.codec().decode(reader) + obj.lol++ + + yield { + field: `${prefix != null ? `${prefix}.` : ''}lol`, + index: obj.lol, + value + } + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Yo): Uint8Array => { + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Yo.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList): Yo => { - return decodeMessage(buf, Yo.codec()) + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Yo { + return decodeMessage(buf, Yo.codec(), opts) + } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator<{}> { + return streamMessage(buf, Yo.codec(), opts) } } @@ -215,15 +325,13 @@ export namespace Lol { if (obj.b != null) { w.uint32(18) - Bar.codec().encode(obj.b, w, { - writeDefaults: false - }) + Bar.codec().encode(obj.b, w) } if (opts.lengthDelimited !== false) { w.ldelim() } - }, (reader, length) => { + }, (reader, length, opts = {}) => { const obj: any = {} const end = length == null ? reader.len : reader.pos + length @@ -232,31 +340,79 @@ export namespace Lol { const tag = reader.uint32() switch (tag >>> 3) { - case 1: + case 1: { obj.lol = reader.string() break - case 2: - obj.b = Bar.codec().decode(reader, reader.uint32()) + } + case 2: { + obj.b = Bar.codec().decode(reader, reader.uint32(), { + limits: opts.limits?.b + }) break - default: + } + default: { reader.skipType(tag & 7) break + } } } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}lol`, + value: reader.string() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}b`, + value: Bar.codec().decode(reader, reader.uint32(), { + limits: opts.limits?.b + }) + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Lol): Uint8Array => { + export interface LolLolFieldEvent { + field: 'lol' + value: string + } + + export interface LolBBarTmpFooBazFieldEvent { + field: 'baz' + value: number + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Lol.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList): Lol => { - return decodeMessage(buf, Lol.codec()) + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Lol { + return decodeMessage(buf, Lol.codec(), opts) + } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Lol.codec(), opts) } } @@ -279,9 +435,7 @@ export namespace Test { if (obj.meh != null) { w.uint32(50) - Lol.codec().encode(obj.meh, w, { - writeDefaults: false - }) + Lol.codec().encode(obj.meh, w) } if (obj.hello != null) { @@ -302,7 +456,7 @@ export namespace Test { if (opts.lengthDelimited !== false) { w.ldelim() } - }, (reader, length) => { + }, (reader, length, opts = {}) => { const obj: any = {} const end = length == null ? reader.len : reader.pos + length @@ -311,36 +465,115 @@ export namespace Test { const tag = reader.uint32() switch (tag >>> 3) { - case 6: - obj.meh = Lol.codec().decode(reader, reader.uint32()) + case 6: { + obj.meh = Lol.codec().decode(reader, reader.uint32(), { + limits: opts.limits?.meh + }) break - case 3: + } + case 3: { obj.hello = reader.uint32() break - case 1: + } + case 1: { obj.foo = reader.string() break - case 7: + } + case 7: { obj.payload = reader.bytes() break - default: + } + default: { reader.skipType(tag & 7) break + } } } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 6: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}meh`, + value: Lol.codec().decode(reader, reader.uint32(), { + limits: opts.limits?.meh + }) + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}hello`, + value: reader.uint32() + } + break + } + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}foo`, + value: reader.string() + } + break + } + case 7: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}payload`, + value: reader.bytes() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Test): Uint8Array => { + export interface TestMehLolLolFieldEvent { + field: 'lol' + value: string + } + + export interface TestMehLolBBarTmpFooBazFieldEvent { + field: 'baz' + value: number + } + + export interface TestHelloFieldEvent { + field: 'hello' + value: number + } + + export interface TestFooFieldEvent { + field: 'foo' + value: string + } + + export interface TestPayloadFieldEvent { + field: 'payload' + value: Uint8Array + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Test.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList): Test => { - return decodeMessage(buf, Test.codec()) + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Test { + return decodeMessage(buf, Test.codec(), opts) + } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Test.codec(), opts) } } diff --git a/packages/protons-benchmark/src/implementations/protons/rpc.ts b/packages/protons-benchmark/src/implementations/protons/rpc.ts deleted file mode 100644 index abaa988..0000000 --- a/packages/protons-benchmark/src/implementations/protons/rpc.ts +++ /dev/null @@ -1,734 +0,0 @@ -import { encodeMessage, decodeMessage, message, writer } from 'protons-runtime' -import type { Codec } from 'protons-runtime' -import type { Uint8ArrayList } from 'uint8arraylist' - -export interface RPC { - subscriptions: RPC.SubOpts[] - messages: RPC.Message[] - control?: RPC.ControlMessage -} - -export namespace RPC { - export interface SubOpts { - subscribe?: boolean - topic?: string - } - - export namespace SubOpts { - let _codec: Codec - - export const codec = (): Codec => { - if (_codec == null) { - _codec = message((obj, w, opts = {}) => { - if (opts.lengthDelimited !== false) { - w.fork() - } - - if (obj.subscribe != null) { - w.uint32(8) - w.bool(obj.subscribe) - } - - if (obj.topic != null) { - w.uint32(18) - w.string(obj.topic) - } - - if (opts.lengthDelimited !== false) { - w.ldelim() - } - }, (reader, length) => { - const obj: any = {} - - const end = length == null ? reader.len : reader.pos + length - - while (reader.pos < end) { - const tag = reader.uint32() - - switch (tag >>> 3) { - case 1: - obj.subscribe = reader.bool() - break - case 2: - obj.topic = reader.string() - break - default: - reader.skipType(tag & 7) - break - } - } - - return obj - }) - } - - return _codec - } - - export const encode = (obj: SubOpts): Uint8Array => { - return encodeMessage(obj, SubOpts.codec()) - } - - export const decode = (buf: Uint8Array | Uint8ArrayList): SubOpts => { - return decodeMessage(buf, SubOpts.codec()) - } - } - - export interface Message { - from?: Uint8Array - data?: Uint8Array - seqno?: Uint8Array - topic: string - signature?: Uint8Array - key?: Uint8Array - } - - export namespace Message { - let _codec: Codec - - export const codec = (): Codec => { - if (_codec == null) { - _codec = message((obj, w, opts = {}) => { - if (opts.lengthDelimited !== false) { - w.fork() - } - - if (obj.from != null) { - w.uint32(10) - w.bytes(obj.from) - } - - if (obj.data != null) { - w.uint32(18) - w.bytes(obj.data) - } - - if (obj.seqno != null) { - w.uint32(26) - w.bytes(obj.seqno) - } - - if (opts.writeDefaults === true || obj.topic !== '') { - w.uint32(34) - w.string(obj.topic ?? '') - } - - if (obj.signature != null) { - w.uint32(42) - w.bytes(obj.signature) - } - - if (obj.key != null) { - w.uint32(50) - w.bytes(obj.key) - } - - if (opts.lengthDelimited !== false) { - w.ldelim() - } - }, (reader, length) => { - const obj: any = { - topic: '' - } - - const end = length == null ? reader.len : reader.pos + length - - while (reader.pos < end) { - const tag = reader.uint32() - - switch (tag >>> 3) { - case 1: - obj.from = reader.bytes() - break - case 2: - obj.data = reader.bytes() - break - case 3: - obj.seqno = reader.bytes() - break - case 4: - obj.topic = reader.string() - break - case 5: - obj.signature = reader.bytes() - break - case 6: - obj.key = reader.bytes() - break - default: - reader.skipType(tag & 7) - break - } - } - - return obj - }) - } - - return _codec - } - - export const encode = (obj: Message): Uint8Array => { - return encodeMessage(obj, Message.codec()) - } - - export const decode = (buf: Uint8Array | Uint8ArrayList): Message => { - return decodeMessage(buf, Message.codec()) - } - } - - export interface ControlMessage { - ihave: RPC.ControlIHave[] - iwant: RPC.ControlIWant[] - graft: RPC.ControlGraft[] - prune: RPC.ControlPrune[] - } - - export namespace ControlMessage { - let _codec: Codec - - export const codec = (): Codec => { - if (_codec == null) { - _codec = message((obj, w, opts = {}) => { - if (opts.lengthDelimited !== false) { - w.fork() - } - - if (obj.ihave != null) { - for (const value of obj.ihave) { - const mw = writer() - RPC.ControlIHave.codec().encode(value, mw, { - lengthDelimited: false, - writeDefaults: true - }) - const buf = mw.finish() - - w.uint32(10) - w.bytes(buf) - } - } - - if (obj.iwant != null) { - for (const value of obj.iwant) { - const mw = writer() - RPC.ControlIWant.codec().encode(value, mw, { - lengthDelimited: false, - writeDefaults: true - }) - const buf = mw.finish() - - w.uint32(18) - w.bytes(buf) - } - } - - if (obj.graft != null) { - for (const value of obj.graft) { - const mw = writer() - RPC.ControlGraft.codec().encode(value, mw, { - lengthDelimited: false, - writeDefaults: true - }) - const buf = mw.finish() - - w.uint32(26) - w.bytes(buf) - } - } - - if (obj.prune != null) { - for (const value of obj.prune) { - const mw = writer() - RPC.ControlPrune.codec().encode(value, mw, { - lengthDelimited: false, - writeDefaults: true - }) - const buf = mw.finish() - - w.uint32(34) - w.bytes(buf) - } - } - - if (opts.lengthDelimited !== false) { - w.ldelim() - } - }, (reader, length) => { - const obj: any = { - ihave: [], - iwant: [], - graft: [], - prune: [] - } - - const end = length == null ? reader.len : reader.pos + length - - while (reader.pos < end) { - const tag = reader.uint32() - - switch (tag >>> 3) { - case 1: - obj.ihave.push(RPC.ControlIHave.codec().decode(reader, reader.uint32())) - break - case 2: - obj.iwant.push(RPC.ControlIWant.codec().decode(reader, reader.uint32())) - break - case 3: - obj.graft.push(RPC.ControlGraft.codec().decode(reader, reader.uint32())) - break - case 4: - obj.prune.push(RPC.ControlPrune.codec().decode(reader, reader.uint32())) - break - default: - reader.skipType(tag & 7) - break - } - } - - return obj - }) - } - - return _codec - } - - export const encode = (obj: ControlMessage): Uint8Array => { - return encodeMessage(obj, ControlMessage.codec()) - } - - export const decode = (buf: Uint8Array | Uint8ArrayList): ControlMessage => { - return decodeMessage(buf, ControlMessage.codec()) - } - } - - export interface ControlIHave { - topicID?: string - messageIDs: Uint8Array[] - } - - export namespace ControlIHave { - let _codec: Codec - - export const codec = (): Codec => { - if (_codec == null) { - _codec = message((obj, w, opts = {}) => { - if (opts.lengthDelimited !== false) { - w.fork() - } - - if (obj.topicID != null) { - w.uint32(10) - w.string(obj.topicID) - } - - if (obj.messageIDs != null) { - for (const value of obj.messageIDs) { - w.uint32(18) - w.bytes(value) - } - } - - if (opts.lengthDelimited !== false) { - w.ldelim() - } - }, (reader, length) => { - const obj: any = { - messageIDs: [] - } - - const end = length == null ? reader.len : reader.pos + length - - while (reader.pos < end) { - const tag = reader.uint32() - - switch (tag >>> 3) { - case 1: - obj.topicID = reader.string() - break - case 2: - obj.messageIDs.push(reader.bytes()) - break - default: - reader.skipType(tag & 7) - break - } - } - - return obj - }) - } - - return _codec - } - - export const encode = (obj: ControlIHave): Uint8Array => { - return encodeMessage(obj, ControlIHave.codec()) - } - - export const decode = (buf: Uint8Array | Uint8ArrayList): ControlIHave => { - return decodeMessage(buf, ControlIHave.codec()) - } - } - - export interface ControlIWant { - messageIDs: Uint8Array[] - } - - export namespace ControlIWant { - let _codec: Codec - - export const codec = (): Codec => { - if (_codec == null) { - _codec = message((obj, w, opts = {}) => { - if (opts.lengthDelimited !== false) { - w.fork() - } - - if (obj.messageIDs != null) { - for (const value of obj.messageIDs) { - w.uint32(10) - w.bytes(value) - } - } - - if (opts.lengthDelimited !== false) { - w.ldelim() - } - }, (reader, length) => { - const obj: any = { - messageIDs: [] - } - - const end = length == null ? reader.len : reader.pos + length - - while (reader.pos < end) { - const tag = reader.uint32() - - switch (tag >>> 3) { - case 1: - obj.messageIDs.push(reader.bytes()) - break - default: - reader.skipType(tag & 7) - break - } - } - - return obj - }) - } - - return _codec - } - - export const encode = (obj: ControlIWant): Uint8Array => { - return encodeMessage(obj, ControlIWant.codec()) - } - - export const decode = (buf: Uint8Array | Uint8ArrayList): ControlIWant => { - return decodeMessage(buf, ControlIWant.codec()) - } - } - - export interface ControlGraft { - topicID?: string - } - - export namespace ControlGraft { - let _codec: Codec - - export const codec = (): Codec => { - if (_codec == null) { - _codec = message((obj, w, opts = {}) => { - if (opts.lengthDelimited !== false) { - w.fork() - } - - if (obj.topicID != null) { - w.uint32(10) - w.string(obj.topicID) - } - - if (opts.lengthDelimited !== false) { - w.ldelim() - } - }, (reader, length) => { - const obj: any = {} - - const end = length == null ? reader.len : reader.pos + length - - while (reader.pos < end) { - const tag = reader.uint32() - - switch (tag >>> 3) { - case 1: - obj.topicID = reader.string() - break - default: - reader.skipType(tag & 7) - break - } - } - - return obj - }) - } - - return _codec - } - - export const encode = (obj: ControlGraft): Uint8Array => { - return encodeMessage(obj, ControlGraft.codec()) - } - - export const decode = (buf: Uint8Array | Uint8ArrayList): ControlGraft => { - return decodeMessage(buf, ControlGraft.codec()) - } - } - - export interface ControlPrune { - topicID?: string - peers: RPC.PeerInfo[] - backoff?: bigint - } - - export namespace ControlPrune { - let _codec: Codec - - export const codec = (): Codec => { - if (_codec == null) { - _codec = message((obj, w, opts = {}) => { - if (opts.lengthDelimited !== false) { - w.fork() - } - - if (obj.topicID != null) { - w.uint32(10) - w.string(obj.topicID) - } - - if (obj.peers != null) { - for (const value of obj.peers) { - const mw = writer() - RPC.PeerInfo.codec().encode(value, mw, { - lengthDelimited: false, - writeDefaults: true - }) - const buf = mw.finish() - - w.uint32(18) - w.bytes(buf) - } - } - - if (obj.backoff != null) { - w.uint32(24) - w.uint64(obj.backoff) - } - - if (opts.lengthDelimited !== false) { - w.ldelim() - } - }, (reader, length) => { - const obj: any = { - peers: [] - } - - const end = length == null ? reader.len : reader.pos + length - - while (reader.pos < end) { - const tag = reader.uint32() - - switch (tag >>> 3) { - case 1: - obj.topicID = reader.string() - break - case 2: - obj.peers.push(RPC.PeerInfo.codec().decode(reader, reader.uint32())) - break - case 3: - obj.backoff = reader.uint64() - break - default: - reader.skipType(tag & 7) - break - } - } - - return obj - }) - } - - return _codec - } - - export const encode = (obj: ControlPrune): Uint8Array => { - return encodeMessage(obj, ControlPrune.codec()) - } - - export const decode = (buf: Uint8Array | Uint8ArrayList): ControlPrune => { - return decodeMessage(buf, ControlPrune.codec()) - } - } - - export interface PeerInfo { - peerID?: Uint8Array - signedPeerRecord?: Uint8Array - } - - export namespace PeerInfo { - let _codec: Codec - - export const codec = (): Codec => { - if (_codec == null) { - _codec = message((obj, w, opts = {}) => { - if (opts.lengthDelimited !== false) { - w.fork() - } - - if (obj.peerID != null) { - w.uint32(10) - w.bytes(obj.peerID) - } - - if (obj.signedPeerRecord != null) { - w.uint32(18) - w.bytes(obj.signedPeerRecord) - } - - if (opts.lengthDelimited !== false) { - w.ldelim() - } - }, (reader, length) => { - const obj: any = {} - - const end = length == null ? reader.len : reader.pos + length - - while (reader.pos < end) { - const tag = reader.uint32() - - switch (tag >>> 3) { - case 1: - obj.peerID = reader.bytes() - break - case 2: - obj.signedPeerRecord = reader.bytes() - break - default: - reader.skipType(tag & 7) - break - } - } - - return obj - }) - } - - return _codec - } - - export const encode = (obj: PeerInfo): Uint8Array => { - return encodeMessage(obj, PeerInfo.codec()) - } - - export const decode = (buf: Uint8Array | Uint8ArrayList): PeerInfo => { - return decodeMessage(buf, PeerInfo.codec()) - } - } - - let _codec: Codec - - export const codec = (): Codec => { - if (_codec == null) { - _codec = message((obj, w, opts = {}) => { - if (opts.lengthDelimited !== false) { - w.fork() - } - - if (obj.subscriptions != null) { - for (const value of obj.subscriptions) { - const mw = writer() - RPC.SubOpts.codec().encode(value, mw, { - lengthDelimited: false, - writeDefaults: true - }) - const buf = mw.finish() - - w.uint32(10) - w.bytes(buf) - } - } - - if (obj.messages != null) { - for (const value of obj.messages) { - const mw = writer() - RPC.Message.codec().encode(value, mw, { - lengthDelimited: false, - writeDefaults: true - }) - const buf = mw.finish() - - w.uint32(18) - w.bytes(buf) - } - } - - if (obj.control != null) { - const mw = writer() - RPC.ControlMessage.codec().encode(obj.control, mw, { - lengthDelimited: false, - writeDefaults: false - }) - const buf = mw.finish() - - if (buf.byteLength > 0) { - w.uint32(26) - w.bytes(buf) - } - } - - if (opts.lengthDelimited !== false) { - w.ldelim() - } - }, (reader, length) => { - const obj: any = { - subscriptions: [], - messages: [] - } - - const end = length == null ? reader.len : reader.pos + length - - while (reader.pos < end) { - const tag = reader.uint32() - - switch (tag >>> 3) { - case 1: - obj.subscriptions.push(RPC.SubOpts.codec().decode(reader, reader.uint32())) - break - case 2: - obj.messages.push(RPC.Message.codec().decode(reader, reader.uint32())) - break - case 3: - obj.control = RPC.ControlMessage.codec().decode(reader, reader.uint32()) - break - default: - reader.skipType(tag & 7) - break - } - } - - return obj - }) - } - - return _codec - } - - export const encode = (obj: RPC): Uint8Array => { - return encodeMessage(obj, RPC.codec()) - } - - export const decode = (buf: Uint8Array | Uint8ArrayList): RPC => { - return decodeMessage(buf, RPC.codec()) - } -} diff --git a/packages/protons-runtime/src/codec.ts b/packages/protons-runtime/src/codec.ts index bf02047..5fbfdd5 100644 --- a/packages/protons-runtime/src/codec.ts +++ b/packages/protons-runtime/src/codec.ts @@ -1,13 +1,13 @@ import type { Writer, Reader } from './index.ts' // https://developers.google.com/protocol-buffers/docs/encoding#structure -export enum CODEC_TYPES { - VARINT = 0, - BIT64, - LENGTH_DELIMITED, - START_GROUP, - END_GROUP, - BIT32 +export const CODEC_TYPES = { + VARINT: 0, + BIT64: 1, + LENGTH_DELIMITED: 2, + START_GROUP: 3, + END_GROUP: 4, + BIT32: 5 } export interface EncodeOptions { @@ -59,18 +59,24 @@ export interface DecodeFunction { (reader: Reader, length?: number, opts?: DecodeOptions): T } +export interface StreamFunction { + (reader: Reader, length?: number, prefix?: string, opts?: DecodeOptions): Generator +} + export interface Codec { name: string - type: CODEC_TYPES + type: number encode: EncodeFunction decode: DecodeFunction + stream: StreamFunction } -export function createCodec (name: string, type: CODEC_TYPES, encode: EncodeFunction, decode: DecodeFunction): Codec { +export function createCodec (name: string, type: number, encode: EncodeFunction, decode: DecodeFunction, stream: StreamFunction): Codec { return { name, type, encode, - decode + decode, + stream } } diff --git a/packages/protons-runtime/src/codecs/enum.ts b/packages/protons-runtime/src/codecs/enum.ts index fb83643..525091a 100644 --- a/packages/protons-runtime/src/codecs/enum.ts +++ b/packages/protons-runtime/src/codecs/enum.ts @@ -1,8 +1,8 @@ import { createCodec, CODEC_TYPES } from '../codec.ts' -import type { DecodeFunction, EncodeFunction, Codec } from '../codec.ts' +import type { DecodeFunction, EncodeFunction, Codec, StreamFunction } from '../codec.ts' export function enumeration (v: any): Codec { - function findValue (val: string | number): number { + function findValue (val: any): number { // Use the reverse mapping to look up the enum key for the stored value // https://www.typescriptlang.org/docs/handbook/enums.html#reverse-mappings if (v[val.toString()] == null) { @@ -12,18 +12,23 @@ export function enumeration (v: any): Codec { return v[val] } - const encode: EncodeFunction = function enumEncode (val, writer) { + const encode: EncodeFunction = function enumEncode (val, writer) { const enumValue = findValue(val) writer.int32(enumValue) } - const decode: DecodeFunction = function enumDecode (reader) { + const decode: DecodeFunction = function enumDecode (reader) { const val = reader.int32() return findValue(val) } - // @ts-expect-error yeah yeah - return createCodec('enum', CODEC_TYPES.VARINT, encode, decode) + const stream: StreamFunction = function * enumStream (reader) { + const val = reader.int32() + + yield findValue(val) + } + + return createCodec('enum', CODEC_TYPES.VARINT, encode, decode, stream) } diff --git a/packages/protons-runtime/src/codecs/message.ts b/packages/protons-runtime/src/codecs/message.ts index 0c7c2d5..41018c7 100644 --- a/packages/protons-runtime/src/codecs/message.ts +++ b/packages/protons-runtime/src/codecs/message.ts @@ -1,10 +1,10 @@ import { createCodec, CODEC_TYPES } from '../codec.ts' -import type { EncodeFunction, DecodeFunction, Codec } from '../codec.ts' +import type { EncodeFunction, DecodeFunction, Codec, StreamFunction } from '../codec.ts' export interface Factory { new (obj: A): T } -export function message (encode: EncodeFunction, decode: DecodeFunction): Codec { - return createCodec('message', CODEC_TYPES.LENGTH_DELIMITED, encode, decode) +export function message (encode: EncodeFunction, decode: DecodeFunction, stream: StreamFunction): Codec { + return createCodec('message', CODEC_TYPES.LENGTH_DELIMITED, encode, decode, stream) } diff --git a/packages/protons-runtime/src/index.ts b/packages/protons-runtime/src/index.ts index 29d4279..58a06e2 100644 --- a/packages/protons-runtime/src/index.ts +++ b/packages/protons-runtime/src/index.ts @@ -28,6 +28,10 @@ export { encodeMessage } from './encode.ts' +export { + streamMessage +} from './stream.ts' + export { enumeration } from './codecs/enum.ts' export { message } from './codecs/message.ts' export { createReader as reader } from './utils/reader.ts' diff --git a/packages/protons-runtime/src/stream.ts b/packages/protons-runtime/src/stream.ts new file mode 100644 index 0000000..ed31acc --- /dev/null +++ b/packages/protons-runtime/src/stream.ts @@ -0,0 +1,9 @@ +import { createReader } from './utils/reader.ts' +import type { Codec } from './codec.ts' +import type { Uint8ArrayList } from 'uint8arraylist' + +export function * streamMessage (buf: Uint8Array | Uint8ArrayList, codec: Pick, 'stream'>, opts?: any): Generator { + const reader = createReader(buf) + + yield * codec.stream(reader, undefined, opts) +} diff --git a/packages/protons/package.json b/packages/protons/package.json index 8bc3120..9acb465 100644 --- a/packages/protons/package.json +++ b/packages/protons/package.json @@ -56,6 +56,7 @@ }, "devDependencies": { "aegir": "^47.0.5", + "it-all": "^3.0.9", "long": "^5.2.0", "pbjs": "^0.0.14", "protobufjs": "^7.0.0", diff --git a/packages/protons/src/fields/array-field.ts b/packages/protons/src/fields/array-field.ts new file mode 100644 index 0000000..86ee0a3 --- /dev/null +++ b/packages/protons/src/fields/array-field.ts @@ -0,0 +1,109 @@ +import { Enum } from '../types/enum.ts' +import { Message } from '../types/message.ts' +import { codecTypes, Field } from './field.ts' +import type { FieldDef } from './field.ts' +import type { Parent, Type } from '../types/index.ts' + +export interface ArrayFieldDef extends FieldDef { + rule: 'repeated' +} + +export function isArrayFieldDef (obj?: any): obj is ArrayFieldDef { + return obj?.rule === 'repeated' +} + +export class ArrayField extends Field { + private lengthLimit?: number + + constructor (name: string, def: ArrayFieldDef, parent: Parent) { + super(name, def, parent) + + this.lengthLimit = def.options?.['(protons.options).limit'] + } + + getInterfaceField (parent: Parent, indent = ''): string { + return `${super.getInterfaceField(parent, indent)}[]` + } + + getDefaultField (parent: Parent): string { + return `${this.name}: []` + } + + getEncoder (parent: Parent): string { + const type = parent.findType(this.type) + let id = (this.id << 3) | codecTypes[this.type] + + if (type instanceof Message) { + id = (this.id << 3) | codecTypes.message + } + + if (type instanceof Enum) { + id = (this.id << 3) | codecTypes.enum + } + + return ` + if (obj.${this.name} != null) { + for (const value of obj.${this.name}) { + w.uint32(${id}) + ${type.getEncoder(this, 'value')} + } + }` + } + + getDecoder (parent: Parent): string { + parent.addImport('protons-runtime', 'MaxLengthError') + + let limit = ` + if (opts.limits?.${this.name} != null && obj.${this.name}.length === opts.limits.${this.name}) { + throw new MaxLengthError('Decode error - repeated field "${this.name}" had too many elements') + } +` + + if (this.lengthLimit != null) { + limit += ` + if (obj.${this.name}.length === ${this.lengthLimit}) { + throw new MaxLengthError('Decode error - repeated field "${this.name}" had too many elements') + } +` + } + + const type: Type = parent.findType(this.type) + + return `case ${this.id}: {${limit} + obj.${this.name}.push(${type.getDecoder(this)}) + break + }` + } + + getStreamingDecoder (parent: Parent): string { + parent.addImport('protons-runtime', 'MaxLengthError') + + let limit = ` + if (opts.limits?.${this.name} != null && obj.${this.name} === opts.limits.${this.name}) { + throw new MaxLengthError('Streaming decode error - repeated field "${this.name}" had too many elements') + } +` + + if (this.lengthLimit != null) { + limit += ` + if (obj.${this.name} === ${this.lengthLimit}) { + throw new MaxLengthError('Streaming decode error - repeated field "${this.name}" had too many elements') + } +` + } + + const type: Type = parent.findType(this.type) + + return `case ${this.id}: {${limit} + ${type.getStreamingDecoder(this, `\`\${prefix != null ? \`\${prefix}.\` : ''}${this.name}\``, ' ')} + + obj.${this.name}++ + + break + }` + } + + getLimitField (): string { + return `${this.name}: ${this.lengthLimit ?? 0}` + } +} diff --git a/packages/protons/src/fields/enum-field.ts b/packages/protons/src/fields/enum-field.ts new file mode 100644 index 0000000..65a1701 --- /dev/null +++ b/packages/protons/src/fields/enum-field.ts @@ -0,0 +1,53 @@ +import { Enum } from '../types/enum.ts' +import { Field } from './field.ts' +import type { FieldDef } from './field.ts' +import type { Parent } from '../types/index.ts' + +export class EnumField extends Field { + private enum: Enum + + constructor (name: string, def: FieldDef, parent: Parent) { + super(name, def, parent) + + const type = parent.findType(def.type) + + if (!(type instanceof Enum)) { + throw new Error(`Type "${def.type}" was not an Enum`) + } + + this.enum = type + } + + getDefaultField (parent: Parent): string { + if (this.optional) { + return '' + } + + const type = parent.findType(this.type) + + return `${this.name}: ${type.pbType}.${this.enum.lowestValueName}` + } +/* + getValueTest (): string { + console.info(this.name, 'optional', this.optional, 'proto2required', this.proto2Required) + + if (this.proto2Required) { + return 'true' + } + + const valueTest = `obj.${this.name} != null` + + // singular enums default to 0, but enums can be defined without a 0 + // value which is against the proto3 spec but is tolerated + if (this.optional || this.proto2Required) { + return valueTest + } + + if (this.enum.lowestValue === 0) { + return `${valueTest} && __${this.type}Values[obj.${this.name}] !== 0` + } + + return valueTest + } + */ +} diff --git a/packages/protons/src/fields/field.ts b/packages/protons/src/fields/field.ts new file mode 100644 index 0000000..5e370ac --- /dev/null +++ b/packages/protons/src/fields/field.ts @@ -0,0 +1,201 @@ +import { ParseError } from 'protons-runtime' +import { Enum } from '../types/enum.ts' +import { Message } from '../types/message.ts' +import type { Parent, Type } from '../types/index.ts' + +export const CODEC_TYPES = { + VARINT: 0, + BIT64: 1, + LENGTH_DELIMITED: 2, + START_GROUP: 3, + END_GROUP: 4, + BIT32: 5 +} + +export const codecTypes: Record = { + bool: CODEC_TYPES.VARINT, + bytes: CODEC_TYPES.LENGTH_DELIMITED, + double: CODEC_TYPES.BIT64, + enum: CODEC_TYPES.VARINT, + fixed32: CODEC_TYPES.BIT32, + fixed64: CODEC_TYPES.BIT64, + float: CODEC_TYPES.BIT32, + int32: CODEC_TYPES.VARINT, + int64: CODEC_TYPES.VARINT, + message: CODEC_TYPES.LENGTH_DELIMITED, + sfixed32: CODEC_TYPES.BIT32, + sfixed64: CODEC_TYPES.BIT64, + sint32: CODEC_TYPES.VARINT, + sint64: CODEC_TYPES.VARINT, + string: CODEC_TYPES.LENGTH_DELIMITED, + uint32: CODEC_TYPES.VARINT, + uint64: CODEC_TYPES.VARINT +} + +const jsTypeOverrides: Record = { + JS_NUMBER: 'number', + JS_STRING: 'string' +} + +interface DefaultValueGenerator { + (): string +} + +const defaultValueGenerators: Record = { + bool: () => 'false', + bytes: () => 'uint8ArrayAlloc(0)', + double: () => '0', + fixed32: () => '0', + fixed64: () => '0n', + float: () => '0', + int32: () => '0', + int64: () => '0n', + sfixed32: () => '0', + sfixed64: () => '0n', + sint32: () => '0', + sint64: () => '0n', + string: () => "''", + uint32: () => '0', + uint64: () => '0n' +} + +const defaultValueGeneratorsJsTypeOverrides: Record = { + number: () => '0', + string: () => "''" +} + +export interface FieldOptions extends Record { + proto3_optional?: boolean + jstype?: 'string' | 'number' +} + +export interface FieldDef { + id: number + type: string + repeated?: boolean + options?: FieldOptions + rule?: string + oneof?: string[] +} + +export interface MessageField { + /** + * Return a string that can be used in a typescript interface for this field + */ + getInterfaceField (parent: Parent, indent?: string): string +} + +export class Field implements MessageField { + public id: number + public name: string + public optional: boolean + public type: string + public proto2Required: boolean + public jsTypeOverride?: 'string' | 'number' + public oneof?: string[] + + constructor (name: string, def: FieldDef, parent: Parent) { + this.id = def.id + this.name = name + + // the default type for a message is unset so they are always optional + // https://developers.google.com/protocol-buffers/docs/proto3#default + this.optional = def.repeated !== true && def.options?.proto3_optional === true + this.type = def.type ?? 'string' + this.oneof = def.oneof + this.proto2Required = false + + if (def.options?.jstype != null) { + this.jsTypeOverride = jsTypeOverrides[def.options.jstype] + } + + if (this.jsTypeOverride != null && !['int64', 'uint64', 'sint64', 'fixed64', 'sfixed64'].includes(this.type)) { + throw new Error(`jstype override option is only allowed on int64, uint64, sint64, fixed64 or sfixed64 fields - got "${this.type}"`) + } + + if (def.rule === 'required') { + const message = `field "${name}" is required, this is not allowed in proto3. Please convert your proto2 definitions to proto3 - see https://github.com/ipfs/protons/wiki/Required-fields-and-protobuf-3` + + if (parent.flags?.strict === true) { + throw new ParseError(message) + } else { + this.proto2Required = true + + // eslint-disable-next-line no-console + console.info(`[WARN] ${message}`) + } + } + } + + getInterfaceField (parent: Parent, indent = ''): string { + return `${indent}${this.name}${this.optional ? '?' : ''}: ${this.jsTypeOverride ?? parent.findType(this.type).jsType}` + } + + getDefaultField (parent: Parent): string { + if (this.optional) { + return '' + } + + const type = parent.findType(this.type) + + if (type.pbType === 'bytes') { + parent.addImport('uint8arrays/alloc', 'alloc', 'uint8ArrayAlloc') + } + + let defaultValueGenerator = defaultValueGenerators[type.pbType] + + if (this.jsTypeOverride) { + defaultValueGenerator = defaultValueGeneratorsJsTypeOverrides[this.jsTypeOverride] + } + + if (defaultValueGenerator == null) { + return '' + } + + return `${this.name}: ${defaultValueGenerator()}` + } + + getDecoder (parent: Parent): string { + const type: Type = parent.findType(this.type) + + return `case ${this.id}: { + obj.${this.name} = ${type.getDecoder(this)} + break + }` + } + + getStreamingDecoder (parent: Parent): string { + const type: Type = parent.findType(this.type) + + return `case ${this.id}: { + yield { + field: \`\${prefix != null ? \`\${prefix}.\` : ''}${this.name}\`, + value: ${type.getDecoder(this, ' ')} + } + break + }` + } + + getEncoder (parent: Parent): string { + const type = parent.findType(this.type) + let id = (this.id << 3) | codecTypes[this.type] + + if (type instanceof Message) { + id = (this.id << 3) | codecTypes.message + } + + if (type instanceof Enum) { + id = (this.id << 3) | codecTypes.enum + } + + return ` + if (${type.getValueTest(this, `obj.${this.name}`)}) { + w.uint32(${id}) + ${type.getEncoder(this, `obj.${this.name}`)} + }` + } + + getLimitField (): string { + return '' + } +} diff --git a/packages/protons/src/fields/map-field.ts b/packages/protons/src/fields/map-field.ts new file mode 100644 index 0000000..df3243e --- /dev/null +++ b/packages/protons/src/fields/map-field.ts @@ -0,0 +1,107 @@ +import { codecTypes, Field } from './field.ts' +import type { FieldDef } from './field.ts' +import type { Parent } from '../types/index.ts' + +export interface MapFieldDef extends FieldDef { + keyType?: string + valueType: string +} + +export function isMapFieldDef (obj?: any): obj is MapFieldDef { + return obj?.keyType != null +} + +export class MapField extends Field { + public keyType: string + public valueType: string + public entryType: string + private lengthLimit?: number + + constructor (name: string, def: MapFieldDef, parent: Parent) { + super(name, def, parent) + + this.type = 'message' + this.keyType = def.keyType ?? 'string' + this.valueType = def.valueType + this.entryType = def.type + this.lengthLimit = def.options?.['(protons.options).limit'] + } + + getInterfaceField (parent: Parent): string { + return `${this.name}: Map<${parent.findType(this.keyType).jsType}, ${parent.findType(this.valueType).jsType}>` + } + + getDefaultField (parent: Parent): string { + return `${this.name}: new Map<${parent.findType(this.keyType).jsType}, ${parent.findType(this.valueType).jsType}>()` + } + + getEncoder (parent: Parent): string { + const id = (this.id << 3) | codecTypes.message + const entryType = parent.findType(this.entryType) + + return ` + if (${entryType.getValueTest(this, 'value')}) { + for (const [key, value] of obj.${this.name}.entries()) { + w.uint32(${id}) + ${entryType.getEncoder(this, '{ key, value }')} + } + }` + } + + getDecoder (parent: Parent): string { + parent.addImport('protons-runtime', 'MaxSizeError') + const entryType = parent.findType(this.entryType) + + let limit = ` + if (opts.limits?.${this.name} != null && obj.${this.name}.size === opts.limits.${this.name}) { + throw new MaxSizeError('Decode error - map field "${this.name}" had too many elements') + } +` + + if (this.lengthLimit != null) { + limit += ` + if (obj.${this.name}.size === ${this.lengthLimit}) { + throw new MaxSizeError('Decode error - map field "${this.name}" had too many elements') + } +` + } + + return `case ${this.id}: {${limit} + const entry = ${entryType.getDecoder(this)} + obj.${this.name}.set(entry.key, entry.value) + break + }` + } + + getStreamingDecoder (parent: Parent): string { + parent.addImport('protons-runtime', 'MaxLengthError') + + let limit = ` + if (opts.limits?.${this.name} != null && obj.${this.name} === opts.limits.${this.name}) { + throw new MaxLengthError('Decode error - map field "${this.name}" had too many elements') + } +` + + if (this.lengthLimit != null) { + limit += ` + if (obj.${this.name} === ${this.lengthLimit}) { + throw new MaxLengthError('Decode error - repeated field "${this.name}" had too many elements') + } +` + } + + const type = parent.findType(this.entryType) + + return `case ${this.id}: {${limit} + ${type.getStreamingDecoder(this, `\`\${prefix != null ? \`\${prefix}.\` : ''}${this.name}\``, ' ')} + + obj.${this.name}++ + + break + }` + } + + getLimitField (): string { + return `${this.name}: ${this.lengthLimit ?? 0}` + } +} diff --git a/packages/protons/src/fields/message-field.ts b/packages/protons/src/fields/message-field.ts new file mode 100644 index 0000000..e77b385 --- /dev/null +++ b/packages/protons/src/fields/message-field.ts @@ -0,0 +1,29 @@ +import { Message } from '../types/message.ts' +import { Field } from './field.ts' +import type { Parent, Type } from '../types/index.ts' + +export class MessageField extends Field { + getInterfaceField (parent: Parent, indent = ''): string { + return `${indent}${this.name}?: ${parent.findType(this.type).jsType}` + } + + getMessage (parent: Parent): Message { + const type = parent.findType(this.type) + + if (!(type instanceof Message)) { + throw new Error(`Field ${this.name} was not a message field`) + } + + return type + } + + getStreamingDecoder (parent: Parent): string { + const type: Type = parent.findType(this.type) + + return `case ${this.id}: { + ${type.getStreamingDecoder(this, `\`\${prefix != null ? \`\${prefix}.\` : ''}${this.name}\``, ' ')} + + break + }` + } +} diff --git a/packages/protons/src/index.ts b/packages/protons/src/index.ts index 570715d..4e12751 100644 --- a/packages/protons/src/index.ts +++ b/packages/protons/src/index.ts @@ -1,5 +1,3 @@ -/* eslint-disable max-depth */ - /** * @packageDocumentation * @@ -197,1020 +195,14 @@ import fs from 'fs/promises' import path from 'path' import { promisify } from 'util' import { main as pbjs } from 'protobufjs-cli/pbjs.js' -import { NoMessagesFoundError, ParseError } from 'protons-runtime' - -export enum CODEC_TYPES { - VARINT = 0, - BIT64, - LENGTH_DELIMITED, - START_GROUP, - END_GROUP, - BIT32 -} +import { Module } from './types/module.ts' function pathWithExtension (input: string, extension: string, outputDir?: string): string { const output = outputDir ?? path.dirname(input) return path.join(output, path.basename(input).split('.').slice(0, -1).join('.') + extension) } -/** - * This will be removed in a future release - * - * @deprecated - */ -export class CodeError extends Error { - public code: string - - constructor (message: string, code: string, options?: ErrorOptions) { - super(message, options) - - this.code = code - } -} - -const types: Record = { - bool: 'boolean', - bytes: 'Uint8Array', - double: 'number', - fixed32: 'number', - fixed64: 'bigint', - float: 'number', - int32: 'number', - int64: 'bigint', - sfixed32: 'number', - sfixed64: 'bigint', - sint32: 'number', - sint64: 'bigint', - string: 'string', - uint32: 'number', - uint64: 'bigint' -} - -const jsTypeOverrides: Record = { - JS_NUMBER: 'number', - JS_STRING: 'string' -} - -const encoderGenerators: Record string> = { - bool: (val) => `w.bool(${val})`, - bytes: (val) => `w.bytes(${val})`, - double: (val) => `w.double(${val})`, - fixed32: (val) => `w.fixed32(${val})`, - fixed64: (val, jsTypeOverride) => { - if (jsTypeOverride === 'number') { - return `w.fixed64Number(${val})` - } - - if (jsTypeOverride === 'string') { - return `w.fixed64String(${val})` - } - - return `w.fixed64(${val})` - }, - float: (val) => `w.float(${val})`, - int32: (val) => `w.int32(${val})`, - int64: (val, jsTypeOverride) => { - if (jsTypeOverride === 'number') { - return `w.int64Number(${val})` - } - - if (jsTypeOverride === 'string') { - return `w.int64String(${val})` - } - - return `w.int64(${val})` - }, - sfixed32: (val) => `w.sfixed32(${val})`, - sfixed64: (val, jsTypeOverride) => { - if (jsTypeOverride === 'number') { - return `w.sfixed64Number(${val})` - } - - if (jsTypeOverride === 'string') { - return `w.sfixed64String(${val})` - } - - return `w.sfixed64(${val})` - }, - sint32: (val) => `w.sint32(${val})`, - sint64: (val, jsTypeOverride) => { - if (jsTypeOverride === 'number') { - return `w.sint64Number(${val})` - } - - if (jsTypeOverride === 'string') { - return `w.sint64String(${val})` - } - - return `w.sint64(${val})` - }, - string: (val) => `w.string(${val})`, - uint32: (val) => `w.uint32(${val})`, - uint64: (val, jsTypeOverride) => { - if (jsTypeOverride === 'number') { - return `w.uint64Number(${val})` - } - - if (jsTypeOverride === 'string') { - return `w.uint64String(${val})` - } - - return `w.uint64(${val})` - } -} - -const decoderGenerators: Record string> = { - bool: () => 'reader.bool()', - bytes: () => 'reader.bytes()', - double: () => 'reader.double()', - fixed32: () => 'reader.fixed32()', - fixed64: (jsTypeOverride) => { - if (jsTypeOverride === 'number') { - return 'reader.fixed64Number()' - } - - if (jsTypeOverride === 'string') { - return 'reader.fixed64String()' - } - - return 'reader.fixed64()' - }, - float: () => 'reader.float()', - int32: () => 'reader.int32()', - int64: (jsTypeOverride) => { - if (jsTypeOverride === 'number') { - return 'reader.int64Number()' - } - - if (jsTypeOverride === 'string') { - return 'reader.int64String()' - } - - return 'reader.int64()' - }, - sfixed32: () => 'reader.sfixed32()', - sfixed64: (jsTypeOverride) => { - if (jsTypeOverride === 'number') { - return 'reader.sfixed64Number()' - } - - if (jsTypeOverride === 'string') { - return 'reader.sfixed64String()' - } - - return 'reader.sfixed64()' - }, - sint32: () => 'reader.sint32()', - sint64: (jsTypeOverride) => { - if (jsTypeOverride === 'number') { - return 'reader.sint64Number()' - } - - if (jsTypeOverride === 'string') { - return 'reader.sint64String()' - } - - return 'reader.sint64()' - }, - string: () => 'reader.string()', - uint32: () => 'reader.uint32()', - uint64: (jsTypeOverride) => { - if (jsTypeOverride === 'number') { - return 'reader.uint64Number()' - } - - if (jsTypeOverride === 'string') { - return 'reader.uint64String()' - } - - return 'reader.uint64()' - } -} - -const defaultValueGenerators: Record string> = { - bool: () => 'false', - bytes: () => 'uint8ArrayAlloc(0)', - double: () => '0', - fixed32: () => '0', - fixed64: () => '0n', - float: () => '0', - int32: () => '0', - int64: () => '0n', - sfixed32: () => '0', - sfixed64: () => '0n', - sint32: () => '0', - sint64: () => '0n', - string: () => "''", - uint32: () => '0', - uint64: () => '0n' -} - -const defaultValueGeneratorsJsTypeOverrides: Record string> = { - number: () => '0', - string: () => "''" -} - -const defaultValueTestGenerators: Record string> = { - bool: (field) => `(${field} != null && ${field} !== false)`, - bytes: (field) => `(${field} != null && ${field}.byteLength > 0)`, - double: (field) => `(${field} != null && ${field} !== 0)`, - fixed32: (field) => `(${field} != null && ${field} !== 0)`, - fixed64: (field) => `(${field} != null && ${field} !== 0n)`, - float: (field) => `(${field} != null && ${field} !== 0)`, - int32: (field) => `(${field} != null && ${field} !== 0)`, - int64: (field) => `(${field} != null && ${field} !== 0n)`, - sfixed32: (field) => `(${field} != null && ${field} !== 0)`, - sfixed64: (field) => `(${field} != null && ${field} !== 0n)`, - sint32: (field) => `(${field} != null && ${field} !== 0)`, - sint64: (field) => `(${field} != null && ${field} !== 0n)`, - string: (field) => `(${field} != null && ${field} !== '')`, - uint32: (field) => `(${field} != null && ${field} !== 0)`, - uint64: (field) => `(${field} != null && ${field} !== 0n)` -} - -const defaultValueTestGeneratorsJsTypeOverrides: Record string> = { - number: (field) => `(${field} != null && ${field} !== 0)`, - string: (field) => `(${field} != null && ${field} !== '')` -} - -function findJsTypeOverride (defaultType: string, fieldDef: FieldDef): 'number' | 'string' | undefined { - if (fieldDef.options?.jstype != null && jsTypeOverrides[fieldDef.options?.jstype] != null) { - if (!['int64', 'uint64', 'sint64', 'fixed64', 'sfixed64'].includes(defaultType)) { - throw new Error(`jstype is only allowed on int64, uint64, sint64, fixed64 or sfixed64 fields - got "${defaultType}"`) - } - - return jsTypeOverrides[fieldDef.options?.jstype] - } -} - -function findJsTypeName (typeName: string, classDef: MessageDef, moduleDef: ModuleDef, fieldDef: FieldDef): string { - const override = findJsTypeOverride(typeName, fieldDef) - - if (override != null) { - return override - } - - if (types[typeName] != null) { - return types[typeName] - } - - if (isEnumDef(classDef)) { - throw new Error('Could not find type in enum') - } - - if (classDef.nested?.[typeName] != null) { - return `${classDef.fullName}.${typeName}` - } - - if (classDef.parent != null) { - return findJsTypeName(typeName, classDef.parent, moduleDef, fieldDef) - } - - if (moduleDef.globals[typeName] != null) { - return typeName - } - - throw new Error(`Could not resolve type name "${typeName}"`) -} - -function findDef (typeName: string, classDef: MessageDef, moduleDef: ModuleDef): MessageDef { - if (isEnumDef(classDef)) { - throw new Error('Could not find type in enum') - } - - if (classDef.nested?.[typeName] != null) { - return classDef.nested?.[typeName] - } - - if (classDef.parent != null) { - return findDef(typeName, classDef.parent, moduleDef) - } - - if (moduleDef.globals[typeName] != null) { - return moduleDef.globals[typeName] - } - - throw new Error(`Could not resolve type name "${typeName}"`) -} - -function createDefaultObject (fields: Record, messageDef: MessageDef, moduleDef: ModuleDef): string { - const output = Object.entries(fields) - .map(([name, fieldDef]) => { - if (fieldDef.map) { - return `${name}: new Map<${types[fieldDef.keyType ?? 'string']}, ${types[fieldDef.valueType]}>()` - } - - if (fieldDef.repeated) { - return `${name}: []` - } - - if (fieldDef.optional) { - return '' - } - - const type: string = fieldDef.type - let defaultValue - let defaultValueGenerator = defaultValueGenerators[type] - - if (defaultValueGenerator != null) { - const jsTypeOverride = findJsTypeOverride(type, fieldDef) - - if (jsTypeOverride != null && defaultValueGeneratorsJsTypeOverrides[jsTypeOverride] != null) { - defaultValueGenerator = defaultValueGeneratorsJsTypeOverrides[jsTypeOverride] - } - - if (type === 'bytes') { - moduleDef.addImport('uint8arrays/alloc', 'alloc', 'uint8ArrayAlloc') - } - - defaultValue = defaultValueGenerator() - } else { - const def = findDef(fieldDef.type, messageDef, moduleDef) - - if (isEnumDef(def)) { - // select lowest-value enum - should be 0 but it's not guaranteed - const val = Object.entries(def.values) - .sort((a, b) => { - if (a[1] < b[1]) { - return 1 - } - - if (a[1] > b[1]) { - return -1 - } - - return 0 - }) - .pop() - - if (val == null) { - throw new Error(`Could not find default enum value for ${def.fullName}`) - } - - defaultValue = `${def.name}.${val[0]}` - } else { - defaultValue = 'undefined' - } - } - - return `${name}: ${defaultValue}` - }) - .filter(Boolean) - .join(',\n ') - - if (output !== '') { - return ` - ${output} - ` - } - - return '' -} - -const encoders: Record = { - bool: 'bool', - bytes: 'bytes', - double: 'double', - fixed32: 'fixed32', - fixed64: 'fixed64', - float: 'float', - int32: 'int32', - int64: 'int64', - sfixed32: 'sfixed32', - sfixed64: 'sfixed64', - sint32: 'sint32', - sint64: 'sint64', - string: 'string', - uint32: 'uint32', - uint64: 'uint64' -} - -const codecTypes: Record = { - bool: CODEC_TYPES.VARINT, - bytes: CODEC_TYPES.LENGTH_DELIMITED, - double: CODEC_TYPES.BIT64, - enum: CODEC_TYPES.VARINT, - fixed32: CODEC_TYPES.BIT32, - fixed64: CODEC_TYPES.BIT64, - float: CODEC_TYPES.BIT32, - int32: CODEC_TYPES.VARINT, - int64: CODEC_TYPES.VARINT, - message: CODEC_TYPES.LENGTH_DELIMITED, - sfixed32: CODEC_TYPES.BIT32, - sfixed64: CODEC_TYPES.BIT64, - sint32: CODEC_TYPES.VARINT, - sint64: CODEC_TYPES.VARINT, - string: CODEC_TYPES.LENGTH_DELIMITED, - uint32: CODEC_TYPES.VARINT, - uint64: CODEC_TYPES.VARINT -} - -interface ClassDef { - name: string - fullName: string - parent?: ClassDef - fields?: Record - nested?: Record - oneofs?: Array -} - -interface EnumDef { - name: string - fullName: string - parent?: ClassDef - values: Record -} - -type MessageDef = ClassDef | EnumDef - -function isEnumDef (obj: any): obj is EnumDef { - return obj.values != null -} - -interface FieldDef { - type: string - id: number - options?: Record - rule: string - optional: boolean - repeated: boolean - lengthLimit?: number - message: boolean - enum: boolean - map: boolean - valueType: string - keyType: string - - /** - * Support proto2 required field. This field means a value should always be - * in the serialized buffer, any message without it should be considered - * invalid. It was removed for proto3. - */ - proto2Required: boolean -} - -function defineFields (fields: Record, messageDef: MessageDef, moduleDef: ModuleDef): string[] { - return Object.entries(fields).map(([fieldName, fieldDef]) => { - if (fieldDef.map) { - return `${fieldName}: Map<${findJsTypeName(fieldDef.keyType ?? 'string', messageDef, moduleDef, fieldDef)}, ${findJsTypeName(fieldDef.valueType, messageDef, moduleDef, fieldDef)}>` - } - - return `${fieldName}${fieldDef.optional ? '?' : ''}: ${findJsTypeName(fieldDef.type, messageDef, moduleDef, fieldDef)}${fieldDef.repeated ? '[]' : ''}` - }) -} - -function compileMessage (messageDef: MessageDef, moduleDef: ModuleDef, flags?: Flags): string { - if (isEnumDef(messageDef)) { - moduleDef.addImport('protons-runtime', 'enumeration') - - // check that the enum def values start from 0 - if (Object.values(messageDef.values)[0] !== 0) { - const message = `enum ${messageDef.name} does not contain a value that maps to zero as it's first element, this is required in proto3 - see https://protobuf.dev/programming-guides/proto3/#enum` - - if (flags?.strict === true) { - throw new ParseError(message) - } else { - // eslint-disable-next-line no-console - console.info(`[WARN] ${message}`) - } - } - - return ` -export enum ${messageDef.name} { - ${ - Object.keys(messageDef.values).map(name => { - return `${name} = '${name}'` - }).join(',\n ').trim() - } -} - -enum __${messageDef.name}Values { - ${ - Object.entries(messageDef.values).map(([name, value]) => { - return `${name} = ${value}` - }).join(',\n ').trim() - } -} - -export namespace ${messageDef.name} { - export const codec = (): Codec<${messageDef.name}> => { - return enumeration<${messageDef.name}>(__${messageDef.name}Values) - } -} -`.trimStart() - } - - let nested = '' - - if (messageDef.nested != null) { - nested = '\n' - nested += Object.values(messageDef.nested) - .map(def => compileMessage(def, moduleDef, flags).trim()) - .join('\n\n') - .split('\n') - .map(line => line.trim() === '' ? '' : ` ${line}`) - .join('\n') - } - - const fields = messageDef.fields ?? {} - - // import relevant modules - moduleDef.addImport('protons-runtime', 'encodeMessage') - moduleDef.addImport('protons-runtime', 'decodeMessage') - moduleDef.addImport('protons-runtime', 'message') - moduleDef.addTypeImport('protons-runtime', 'Codec') - moduleDef.addTypeImport('protons-runtime', 'DecodeOptions') - moduleDef.addTypeImport('uint8arraylist', 'Uint8ArrayList') - - const interfaceFields = defineFields(fields, messageDef, moduleDef) - .join('\n ') - .trim() - - let interfaceDef = '' - let interfaceCodecDef = '' - - if (interfaceFields === '') { - interfaceDef = ` -export interface ${messageDef.name} {}` - } else { - interfaceDef = ` -export interface ${messageDef.name} { - ${ - defineFields(fields, messageDef, moduleDef) - .join('\n ') - .trim() - } -}` - } - - const encodeFields = Object.entries(fields) - .map(([name, fieldDef]) => { - let codec: string = encoders[fieldDef.type] - let type: string = fieldDef.map ? 'message' : fieldDef.type - let typeName: string = '' - - if (codec == null) { - if (fieldDef.enum) { - moduleDef.addImport('protons-runtime', 'enumeration') - type = 'enum' - } else { - moduleDef.addImport('protons-runtime', 'message') - type = 'message' - } - - typeName = findJsTypeName(fieldDef.type, messageDef, moduleDef, fieldDef) - codec = `${typeName}.codec()` - } - - let valueTest = `obj.${name} != null` - - if (fieldDef.map) { - valueTest = `obj.${name} != null && obj.${name}.size !== 0` - } else if (!fieldDef.optional && !fieldDef.repeated && !fieldDef.proto2Required) { - let defaultValueTestGenerator = defaultValueTestGenerators[type] - - // proto3 singular fields should only be written out if they are not the default value - if (defaultValueTestGenerator != null) { - const jsTypeOverride = findJsTypeOverride(type, fieldDef) - - if (jsTypeOverride != null && defaultValueTestGeneratorsJsTypeOverrides[jsTypeOverride] != null) { - defaultValueTestGenerator = defaultValueTestGeneratorsJsTypeOverrides[jsTypeOverride] - } - - valueTest = `${defaultValueTestGenerator(`obj.${name}`)}` - } else if (type === 'enum') { - // handle enums - const def = findDef(fieldDef.type, messageDef, moduleDef) - - if (!isEnumDef(def)) { - throw new Error(`${fieldDef.type} was not enum def`) - } - - valueTest = `obj.${name} != null` - - // singular enums default to 0, but enums can be defined without a 0 - // value which is against the proto3 spec but is tolerated - if (Object.values(def.values)[0] === 0) { - valueTest += ` && __${fieldDef.type}Values[obj.${name}] !== 0` - } - } - } - - function createWriteField (valueVar: string): () => string { - const id = (fieldDef.id << 3) | codecTypes[type] - - if (fieldDef.enum) { - const def = findDef(fieldDef.type, messageDef, moduleDef) - - if (!isEnumDef(def)) { - throw new Error(`${fieldDef.type} was not enum def`) - } - } - - let writeField = (): string => { - const encoderGenerator = encoderGenerators[type] - const jsTypeOverride = findJsTypeOverride(type, fieldDef) - - return `w.uint32(${id}) - ${encoderGenerator == null ? `${codec}.encode(${valueVar}, w)` : encoderGenerator(valueVar, jsTypeOverride)}` - } - - if (type === 'message') { - // message fields are only written if they have values. But if a message - // is part of a repeated field, and consists of only default values it - // won't be written, so write a zero-length buffer if that's the case - writeField = (): string => `w.uint32(${id}) - ${typeName}.codec().encode(${valueVar}, w)` - } - - return writeField - } - - let writeField = createWriteField(`obj.${name}`) - - if (fieldDef.repeated) { - if (fieldDef.map) { - writeField = () => ` - for (const [key, value] of obj.${name}.entries()) { - ${ - createWriteField('{ key, value }')() - .split('\n') - .map(s => { - const trimmed = s.trim() - - return trimmed === '' ? trimmed : ` ${s}` - }) - .join('\n') - } - } - `.trim() - } else { - writeField = () => ` - for (const value of obj.${name}) { - ${ - createWriteField('value')() - .split('\n') - .map(s => { - const trimmed = s.trim() - - return trimmed === '' ? trimmed : ` ${s}` - }) - .join('\n') - } - } - `.trim() - } - } - - return ` - if (${valueTest}) { - ${writeField()} - }` - }).join('\n') - - const enforceOneOfEncoding = createOneOfEncoding(messageDef) - const enforceOneOfDecoding = createOneOfDecoding(messageDef) - - const decodeFields = Object.entries(fields) - .map(([fieldName, fieldDef]) => { - function createReadField (fieldName: string, fieldDef: FieldDef): string { - let codec: string = encoders[fieldDef.type] - let type: string = fieldDef.type - - if (codec == null) { - if (fieldDef.enum) { - moduleDef.addImport('protons-runtime', 'enumeration') - type = 'enum' - } else { - moduleDef.addImport('protons-runtime', 'message') - type = 'message' - } - - const typeName = findJsTypeName(fieldDef.type, messageDef, moduleDef, fieldDef) - codec = `${typeName}.codec()` - } - - // override setting type on js object - const jsTypeOverride = findJsTypeOverride(fieldDef.type, fieldDef) - - let fieldOpts = '' - - if (fieldDef.message) { - let suffix = '' - - if (fieldDef.repeated) { - suffix = '$' - } - - fieldOpts = `, { - limits: opts.limits?.${fieldName}${suffix} - }` - } - - if (fieldDef.map) { - fieldOpts = `, { - limits: { - value: opts.limits?.${fieldName}$value - } - }` - - // do not pass limit opts to map value types that are enums or - // primitives - only support messages - if (types[fieldDef.valueType] != null) { - // primmitive type - fieldOpts = '' - } else { - const valueType = findDef(fieldDef.valueType, messageDef, moduleDef) - - if (isEnumDef(valueType)) { - // enum type - fieldOpts = '' - } - } - } - - const parseValue = `${decoderGenerators[type] == null - ? `${codec}.decode(reader${type === 'message' - ? `, reader.uint32()${fieldOpts}` - : ''})` - : decoderGenerators[type](jsTypeOverride)}` - - if (fieldDef.map) { - moduleDef.addImport('protons-runtime', 'MaxSizeError') - - let limit = ` - if (opts.limits?.${fieldName} != null && obj.${fieldName}.size === opts.limits.${fieldName}) { - throw new MaxSizeError('Decode error - map field "${fieldName}" had too many elements') - } -` - - if (fieldDef.lengthLimit != null) { - limit += ` - if (obj.${fieldName}.size === ${fieldDef.lengthLimit}) { - throw new MaxSizeError('Decode error - map field "${fieldName}" had too many elements') - } -` - } - - return `case ${fieldDef.id}: {${limit} - const entry = ${parseValue} - obj.${fieldName}.set(entry.key, entry.value) - break - }` - } else if (fieldDef.repeated) { - moduleDef.addImport('protons-runtime', 'MaxLengthError') - - let limit = ` - if (opts.limits?.${fieldName} != null && obj.${fieldName}.length === opts.limits.${fieldName}) { - throw new MaxLengthError('Decode error - map field "${fieldName}" had too many elements') - } -` - - if (fieldDef.lengthLimit != null) { - limit += ` - if (obj.${fieldName}.length === ${fieldDef.lengthLimit}) { - throw new MaxLengthError('Decode error - repeated field "${fieldName}" had too many elements') - } -` - } - - return `case ${fieldDef.id}: {${limit} - obj.${fieldName}.push(${parseValue}) - break - }` - } - - return `case ${fieldDef.id}: { - obj.${fieldName} = ${parseValue} - break - }` - } - - return createReadField(fieldName, fieldDef) - }) - .join('\n ') - - interfaceCodecDef = ` - let _codec: Codec<${messageDef.name}> - - export const codec = (): Codec<${messageDef.name}> => { - if (_codec == null) { - _codec = message<${messageDef.name}>((obj, w, opts = {}) => { - if (opts.lengthDelimited !== false) { - w.fork() - } -${enforceOneOfEncoding}${encodeFields === '' ? '' : `${encodeFields}\n`} - if (opts.lengthDelimited !== false) { - w.ldelim() - } - }, (reader, length, opts = {}) => { - const obj: any = {${createDefaultObject(fields, messageDef, moduleDef)}} - - const end = length == null ? reader.len : reader.pos + length - - while (reader.pos < end) { - const tag = reader.uint32() - - switch (tag >>> 3) {${decodeFields === '' ? '' : `\n ${decodeFields}`} - default: { - reader.skipType(tag & 7) - break - } - } - } -${enforceOneOfDecoding === '' ? '' : `${enforceOneOfDecoding}\n`} - return obj - }) - } - - return _codec - } - - export const encode = (obj: Partial<${messageDef.name}>): Uint8Array => { - return encodeMessage(obj, ${messageDef.name}.codec()) - } - - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions<${messageDef.name}>): ${messageDef.name} => { - return decodeMessage(buf, ${messageDef.name}.codec(), opts) - }` - - return ` -${interfaceDef} - -export namespace ${messageDef.name} { - ${`${nested}${nested !== '' && interfaceCodecDef !== '' ? '\n' : ''}${interfaceCodecDef}`.trim()} -} -`.trimStart() -} - -interface Import { - symbol: string - alias?: string - type: boolean -} - -class ModuleDef { - imports: Map - types: Set - compiled: string[] - globals: Record - - constructor () { - this.imports = new Map() - this.types = new Set() - this.compiled = [] - this.globals = {} - } - - addImport (module: string, symbol: string, alias?: string): void { - const defs = this._findDefs(module) - - for (const def of defs) { - // check if we already have a definition for this symbol - if (def.symbol === symbol) { - if (alias !== def.alias) { - throw new Error(`Type symbol ${symbol} imported from ${module} with alias ${def.alias} does not match alias ${alias}`) - } - - // if it was a type before it's not now - def.type = false - return - } - } - - defs.push({ - symbol, - alias, - type: false - }) - } - - addTypeImport (module: string, symbol: string, alias?: string): void { - const defs = this._findDefs(module) - - for (const def of defs) { - // check if we already have a definition for this symbol - if (def.symbol === symbol) { - if (alias !== def.alias) { - throw new Error(`Type symbol ${symbol} imported from ${module} with alias ${def.alias} does not match alias ${alias}`) - } - - return - } - } - - defs.push({ - symbol, - alias, - type: true - }) - } - - _findDefs (module: string): Import[] { - let defs = this.imports.get(module) - - if (defs == null) { - defs = [] - this.imports.set(module, defs) - } - - return defs - } -} - -function defineModule (def: ClassDef, flags: Flags): ModuleDef { - const moduleDef = new ModuleDef() - const defs = def.nested - - if (defs == null) { - throw new NoMessagesFoundError('No top-level messages found in protobuf') - } - - function defineMessage (defs: Record, parent?: ClassDef, flags?: Flags): void { - for (const className of Object.keys(defs)) { - const classDef = defs[className] - - classDef.name = className - classDef.parent = parent - classDef.fullName = parent == null ? className : `${parent.fullName}.${className}` - - if (classDef.nested != null) { - defineMessage(classDef.nested, classDef) - } - - if (classDef.fields != null) { - for (const name of Object.keys(classDef.fields)) { - const fieldDef = classDef.fields[name] - fieldDef.repeated = fieldDef.rule === 'repeated' - fieldDef.optional = !fieldDef.repeated && fieldDef.options?.proto3_optional === true - fieldDef.map = fieldDef.keyType != null - fieldDef.lengthLimit = fieldDef.options?.['(protons.options).limit'] - fieldDef.proto2Required = false - - if (fieldDef.rule === 'required') { - const message = `field "${name}" is required, this is not allowed in proto3. Please convert your proto2 definitions to proto3 - see https://github.com/ipfs/protons/wiki/Required-fields-and-protobuf-3` - - if (flags?.strict === true) { - throw new ParseError(message) - } else { - fieldDef.proto2Required = true - - // eslint-disable-next-line no-console - console.info(`[WARN] ${message}`) - } - } - } - } - - if (parent == null) { - moduleDef.globals[className] = classDef - } - } - } - - function updateTypes (defs: Record, parent?: ClassDef): void { - for (const className of Object.keys(defs)) { - const classDef = defs[className] - - if (classDef.nested != null) { - updateTypes(classDef.nested, classDef) - } - - if (classDef.fields != null) { - for (const name of Object.keys(classDef.fields)) { - const fieldDef = classDef.fields[name] - if (types[fieldDef.type] == null) { - const def = findDef(fieldDef.type, classDef, moduleDef) - - fieldDef.enum = isEnumDef(def) - fieldDef.message = !fieldDef.enum - - if (fieldDef.message && !fieldDef.repeated) { - // the default type for a message is unset so they are always optional - // https://developers.google.com/protocol-buffers/docs/proto3#default - fieldDef.optional = true - } - } - } - } - } - } - - defineMessage(defs, undefined, flags) - - // set enum/message fields now all messages have been defined - updateTypes(defs) - - for (const className of Object.keys(defs)) { - const classDef = defs[className] - - moduleDef.compiled.push(compileMessage(classDef, moduleDef, flags)) - } - - return moduleDef -} - -interface Flags { +export interface Flags { /** * Specifies an output directory */ @@ -1240,197 +232,9 @@ export async function generate (source: string, flags: Flags): Promise { } const def = JSON.parse(json) - - for (const [className, classDef] of Object.entries(def.nested ?? {})) { - for (const [fieldName, fieldDef] of Object.entries(classDef.fields ?? {})) { - if (fieldDef.keyType == null) { - continue - } - - // https://developers.google.com/protocol-buffers/docs/proto3#backwards_compatibility - const mapEntryType = `${className}$${fieldName}Entry` - - classDef.nested = classDef.nested ?? {} - classDef.nested[mapEntryType] = { - fields: { - key: { - type: fieldDef.keyType, - id: 1 - }, - value: { - type: fieldDef.type, - id: 2 - } - } - } - - fieldDef.valueType = fieldDef.type - fieldDef.type = mapEntryType - fieldDef.rule = 'repeated' - } - - configureOnOfs(classDef) - } - - const moduleDef = defineModule(def, flags) - - const ignores = [ - '/* eslint-disable import/export */', - '/* eslint-disable complexity */', - '/* eslint-disable @typescript-eslint/no-namespace */', - '/* eslint-disable @typescript-eslint/no-unnecessary-boolean-literal-compare */', - '/* eslint-disable @typescript-eslint/no-empty-interface */', - '/* eslint-disable import/consistent-type-specifier-style */', - '/* eslint-disable @typescript-eslint/no-unused-vars */' - ] - - const imports = [] - const importedModules = Array.from([...moduleDef.imports.entries()]) - .sort((a, b) => { - return a[0].localeCompare(b[0]) - }) - .sort((a, b) => { - const aAllTypes = a[1].reduce((acc, curr) => { - return acc && curr.type - }, true) - - const bAllTypes = b[1].reduce((acc, curr) => { - return acc && curr.type - }, true) - - if (aAllTypes && !bAllTypes) { - return 1 - } - - if (!aAllTypes && bAllTypes) { - return -1 - } - - return 0 - }) - - // add imports - for (const imp of importedModules) { - const symbols = imp[1] - .filter(imp => !imp.type) - .sort((a, b) => { - return a.symbol.localeCompare(b.symbol) - }).map(imp => { - return `${imp.symbol}${imp.alias != null ? ` as ${imp.alias}` : ''}` - }).join(', ') - - if (symbols.length > 0) { - imports.push(`import { ${symbols} } from '${imp[0]}'`) - } - } - - // add type imports - for (const imp of importedModules) { - const symbols = imp[1] - .filter(imp => imp.type) - .sort((a, b) => { - return a.symbol.localeCompare(b.symbol) - }).map(imp => { - return `${imp.symbol}${imp.alias != null ? ` as ${imp.alias}` : ''}` - }).join(', ') - - if (symbols.length > 0) { - imports.push(`import type { ${symbols} } from '${imp[0]}'`) - } - } - - const lines = [ - ...ignores, - '', - ...imports, - '', - ...moduleDef.compiled - ] - - const content = lines.join('\n').trim() + const module = new Module(def, flags) + const content = module.compile() const outputPath = pathWithExtension(source, '.ts', flags.output) await fs.writeFile(outputPath, content + '\n') } - -function configureOnOfs (classDef: any): void { - const oneOfs: Record = classDef.oneofs ?? {} - - for (const [, { oneof: fields }] of Object.entries(oneOfs)) { - fields.forEach(field => { - classDef.fields[field].options ??= {} - classDef.fields[field].options.proto3_optional = true - classDef.fields[field].oneof = fields - }) - } - - const oneofs: Record = classDef.oneofs ?? {} - - // reverse order of oneofs as spec says last field overwrites all others - classDef.oneofs = Object.values(oneofs).map(({ oneof }) => oneof.reverse()) - - for (const nestedDef of Object.values(classDef.nested ?? {})) { - configureOnOfs(nestedDef) - } -} - -function createOneOfEncoding (messageDef: ClassDef): string { - if (messageDef.oneofs == null) { - return '' - } - - let oneofs = messageDef.oneofs.map(fields => { - if (fields.length < 2) { - return '' - } - - let oneof = '' - - for (const name of fields) { - oneof += ` - if (obj.${name} != null) { -${fields - .filter(field => field !== name) - .map(name => ` obj.${name} = undefined`).join('\n')} - } -` - } - - return oneof.trimEnd() - }).join('\n').trimEnd() - - if (oneofs !== '') { - oneofs = ` - obj = { ...obj } -${oneofs} -` - } - - return oneofs -} - -function createOneOfDecoding (messageDef: ClassDef): string { - if (messageDef.oneofs == null) { - return '' - } - - return messageDef.oneofs.map(fields => { - if (fields.length < 2) { - return '' - } - - let oneof = '' - - for (const name of fields) { - oneof += ` - if (obj.${name} != null) { -${fields - .filter(field => field !== name) - .map(name => ` delete obj.${name}`).join('\n')} - } -` - } - - return oneof.trimEnd() - }).join('\n').trimEnd() -} diff --git a/packages/protons/src/types/enum.ts b/packages/protons/src/types/enum.ts new file mode 100644 index 0000000..655da44 --- /dev/null +++ b/packages/protons/src/types/enum.ts @@ -0,0 +1,112 @@ +import { ParseError } from 'protons-runtime' +import type { Parent, Type } from './index.ts' +import type { Field } from '../fields/field.ts' + +export interface EnumDef { + values: Record +} + +export function isEnumDef (obj?: any): obj is EnumDef { + return obj?.values != null +} + +export class Enum implements Type { + public pbType: string + public jsType: string + public values: Map + public lowestValue: number + public lowestValueName: string + + constructor (pbType: string, jsType: string, def: EnumDef) { + this.pbType = pbType + this.jsType = jsType + this.values = new Map(Object.entries(def.values)) + + // select lowest-value enum - should be 0 but it's not guaranteed + const lowestValue = [...this.values.entries()] + .sort((a, b) => { + if (a[1] < b[1]) { + return 1 + } + + if (a[1] > b[1]) { + return -1 + } + + return 0 + }) + .pop() + + if (lowestValue == null) { + throw new Error(`Could not find lowest enum value for ${pbType}`) + } + + this.lowestValue = lowestValue[1] + this.lowestValueName = lowestValue[0] + } + + init (): void { + + } + + getDecoder (field: Field): string { + return `${this.jsType}.codec().decode(reader)` + } + + getStreamingDecoder (field: Field): string { + return `${this.jsType}.codec().stream(reader)` + } + + getEncoder (field: Field, accessor: string): string { + return `${this.jsType}.codec().encode(${accessor}, w)` + } + + getValueTest (field: Field, accessor: string): string { + if (field.proto2Required) { + return 'true' + } + + const valueTest = `${accessor} != null` + + // singular enums default to 0, but enums can be defined without a 0 + // value which is against the proto3 spec but is tolerated + if (field.optional || field.proto2Required) { + return valueTest + } + + return `${valueTest} && __${field.type}Values[${accessor}] !== 0` + } + + public compile (parent: Parent): string { + // import required modules + parent.addImport('protons-runtime', 'enumeration') + + // check that the enum def values start from 0 + if ([...this.values.values()][0] !== 0) { + const message = `enum ${this.pbType} does not contain a value that maps to zero as it's first element, this is required in proto3 - see https://protobuf.dev/programming-guides/proto3/#enum` + + if (parent.flags.strict === true) { + throw new ParseError(message) + } else { + // eslint-disable-next-line no-console + console.info(`[WARN] ${message}`) + } + } + + return ` +export enum ${this.pbType} { + ${[...this.values.keys()].map(key => `${key} = '${key}'`).join(',\n ')} +} + +enum __${this.pbType}Values { + ${[...this.values.entries()].map(([key, value]) => `${key} = ${value}`).join(',\n ')} +} + +export namespace ${this.pbType} { + export const codec = (): Codec<${this.pbType}> => { + return enumeration<${this.pbType}>(__${this.pbType}Values) + } +} +`.trimStart() + } +} diff --git a/packages/protons/src/types/index.ts b/packages/protons/src/types/index.ts new file mode 100644 index 0000000..db02ec2 --- /dev/null +++ b/packages/protons/src/types/index.ts @@ -0,0 +1,21 @@ +import type { Field } from '../fields/field.ts' +import type { Flags } from '../index.ts' +import type { Module } from './module.ts' + +export interface Type { + jsType: string + pbType: string + init(module: Module): void + getDecoder(field: Field, indent?: string): string + getStreamingDecoder(field: Field, prefix: string, indent?: string): string + getEncoder(field: Field, accessor: string): string + getValueTest(field: Field, accessor: string): string +} + +export interface Parent { + flags: Flags + findType (type: string, jsOverride?: 'string' | 'number'): Type + addImport (module: string, symbol: string, alias?: string): void + addTypeImport (module: string, symbol: string, alias?: string): void + addEslintIgnore (rule: string): void +} diff --git a/packages/protons/src/types/message.ts b/packages/protons/src/types/message.ts new file mode 100644 index 0000000..35cb818 --- /dev/null +++ b/packages/protons/src/types/message.ts @@ -0,0 +1,524 @@ +import { ArrayField, isArrayFieldDef } from '../fields/array-field.ts' +import { EnumField } from '../fields/enum-field.ts' +import { Field } from '../fields/field.ts' +import { isMapFieldDef, MapField } from '../fields/map-field.ts' +import { MessageField } from '../fields/message-field.ts' +import { Enum } from './enum.ts' +import { isPrimitiveType, Primitive } from './primitive.ts' +import type { EnumDef } from './enum.ts' +import type { Parent, Type } from './index.ts' +import type { FieldDef } from '../fields/field.ts' +import type { Flags } from '../index.ts' + +interface StreamEvent { + name: string + fields: string[] + type: 'field' + | 'collection-primitive-member' + | 'collection-message-member-field' + | 'sub-message-field' + | 'sub-message-collection-primitive-member' + | 'sub-message-collection-message-member-field' +} + +function camelize (input: string): string { + return `${input.substring(0, 1).toUpperCase()}${input.substring(1)}` +} + +export interface MessageDef { + fields?: Record + oneofs?: Record + nested?: Record +} + +export function isMessageDef (obj?: any): obj is MessageDef { + return obj?.fields != null +} + +export class Message implements Type { + public pbType: string + public jsType: string + public fields: Field[] + public oneOfs: string[][] + public nested: Record + private def: MessageDef + private parent: Parent + + constructor (pbType: string, jsType: string, def: MessageDef, parent: Parent) { + this.pbType = pbType + this.jsType = jsType + this.oneOfs = [] + this.nested = {} + this.fields = [] + this.def = def + this.parent = parent + + def.fields ??= {} + def.nested ??= {} + def.oneofs ??= {} + + // create extra message types for map type backwards compatibility + // https://developers.google.com/protocol-buffers/docs/proto3#backwards + for (const [fieldName, fieldDef] of Object.entries(def.fields)) { + if (fieldDef.keyType == null) { + continue + } + + const mapEntryType = `${this.pbType}$${fieldName}Entry` + + def.nested[mapEntryType] = { + fields: { + key: { + type: fieldDef.keyType, + id: 1 + }, + value: { + type: fieldDef.type, + id: 2 + } + } + } + + fieldDef.valueType = fieldDef.type + fieldDef.type = mapEntryType + fieldDef.rule = 'repeated' + } + + Object.entries(def.nested ?? {}).forEach(([name, def]) => { + const fullName = `${this.jsType}.${name}` + + if (isMessageDef(def)) { + this.nested[name] = new Message(name, fullName, def, this) + } else { + this.nested[name] = new Enum(name, fullName, def) + } + }) + + for (const [, { oneof: fields }] of Object.entries(def.oneofs)) { + for (const field of fields) { + if (def.fields[field] == null) { + continue + } + + def.fields[field].options ??= {} + def.fields[field].options.proto3_optional = true + def.fields[field].oneof = fields + } + } + + // reverse order of oneofs as spec says last field overwrites all others + this.oneOfs = Object.values(def.oneofs).map(({ oneof }) => oneof.reverse()) + } + + init (): void { + for (const [name, fieldDef] of Object.entries(this.def.fields ?? {})) { + if (isMapFieldDef(fieldDef)) { + this.fields.push(new MapField(name, fieldDef, this)) + } else if (isArrayFieldDef(fieldDef)) { + this.fields.push(new ArrayField(name, fieldDef, this)) + } else { + const type = this.findType(fieldDef.type) + + if (type instanceof Enum) { + this.fields.push(new EnumField(name, fieldDef, this)) + } else if (type instanceof Primitive) { + this.fields.push(new Field(name, fieldDef, this)) + } else { + this.fields.push(new MessageField(name, fieldDef, this)) + } + } + } + + Object.values(this.nested).forEach(type => type.init()) + } + + findType (jsType: string, override?: 'string' | 'number'): Type { + const type = this.nested[override ?? jsType] + + if (type == null) { + return this.parent.findType(jsType, override) + } + + return type + } + + addImport (module: string, symbol: string, alias?: string): void { + this.parent.addImport(module, symbol, alias) + } + + addTypeImport (module: string, symbol: string, alias?: string): void { + this.parent.addTypeImport(module, symbol, alias) + } + + addEslintIgnore (rule: string): void { + this.parent.addEslintIgnore(rule) + } + + get flags (): Flags { + return this.parent.flags + } + + getDecoder (field: Field, indent = ''): string { + let opts = '' + + if (field instanceof MessageField) { + opts = `, { +${indent} limits: opts.limits?.${field.name} +${indent} }` + } else if (field instanceof ArrayField) { + opts = `, { +${indent} limits: opts.limits?.${field.name}$ +${indent} }` + } else if (field instanceof MapField) { + opts = `, { +${indent} limits: { +${indent} value: opts.limits?.${field.name}$value + } +${indent} }` + } + + return `${this.jsType}.codec().decode(reader, reader.uint32()${opts})` + } + + getStreamingDecoder (field: Field, prefix: string, indent = ''): string { + let opts = '' + + if (field instanceof MessageField) { + opts = `, { +${indent} limits: opts.limits?.${field.name} +${indent} }` + } else if (field instanceof ArrayField) { + opts = `, { +${indent} limits: opts.limits?.${field.name}$ +${indent} }` + + return `for (const evt of ${this.jsType}.codec().stream(reader, reader.uint32(), ${prefix}${opts})) { + yield { + ...evt, + index: obj.${field.name} + } + }` + } else if (field instanceof MapField) { + opts = `, { +${indent} limits: { +${indent} value: opts.limits?.${field.name}$value + } +${indent} }` + } + + return `yield * ${this.jsType}.codec().stream(reader, reader.uint32(), ${prefix}${opts})` + } + + getEncoder (field: Field, accessor: string): string { + if (field instanceof ArrayField) { + // message fields are only written if they have values. But if a message + // is part of a repeated field, and consists of only default values it + // won't be written, so write a zero-length buffer if that's the case + // writeField = (): string => `w.uint32(${id}) + // ${type.jsType}.codec().encode(${valueVar}, w)` + } + + return `${this.jsType}.codec().encode(${accessor}, w)` + } + + getValueTest (field: Field): string { + return `obj.${field.name} != null` + } + + public compile (parent: Parent, indent: string = ''): string { + // import required modules + parent.addImport('protons-runtime', 'encodeMessage') + parent.addImport('protons-runtime', 'decodeMessage') + parent.addImport('protons-runtime', 'streamMessage') + parent.addImport('protons-runtime', 'message') + parent.addTypeImport('protons-runtime', 'Codec') + parent.addTypeImport('protons-runtime', 'DecodeOptions') + parent.addTypeImport('uint8arraylist', 'Uint8ArrayList') + + let nested = '' + + if (this.nested != null && [...Object.values(this.nested)].length > 0) { + nested += Object.values(this.nested) + .map(def => def.compile(this, `${indent} `).trim()) + .join('\n\n') + nested = nested.split('\n').join('\n ') + nested = ` + ${nested} +` + } + + const interfaceFields = this.fields.map(field => field.getInterfaceField(this)) + .join('\n ') + .trim() + + let interfaceDef = '' + let interfaceCodecDef = '' + + if (interfaceFields === '') { + interfaceDef = ` +export interface ${this.pbType} {}` + } else { + interfaceDef = ` +export interface ${this.pbType} { + ${interfaceFields} +}` + } + + const enforceOneOfEncoding = this.createOneOfEncoding() + const enforceOneOfDecoding = this.createOneOfDecoding() + const streamEvents = this.getStreamEvents() + + const encodeFields = this.fields.map(field => field.getEncoder(this)) + const decodeFields = this.fields.map(field => field.getDecoder(this)) + const streamFields = this.fields.map(field => field.getStreamingDecoder(this)) + + const streamGeneratorEvents = streamEvents.map(evt => evt.name) + + if (streamGeneratorEvents.length === 0) { + this.addEslintIgnore('require-yield') + streamGeneratorEvents.push('{}') + } + + interfaceCodecDef = ` + let _codec: Codec<${this.pbType}> + + export const codec = (): Codec<${this.pbType}> => { + if (_codec == null) { + _codec = message<${this.pbType}>((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + }${enforceOneOfEncoding}${this.formatFields(encodeFields)} + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = {${this.createDefaultObject()}} + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) {${this.formatFields(decodeFields, '\n ')} + default: { + reader.skipType(tag & 7) + break + } + } + } +${enforceOneOfDecoding === '' ? '' : `${enforceOneOfDecoding}\n`} + return obj + }, function * (reader, length, prefix, opts = {}) { + ${this.createLimitObject()}const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) {${this.formatFields(streamFields, '\n ')} + default: { + reader.skipType(tag & 7) + break + } + } + } + }) + } + + return _codec + }${this.formatStreamEvents(streamEvents)} + + export function encode (obj: Partial<${this.pbType}>): Uint8Array { + return encodeMessage(obj, ${this.pbType}.codec()) + } + + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions<${this.pbType}>): ${this.pbType} { + return decodeMessage(buf, ${this.pbType}.codec(), opts) + } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions<${this.pbType}>): Generator<${streamGeneratorEvents.join(' | ')}> { + return streamMessage(buf, ${this.pbType}.codec(), opts) + }` + + return ` +${interfaceDef} + +export namespace ${this.pbType} {${nested}${interfaceCodecDef.trimEnd()} +} +`.trimStart() + } + + private createOneOfEncoding (): string { + let oneOfs = this.oneOfs.map(fields => { + if (fields.length < 2) { + return '' + } + + let oneOf = '' + + for (const name of fields) { + oneOf += ` + if (obj.${name} != null) { +${fields + .filter(field => field !== name) + .map(name => ` obj.${name} = undefined`).join('\n')} + } +` + } + + return oneOf.trimEnd() + }).join('\n').trimEnd() + + if (oneOfs !== '') { + oneOfs = ` + + obj = { ...obj } +${oneOfs}` + } + + return oneOfs + } + + private createOneOfDecoding (): string { + return this.oneOfs.map(fields => { + if (fields.length < 2) { + return '' + } + + let oneOf = '' + + for (const name of fields) { + oneOf += ` + if (obj.${name} != null) { +${fields + .filter(field => field !== name) + .map(name => ` delete obj.${name}`).join('\n')} + } +` + } + + return oneOf.trimEnd() + }).join('\n').trimEnd() + } + + createDefaultObject (indent = ''): string { + const output = this.fields + .map((field) => field.getDefaultField(this)) + .filter(Boolean) + .join(`,\n ${indent}`) + + if (output !== '') { + return ` + ${indent}${output} + ${indent}` + } + + return '' + } + + createLimitObject (): string { + const output = this.fields.map(field => field.getLimitField()) + .filter(Boolean) + .join(',\n ') + + if (output !== '') { + return `const obj = { + ${output} + } + + ` + } + + return '' + } + + formatStreamEvents (streamEvents: StreamEvent[]): string { + if (streamEvents.length === 0) { + return '' + } + + return ` + + ${streamEvents.map(evt => `export interface ${evt.name} { + ${evt.fields.join('\n ')} + }`).join('\n\n ')}` + } + + formatFields (fields: string[], delimiter = '\n'): string { + if (fields.length === 0) { + return '' + } + + return ` + ${fields.join(delimiter)}` + } + + getStreamEvents (): StreamEvent[] { + const streamEvents: StreamEvent[] = [] + + this.fields.forEach(field => { + if (field instanceof MapField) { + const keyType = this.findType(field.keyType) + const valueType = this.findType(field.valueType) + + if (isPrimitiveType(valueType.pbType)) { + streamEvents.push({ + name: `${this.pbType}${camelize(field.name)}FieldEvent`, + fields: [ + `field: '${field.name}$entry'`, + `key: ${keyType.jsType}`, + `value: ${valueType.jsType}` + ], + type: 'collection-primitive-member' + }) + } + } else if (field instanceof ArrayField) { + const type = this.findType(field.type) + + if (isPrimitiveType(type.pbType)) { + streamEvents.push({ + name: `${this.pbType}${camelize(field.name)}FieldEvent`, + fields: [ + `field: '${field.name}$entry'`, + 'index: number', + `value: ${type.jsType}` + ], + type: 'collection-primitive-member' + }) + } + } else if (field instanceof MessageField) { + // include sub messages + streamEvents.push(...field.getMessage(this).getStreamEvents().map(evt => { + let type = evt.type + + if (evt.type === 'field') { + type = 'sub-message-field' + } else if (evt.type === 'collection-primitive-member') { + type = 'sub-message-collection-primitive-member' + } else if (evt.type === 'collection-message-member-field') { + type = 'sub-message-collection-message-member-field' + } + + return { + ...evt, + name: `${this.pbType}${camelize(field.name)}${evt.name}`, + type + } + })) + } else { + const type = this.findType(field.type) + + streamEvents.push({ + name: `${this.pbType}${camelize(field.name)}FieldEvent`, + fields: [ + `field: '${field.name}'`, + `value: ${type.jsType}` + ], + type: 'field' + }) + } + }) + + return streamEvents + } +} diff --git a/packages/protons/src/types/module.ts b/packages/protons/src/types/module.ts new file mode 100644 index 0000000..c9b99d9 --- /dev/null +++ b/packages/protons/src/types/module.ts @@ -0,0 +1,234 @@ +import { NoMessagesFoundError } from 'protons-runtime' +import { Enum, isEnumDef } from './enum.ts' +import { Message } from './message.ts' +import { Primitive } from './primitive.ts' +import type { EnumDef } from './enum.ts' +import type { MessageDef } from './message.ts' +import type { Flags } from '../index.ts' +import type { Type } from './index.ts' + +const types: Record = { + bool: 'boolean', + bytes: 'Uint8Array', + double: 'number', + fixed32: 'number', + fixed64: 'bigint', + float: 'number', + int32: 'number', + int64: 'bigint', + sfixed32: 'number', + sfixed64: 'bigint', + sint32: 'number', + sint64: 'bigint', + string: 'string', + uint32: 'number', + uint64: 'bigint' +} + +interface Import { + symbol: string + alias?: string + type: boolean +} + +export interface ModuleDef { + nested?: Record +} + +export class Module { + private imports: Map + private types: Record + private eslintIgnores: string[] + public flags: Flags + public globals: Array + + constructor (def: ModuleDef, flags: Flags) { + this.imports = new Map() + this.flags = flags + this.types = {} + this.globals = [] + this.eslintIgnores = [] + + Object.entries(types).forEach(([pbType, jsType]) => { + this.types[pbType] = new Primitive(pbType, jsType) + }) + + const defs = def.nested + + if (defs == null) { + throw new NoMessagesFoundError('No top-level messages found in protobuf') + } + + for (const [name, def] of Object.entries(defs)) { + let type: Message | Enum + + if (isEnumDef(def)) { + type = new Enum(name, name, def) + } else { + type = new Message(name, name, def, this) + } + + this.globals.push(type) + this.types[name] = type + } + + this.globals.forEach(type => type.init()) + } + + addImport (module: string, symbol: string, alias?: string): void { + const defs = this._findDefs(module) + + for (const def of defs) { + // check if we already have a definition for this symbol + if (def.symbol === symbol) { + if (alias !== def.alias) { + throw new Error(`Type symbol ${symbol} imported from ${module} with alias ${def.alias} does not match alias ${alias}`) + } + + // if it was a type before it's not now + def.type = false + return + } + } + + defs.push({ + symbol, + alias, + type: false + }) + } + + addTypeImport (module: string, symbol: string, alias?: string): void { + const defs = this._findDefs(module) + + for (const def of defs) { + // check if we already have a definition for this symbol + if (def.symbol === symbol) { + if (alias !== def.alias) { + throw new Error(`Type symbol ${symbol} imported from ${module} with alias ${def.alias} does not match alias ${alias}`) + } + + return + } + } + + defs.push({ + symbol, + alias, + type: true + }) + } + + addEslintIgnore (rule: string): void { + if (this.eslintIgnores.includes(rule)) { + return + } + + this.eslintIgnores.push(rule) + } + + _findDefs (module: string): Import[] { + let defs = this.imports.get(module) + + if (defs == null) { + defs = [] + this.imports.set(module, defs) + } + + return defs + } + + compile (): string { + const compiled = this.globals.map(def => def.compile(this)).flat() + + // TODO: make these conditional + // const ignores: string[] = [ + // '/* eslint-disable import/export */', + // '/* eslint-disable complexity */', + // '/* eslint-disable @typescript-eslint/no-namespace */', + // '/* eslint-disable @typescript-eslint/no-unnecessary-boolean-literal-compare */', + // '/* eslint-disable @typescript-eslint/no-empty-interface */', + // '/* eslint-disable import/consistent-type-specifier-style */', + // '/* eslint-disable @typescript-eslint/no-unused-vars */', + // '/* eslint-disable require-yield */' + // ] + + const imports = [] + const importedModules = Array.from([...this.imports.entries()]) + .sort((a, b) => { + return a[0].localeCompare(b[0]) + }) + .sort((a, b) => { + const aAllTypes = a[1].reduce((acc, curr) => { + return acc && curr.type + }, true) + + const bAllTypes = b[1].reduce((acc, curr) => { + return acc && curr.type + }, true) + + if (aAllTypes && !bAllTypes) { + return 1 + } + + if (!aAllTypes && bAllTypes) { + return -1 + } + + return 0 + }) + + // add imports + for (const imp of importedModules) { + const symbols = imp[1] + .filter(imp => !imp.type) + .sort((a, b) => { + return a.symbol.localeCompare(b.symbol) + }).map(imp => { + return `${imp.symbol}${imp.alias != null ? ` as ${imp.alias}` : ''}` + }).join(', ') + + if (symbols.length > 0) { + imports.push(`import { ${symbols} } from '${imp[0]}'`) + } + } + + // add type imports + for (const imp of importedModules) { + const symbols = imp[1] + .filter(imp => imp.type) + .sort((a, b) => { + return a.symbol.localeCompare(b.symbol) + }).map(imp => { + return `${imp.symbol}${imp.alias != null ? ` as ${imp.alias}` : ''}` + }).join(', ') + + if (symbols.length > 0) { + imports.push(`import type { ${symbols} } from '${imp[0]}'`) + } + } + + return [ + ...this.eslintIgnores.map(rule => `/* eslint-disable ${rule} */`), + '', + ...imports, + '', + ...compiled + ] + .join('\n') + .split('\n') + .map((line) => line.trim() === '' ? '' : line) + .join('\n') + .trim() + } + + findType (jsType: string, override?: 'string' | 'number'): Type { + const type = this.types[override ?? jsType] + + if (type == null) { + throw new Error(`Type for "${jsType}"${override == null ? '' : ` (overridden to "${override}")`} not found in ${[...Object.keys(this.types)].join(', ')}`) + } + + return type + } +} diff --git a/packages/protons/src/types/primitive.ts b/packages/protons/src/types/primitive.ts new file mode 100644 index 0000000..b6cbc8e --- /dev/null +++ b/packages/protons/src/types/primitive.ts @@ -0,0 +1,219 @@ +import { ArrayField } from '../fields/array-field.ts' +import type { Type } from './index.ts' +import type { Field } from '../fields/field.ts' + +const decoderGenerators: Record string> = { + bool: () => 'reader.bool()', + bytes: () => 'reader.bytes()', + double: () => 'reader.double()', + fixed32: () => 'reader.fixed32()', + fixed64: (jsTypeOverride) => { + if (jsTypeOverride === 'number') { + return 'reader.fixed64Number()' + } + + if (jsTypeOverride === 'string') { + return 'reader.fixed64String()' + } + + return 'reader.fixed64()' + }, + float: () => 'reader.float()', + int32: () => 'reader.int32()', + int64: (jsTypeOverride) => { + if (jsTypeOverride === 'number') { + return 'reader.int64Number()' + } + + if (jsTypeOverride === 'string') { + return 'reader.int64String()' + } + + return 'reader.int64()' + }, + sfixed32: () => 'reader.sfixed32()', + sfixed64: (jsTypeOverride) => { + if (jsTypeOverride === 'number') { + return 'reader.sfixed64Number()' + } + + if (jsTypeOverride === 'string') { + return 'reader.sfixed64String()' + } + + return 'reader.sfixed64()' + }, + sint32: () => 'reader.sint32()', + sint64: (jsTypeOverride) => { + if (jsTypeOverride === 'number') { + return 'reader.sint64Number()' + } + + if (jsTypeOverride === 'string') { + return 'reader.sint64String()' + } + + return 'reader.sint64()' + }, + string: () => 'reader.string()', + uint32: () => 'reader.uint32()', + uint64: (jsTypeOverride) => { + if (jsTypeOverride === 'number') { + return 'reader.uint64Number()' + } + + if (jsTypeOverride === 'string') { + return 'reader.uint64String()' + } + + return 'reader.uint64()' + } +} + +const encoderGenerators: Record string> = { + bool: (val) => `w.bool(${val})`, + bytes: (val) => `w.bytes(${val})`, + double: (val) => `w.double(${val})`, + fixed32: (val) => `w.fixed32(${val})`, + fixed64: (val, jsTypeOverride) => { + if (jsTypeOverride === 'number') { + return `w.fixed64Number(${val})` + } + + if (jsTypeOverride === 'string') { + return `w.fixed64String(${val})` + } + + return `w.fixed64(${val})` + }, + float: (val) => `w.float(${val})`, + int32: (val) => `w.int32(${val})`, + int64: (val, jsTypeOverride) => { + if (jsTypeOverride === 'number') { + return `w.int64Number(${val})` + } + + if (jsTypeOverride === 'string') { + return `w.int64String(${val})` + } + + return `w.int64(${val})` + }, + sfixed32: (val) => `w.sfixed32(${val})`, + sfixed64: (val, jsTypeOverride) => { + if (jsTypeOverride === 'number') { + return `w.sfixed64Number(${val})` + } + + if (jsTypeOverride === 'string') { + return `w.sfixed64String(${val})` + } + + return `w.sfixed64(${val})` + }, + sint32: (val) => `w.sint32(${val})`, + sint64: (val, jsTypeOverride) => { + if (jsTypeOverride === 'number') { + return `w.sint64Number(${val})` + } + + if (jsTypeOverride === 'string') { + return `w.sint64String(${val})` + } + + return `w.sint64(${val})` + }, + string: (val) => `w.string(${val})`, + uint32: (val) => `w.uint32(${val})`, + uint64: (val, jsTypeOverride) => { + if (jsTypeOverride === 'number') { + return `w.uint64Number(${val})` + } + + if (jsTypeOverride === 'string') { + return `w.uint64String(${val})` + } + + return `w.uint64(${val})` + } +} + +interface DefaultValueTestGenerator { + (field: string): string +} + +const defaultValueTestGenerators: Record = { + bool: (field) => `(${field} != null && ${field} !== false)`, + bytes: (field) => `(${field} != null && ${field}.byteLength > 0)`, + double: (field) => `(${field} != null && ${field} !== 0)`, + fixed32: (field) => `(${field} != null && ${field} !== 0)`, + fixed64: (field) => `(${field} != null && ${field} !== 0n)`, + float: (field) => `(${field} != null && ${field} !== 0)`, + int32: (field) => `(${field} != null && ${field} !== 0)`, + int64: (field) => `(${field} != null && ${field} !== 0n)`, + sfixed32: (field) => `(${field} != null && ${field} !== 0)`, + sfixed64: (field) => `(${field} != null && ${field} !== 0n)`, + sint32: (field) => `(${field} != null && ${field} !== 0)`, + sint64: (field) => `(${field} != null && ${field} !== 0n)`, + string: (field) => `(${field} != null && ${field} !== '')`, + uint32: (field) => `(${field} != null && ${field} !== 0)`, + uint64: (field) => `(${field} != null && ${field} !== 0n)` +} + +const defaultValueTestGeneratorsJsTypeOverrides: Record = { + number: (field) => `(${field} != null && ${field} !== 0)`, + string: (field) => `(${field} != null && ${field} !== '')` +} + +export function isPrimitiveType (pbType: string): boolean { + return [...Object.keys(decoderGenerators)].includes(pbType) +} + +export class Primitive implements Type { + public jsType: string + public pbType: string + + constructor (pbType: string, jsType: string) { + this.jsType = jsType + this.pbType = pbType + } + + init (): void { + + } + + getDecoder (field: Field): string { + return decoderGenerators[this.pbType](field.jsTypeOverride) + } + + getStreamingDecoder (field: Field, prefix: string, indent: string): string { + const generator = decoderGenerators[this.pbType](field.jsTypeOverride) + + if (field instanceof ArrayField) { + return `yield { + field: ${prefix}, + index: obj.${field.name}, + value: ${generator} + }` + } + + return generator + } + + getValueTest (field: Field, accessor: string): string { + // proto3 singular fields should only be written out if they are not the default value + if (!field.optional && !field.proto2Required) { + if (field.jsTypeOverride != null) { + return defaultValueTestGeneratorsJsTypeOverrides[field.jsTypeOverride](accessor) + } + + return defaultValueTestGenerators[field.type](accessor) + } + + return `${accessor} != null` + } + + getEncoder (field: Field, accessor: string): string { + return encoderGenerators[this.pbType](accessor, field.jsTypeOverride) + } +} diff --git a/packages/protons/test/fixtures/basic.ts b/packages/protons/test/fixtures/basic.ts index 4ea2ef8..94a62db 100644 --- a/packages/protons/test/fixtures/basic.ts +++ b/packages/protons/test/fixtures/basic.ts @@ -1,4 +1,6 @@ -import { decodeMessage, encodeMessage, message } from 'protons-runtime' +/* eslint-disable require-yield */ + +import { decodeMessage, encodeMessage, message, streamMessage } from 'protons-runtime' import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' @@ -57,19 +59,60 @@ export namespace Basic { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}foo`, + value: reader.string() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}num`, + value: reader.int32() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface BasicFooFieldEvent { + field: 'foo' + value: string + } + + export interface BasicNumFieldEvent { + field: 'num' + value: number + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Basic.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Basic => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Basic { return decodeMessage(buf, Basic.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Basic.codec(), opts) + } } export interface Empty {} @@ -104,17 +147,34 @@ export namespace Empty { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Empty.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Empty => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Empty { return decodeMessage(buf, Empty.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator<{}> { + return streamMessage(buf, Empty.codec(), opts) + } } diff --git a/packages/protons/test/fixtures/bitswap.ts b/packages/protons/test/fixtures/bitswap.ts index 2a9d20f..4241865 100644 --- a/packages/protons/test/fixtures/bitswap.ts +++ b/packages/protons/test/fixtures/bitswap.ts @@ -1,6 +1,4 @@ -/* eslint-disable complexity */ - -import { decodeMessage, encodeMessage, enumeration, MaxLengthError, message } from 'protons-runtime' +import { decodeMessage, encodeMessage, enumeration, MaxLengthError, message, streamMessage } from 'protons-runtime' import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' @@ -124,19 +122,96 @@ export namespace Message { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}block`, + value: reader.bytes() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}priority`, + value: reader.int32() + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}cancel`, + value: reader.bool() + } + break + } + case 4: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}wantType`, + value: Message.Wantlist.WantType.codec().decode(reader) + } + break + } + case 5: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}sendDontHave`, + value: reader.bool() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface EntryBlockFieldEvent { + field: 'block' + value: Uint8Array + } + + export interface EntryPriorityFieldEvent { + field: 'priority' + value: number + } + + export interface EntryCancelFieldEvent { + field: 'cancel' + value: boolean + } + + export interface EntryWantTypeFieldEvent { + field: 'wantType' + value: Message.Wantlist.WantType + } + + export interface EntrySendDontHaveFieldEvent { + field: 'sendDontHave' + value: boolean + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Entry.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Entry => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Entry { return decodeMessage(buf, Entry.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Entry.codec(), opts) + } } let _codec: Codec @@ -177,7 +252,7 @@ export namespace Message { switch (tag >>> 3) { case 1: { if (opts.limits?.entries != null && obj.entries.length === opts.limits.entries) { - throw new MaxLengthError('Decode error - map field "entries" had too many elements') + throw new MaxLengthError('Decode error - repeated field "entries" had too many elements') } obj.entries.push(Message.Wantlist.Entry.codec().decode(reader, reader.uint32(), { @@ -197,19 +272,70 @@ export namespace Message { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + entries: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + if (opts.limits?.entries != null && obj.entries === opts.limits.entries) { + throw new MaxLengthError('Streaming decode error - repeated field "entries" had too many elements') + } + + for (const evt of Message.Wantlist.Entry.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}entries`, { + limits: opts.limits?.entries$ + })) { + yield { + ...evt, + index: obj.entries + } + } + + obj.entries++ + + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}full`, + value: reader.bool() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface WantlistFullFieldEvent { + field: 'full' + value: boolean + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Wantlist.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Wantlist => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Wantlist { return decodeMessage(buf, Wantlist.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Wantlist.codec(), opts) + } } export interface Block { @@ -268,19 +394,60 @@ export namespace Message { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}prefix`, + value: reader.bytes() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}data`, + value: reader.bytes() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface BlockPrefixFieldEvent { + field: 'prefix' + value: Uint8Array + } + + export interface BlockDataFieldEvent { + field: 'data' + value: Uint8Array + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Block.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Block => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Block { return decodeMessage(buf, Block.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Block.codec(), opts) + } } export enum BlockPresenceType { @@ -355,19 +522,60 @@ export namespace Message { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}cid`, + value: reader.bytes() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}type`, + value: Message.BlockPresenceType.codec().decode(reader) + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface BlockPresenceCidFieldEvent { + field: 'cid' + value: Uint8Array + } + + export interface BlockPresenceTypeFieldEvent { + field: 'type' + value: Message.BlockPresenceType + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, BlockPresence.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): BlockPresence => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): BlockPresence { return decodeMessage(buf, BlockPresence.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, BlockPresence.codec(), opts) + } } let _codec: Codec @@ -435,7 +643,7 @@ export namespace Message { } case 2: { if (opts.limits?.blocks != null && obj.blocks.length === opts.limits.blocks) { - throw new MaxLengthError('Decode error - map field "blocks" had too many elements') + throw new MaxLengthError('Decode error - repeated field "blocks" had too many elements') } obj.blocks.push(reader.bytes()) @@ -443,7 +651,7 @@ export namespace Message { } case 3: { if (opts.limits?.payload != null && obj.payload.length === opts.limits.payload) { - throw new MaxLengthError('Decode error - map field "payload" had too many elements') + throw new MaxLengthError('Decode error - repeated field "payload" had too many elements') } obj.payload.push(Message.Block.codec().decode(reader, reader.uint32(), { @@ -453,7 +661,7 @@ export namespace Message { } case 4: { if (opts.limits?.blockPresences != null && obj.blockPresences.length === opts.limits.blockPresences) { - throw new MaxLengthError('Decode error - map field "blockPresences" had too many elements') + throw new MaxLengthError('Decode error - repeated field "blockPresences" had too many elements') } obj.blockPresences.push(Message.BlockPresence.codec().decode(reader, reader.uint32(), { @@ -473,17 +681,121 @@ export namespace Message { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + blocks: 0, + payload: 0, + blockPresences: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield * Message.Wantlist.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}wantlist`, { + limits: opts.limits?.wantlist + }) + + break + } + case 2: { + if (opts.limits?.blocks != null && obj.blocks === opts.limits.blocks) { + throw new MaxLengthError('Streaming decode error - repeated field "blocks" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}blocks`, + index: obj.blocks, + value: reader.bytes() + } + + obj.blocks++ + + break + } + case 3: { + if (opts.limits?.payload != null && obj.payload === opts.limits.payload) { + throw new MaxLengthError('Streaming decode error - repeated field "payload" had too many elements') + } + + for (const evt of Message.Block.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}payload`, { + limits: opts.limits?.payload$ + })) { + yield { + ...evt, + index: obj.payload + } + } + + obj.payload++ + + break + } + case 4: { + if (opts.limits?.blockPresences != null && obj.blockPresences === opts.limits.blockPresences) { + throw new MaxLengthError('Streaming decode error - repeated field "blockPresences" had too many elements') + } + + for (const evt of Message.BlockPresence.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}blockPresences`, { + limits: opts.limits?.blockPresences$ + })) { + yield { + ...evt, + index: obj.blockPresences + } + } + + obj.blockPresences++ + + break + } + case 5: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}pendingBytes`, + value: reader.int32() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface MessageWantlistWantlistFullFieldEvent { + field: 'full' + value: boolean + } + + export interface MessageBlocksFieldEvent { + field: 'blocks$entry' + index: number + value: Uint8Array + } + + export interface MessagePendingBytesFieldEvent { + field: 'pendingBytes' + value: number + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Message.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Message => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Message { return decodeMessage(buf, Message.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Message.codec(), opts) + } } diff --git a/packages/protons/test/fixtures/circuit.ts b/packages/protons/test/fixtures/circuit.ts index e5c5317..56d3b4e 100644 --- a/packages/protons/test/fixtures/circuit.ts +++ b/packages/protons/test/fixtures/circuit.ts @@ -1,4 +1,4 @@ -import { decodeMessage, encodeMessage, enumeration, MaxLengthError, message } from 'protons-runtime' +import { decodeMessage, encodeMessage, enumeration, MaxLengthError, message, streamMessage } from 'protons-runtime' import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' @@ -123,7 +123,7 @@ export namespace CircuitRelay { } case 2: { if (opts.limits?.addrs != null && obj.addrs.length === opts.limits.addrs) { - throw new MaxLengthError('Decode error - map field "addrs" had too many elements') + throw new MaxLengthError('Decode error - repeated field "addrs" had too many elements') } obj.addrs.push(reader.bytes()) @@ -137,19 +137,73 @@ export namespace CircuitRelay { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + addrs: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}id`, + value: reader.bytes() + } + break + } + case 2: { + if (opts.limits?.addrs != null && obj.addrs === opts.limits.addrs) { + throw new MaxLengthError('Streaming decode error - repeated field "addrs" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}addrs`, + index: obj.addrs, + value: reader.bytes() + } + + obj.addrs++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface PeerIdFieldEvent { + field: 'id' + value: Uint8Array + } + + export interface PeerAddrsFieldEvent { + field: 'addrs$entry' + index: number + value: Uint8Array + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Peer.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Peer => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Peer { return decodeMessage(buf, Peer.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Peer.codec(), opts) + } } let _codec: Codec @@ -221,17 +275,94 @@ export namespace CircuitRelay { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}type`, + value: CircuitRelay.Type.codec().decode(reader) + } + break + } + case 2: { + yield * CircuitRelay.Peer.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}srcPeer`, { + limits: opts.limits?.srcPeer + }) + + break + } + case 3: { + yield * CircuitRelay.Peer.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}dstPeer`, { + limits: opts.limits?.dstPeer + }) + + break + } + case 4: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}code`, + value: CircuitRelay.Status.codec().decode(reader) + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface CircuitRelayTypeFieldEvent { + field: 'type' + value: CircuitRelay.Type + } + + export interface CircuitRelaySrcPeerPeerIdFieldEvent { + field: 'id' + value: Uint8Array + } + + export interface CircuitRelaySrcPeerPeerAddrsFieldEvent { + field: 'addrs$entry' + index: number + value: Uint8Array + } + + export interface CircuitRelayDstPeerPeerIdFieldEvent { + field: 'id' + value: Uint8Array + } + + export interface CircuitRelayDstPeerPeerAddrsFieldEvent { + field: 'addrs$entry' + index: number + value: Uint8Array + } + + export interface CircuitRelayCodeFieldEvent { + field: 'code' + value: CircuitRelay.Status + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, CircuitRelay.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): CircuitRelay => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): CircuitRelay { return decodeMessage(buf, CircuitRelay.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, CircuitRelay.codec(), opts) + } } diff --git a/packages/protons/test/fixtures/custom-option-jstype.ts b/packages/protons/test/fixtures/custom-option-jstype.ts index 48806c7..f5ef167 100644 --- a/packages/protons/test/fixtures/custom-option-jstype.ts +++ b/packages/protons/test/fixtures/custom-option-jstype.ts @@ -1,4 +1,4 @@ -import { decodeMessage, encodeMessage, message } from 'protons-runtime' +import { decodeMessage, encodeMessage, message, streamMessage } from 'protons-runtime' import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' @@ -102,19 +102,108 @@ export namespace CustomOptionNumber { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}num`, + value: reader.int32() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}i64`, + value: reader.int64Number() + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}ui64`, + value: reader.uint64Number() + } + break + } + case 4: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}si64`, + value: reader.sint64Number() + } + break + } + case 5: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}f64`, + value: reader.fixed64Number() + } + break + } + case 6: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}sf64`, + value: reader.sfixed64Number() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface CustomOptionNumberNumFieldEvent { + field: 'num' + value: number + } + + export interface CustomOptionNumberI64FieldEvent { + field: 'i64' + value: bigint + } + + export interface CustomOptionNumberUi64FieldEvent { + field: 'ui64' + value: bigint + } + + export interface CustomOptionNumberSi64FieldEvent { + field: 'si64' + value: bigint + } + + export interface CustomOptionNumberF64FieldEvent { + field: 'f64' + value: bigint + } + + export interface CustomOptionNumberSf64FieldEvent { + field: 'sf64' + value: bigint + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, CustomOptionNumber.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): CustomOptionNumber => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): CustomOptionNumber { return decodeMessage(buf, CustomOptionNumber.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, CustomOptionNumber.codec(), opts) + } } export interface CustomOptionString { @@ -217,17 +306,106 @@ export namespace CustomOptionString { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}num`, + value: reader.int32() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}i64`, + value: reader.int64String() + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}ui64`, + value: reader.uint64String() + } + break + } + case 4: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}si64`, + value: reader.sint64String() + } + break + } + case 5: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}f64`, + value: reader.fixed64String() + } + break + } + case 6: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}sf64`, + value: reader.sfixed64String() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface CustomOptionStringNumFieldEvent { + field: 'num' + value: number + } + + export interface CustomOptionStringI64FieldEvent { + field: 'i64' + value: bigint + } + + export interface CustomOptionStringUi64FieldEvent { + field: 'ui64' + value: bigint + } + + export interface CustomOptionStringSi64FieldEvent { + field: 'si64' + value: bigint + } + + export interface CustomOptionStringF64FieldEvent { + field: 'f64' + value: bigint + } + + export interface CustomOptionStringSf64FieldEvent { + field: 'sf64' + value: bigint + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, CustomOptionString.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): CustomOptionString => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): CustomOptionString { return decodeMessage(buf, CustomOptionString.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, CustomOptionString.codec(), opts) + } } diff --git a/packages/protons/test/fixtures/daemon.ts b/packages/protons/test/fixtures/daemon.ts index 701a818..22087e9 100644 --- a/packages/protons/test/fixtures/daemon.ts +++ b/packages/protons/test/fixtures/daemon.ts @@ -1,6 +1,4 @@ -/* eslint-disable complexity */ - -import { decodeMessage, encodeMessage, enumeration, MaxLengthError, message } from 'protons-runtime' +import { decodeMessage, encodeMessage, enumeration, MaxLengthError, message, streamMessage } from 'protons-runtime' import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' @@ -178,19 +176,238 @@ export namespace Request { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}type`, + value: Request.Type.codec().decode(reader) + } + break + } + case 2: { + yield * ConnectRequest.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}connect`, { + limits: opts.limits?.connect + }) + + break + } + case 3: { + yield * StreamOpenRequest.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}streamOpen`, { + limits: opts.limits?.streamOpen + }) + + break + } + case 4: { + yield * StreamHandlerRequest.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}streamHandler`, { + limits: opts.limits?.streamHandler + }) + + break + } + case 5: { + yield * DHTRequest.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}dht`, { + limits: opts.limits?.dht + }) + + break + } + case 6: { + yield * ConnManagerRequest.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}connManager`, { + limits: opts.limits?.connManager + }) + + break + } + case 7: { + yield * DisconnectRequest.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}disconnect`, { + limits: opts.limits?.disconnect + }) + + break + } + case 8: { + yield * PSRequest.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}pubsub`, { + limits: opts.limits?.pubsub + }) + + break + } + case 9: { + yield * PeerstoreRequest.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}peerStore`, { + limits: opts.limits?.peerStore + }) + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface RequestTypeFieldEvent { + field: 'type' + value: Request.Type + } + + export interface RequestConnectConnectRequestPeerFieldEvent { + field: 'peer' + value: Uint8Array + } + + export interface RequestConnectConnectRequestAddrsFieldEvent { + field: 'addrs$entry' + index: number + value: Uint8Array + } + + export interface RequestConnectConnectRequestTimeoutFieldEvent { + field: 'timeout' + value: bigint + } + + export interface RequestStreamOpenStreamOpenRequestPeerFieldEvent { + field: 'peer' + value: Uint8Array + } + + export interface RequestStreamOpenStreamOpenRequestProtoFieldEvent { + field: 'proto$entry' + index: number + value: string + } + + export interface RequestStreamOpenStreamOpenRequestTimeoutFieldEvent { + field: 'timeout' + value: bigint + } + + export interface RequestStreamHandlerStreamHandlerRequestAddrFieldEvent { + field: 'addr' + value: Uint8Array + } + + export interface RequestStreamHandlerStreamHandlerRequestProtoFieldEvent { + field: 'proto$entry' + index: number + value: string + } + + export interface RequestDhtDHTRequestTypeFieldEvent { + field: 'type' + value: DHTRequest.Type + } + + export interface RequestDhtDHTRequestPeerFieldEvent { + field: 'peer' + value: Uint8Array + } + + export interface RequestDhtDHTRequestCidFieldEvent { + field: 'cid' + value: Uint8Array + } + + export interface RequestDhtDHTRequestKeyFieldEvent { + field: 'key' + value: Uint8Array + } + + export interface RequestDhtDHTRequestValueFieldEvent { + field: 'value' + value: Uint8Array + } + + export interface RequestDhtDHTRequestCountFieldEvent { + field: 'count' + value: number + } + + export interface RequestDhtDHTRequestTimeoutFieldEvent { + field: 'timeout' + value: bigint + } + + export interface RequestConnManagerConnManagerRequestTypeFieldEvent { + field: 'type' + value: ConnManagerRequest.Type + } + + export interface RequestConnManagerConnManagerRequestPeerFieldEvent { + field: 'peer' + value: Uint8Array + } + + export interface RequestConnManagerConnManagerRequestTagFieldEvent { + field: 'tag' + value: string + } + + export interface RequestConnManagerConnManagerRequestWeightFieldEvent { + field: 'weight' + value: bigint + } + + export interface RequestDisconnectDisconnectRequestPeerFieldEvent { + field: 'peer' + value: Uint8Array + } + + export interface RequestPubsubPSRequestTypeFieldEvent { + field: 'type' + value: PSRequest.Type + } + + export interface RequestPubsubPSRequestTopicFieldEvent { + field: 'topic' + value: string + } + + export interface RequestPubsubPSRequestDataFieldEvent { + field: 'data' + value: Uint8Array + } + + export interface RequestPeerStorePeerstoreRequestTypeFieldEvent { + field: 'type' + value: PeerstoreRequest.Type + } + + export interface RequestPeerStorePeerstoreRequestIdFieldEvent { + field: 'id' + value: Uint8Array + } + + export interface RequestPeerStorePeerstoreRequestProtosFieldEvent { + field: 'protos$entry' + index: number + value: string + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Request.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Request => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Request { return decodeMessage(buf, Request.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Request.codec(), opts) + } } export interface Response { @@ -317,7 +534,7 @@ export namespace Response { } case 6: { if (opts.limits?.peers != null && obj.peers.length === opts.limits.peers) { - throw new MaxLengthError('Decode error - map field "peers" had too many elements') + throw new MaxLengthError('Decode error - repeated field "peers" had too many elements') } obj.peers.push(PeerInfo.codec().decode(reader, reader.uint32(), { @@ -345,19 +562,193 @@ export namespace Response { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + peers: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}type`, + value: Response.Type.codec().decode(reader) + } + break + } + case 2: { + yield * ErrorResponse.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}error`, { + limits: opts.limits?.error + }) + + break + } + case 3: { + yield * StreamInfo.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}streamInfo`, { + limits: opts.limits?.streamInfo + }) + + break + } + case 4: { + yield * IdentifyResponse.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}identify`, { + limits: opts.limits?.identify + }) + + break + } + case 5: { + yield * DHTResponse.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}dht`, { + limits: opts.limits?.dht + }) + + break + } + case 6: { + if (opts.limits?.peers != null && obj.peers === opts.limits.peers) { + throw new MaxLengthError('Streaming decode error - repeated field "peers" had too many elements') + } + + for (const evt of PeerInfo.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}peers`, { + limits: opts.limits?.peers$ + })) { + yield { + ...evt, + index: obj.peers + } + } + + obj.peers++ + + break + } + case 7: { + yield * PSResponse.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}pubsub`, { + limits: opts.limits?.pubsub + }) + + break + } + case 8: { + yield * PeerstoreResponse.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}peerStore`, { + limits: opts.limits?.peerStore + }) + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface ResponseTypeFieldEvent { + field: 'type' + value: Response.Type + } + + export interface ResponseErrorErrorResponseMsgFieldEvent { + field: 'msg' + value: string + } + + export interface ResponseStreamInfoStreamInfoPeerFieldEvent { + field: 'peer' + value: Uint8Array + } + + export interface ResponseStreamInfoStreamInfoAddrFieldEvent { + field: 'addr' + value: Uint8Array + } + + export interface ResponseStreamInfoStreamInfoProtoFieldEvent { + field: 'proto' + value: string + } + + export interface ResponseIdentifyIdentifyResponseIdFieldEvent { + field: 'id' + value: Uint8Array + } + + export interface ResponseIdentifyIdentifyResponseAddrsFieldEvent { + field: 'addrs$entry' + index: number + value: Uint8Array + } + + export interface ResponseDhtDHTResponseTypeFieldEvent { + field: 'type' + value: DHTResponse.Type + } + + export interface ResponseDhtDHTResponsePeerPeerInfoIdFieldEvent { + field: 'id' + value: Uint8Array + } + + export interface ResponseDhtDHTResponsePeerPeerInfoAddrsFieldEvent { + field: 'addrs$entry' + index: number + value: Uint8Array + } + + export interface ResponseDhtDHTResponseValueFieldEvent { + field: 'value' + value: Uint8Array + } + + export interface ResponsePubsubPSResponseTopicsFieldEvent { + field: 'topics$entry' + index: number + value: string + } + + export interface ResponsePubsubPSResponsePeerIDsFieldEvent { + field: 'peerIDs$entry' + index: number + value: Uint8Array + } + + export interface ResponsePeerStorePeerstoreResponsePeerPeerInfoIdFieldEvent { + field: 'id' + value: Uint8Array + } + + export interface ResponsePeerStorePeerstoreResponsePeerPeerInfoAddrsFieldEvent { + field: 'addrs$entry' + index: number + value: Uint8Array + } + + export interface ResponsePeerStorePeerstoreResponseProtosFieldEvent { + field: 'protos$entry' + index: number + value: string + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Response.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Response => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Response { return decodeMessage(buf, Response.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Response.codec(), opts) + } } export interface IdentifyResponse { @@ -408,7 +799,7 @@ export namespace IdentifyResponse { } case 2: { if (opts.limits?.addrs != null && obj.addrs.length === opts.limits.addrs) { - throw new MaxLengthError('Decode error - map field "addrs" had too many elements') + throw new MaxLengthError('Decode error - repeated field "addrs" had too many elements') } obj.addrs.push(reader.bytes()) @@ -422,19 +813,73 @@ export namespace IdentifyResponse { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + addrs: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}id`, + value: reader.bytes() + } + break + } + case 2: { + if (opts.limits?.addrs != null && obj.addrs === opts.limits.addrs) { + throw new MaxLengthError('Streaming decode error - repeated field "addrs" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}addrs`, + index: obj.addrs, + value: reader.bytes() + } + + obj.addrs++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface IdentifyResponseIdFieldEvent { + field: 'id' + value: Uint8Array + } + + export interface IdentifyResponseAddrsFieldEvent { + field: 'addrs$entry' + index: number + value: Uint8Array + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, IdentifyResponse.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): IdentifyResponse => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): IdentifyResponse { return decodeMessage(buf, IdentifyResponse.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, IdentifyResponse.codec(), opts) + } } export interface ConnectRequest { @@ -491,7 +936,7 @@ export namespace ConnectRequest { } case 2: { if (opts.limits?.addrs != null && obj.addrs.length === opts.limits.addrs) { - throw new MaxLengthError('Decode error - map field "addrs" had too many elements') + throw new MaxLengthError('Decode error - repeated field "addrs" had too many elements') } obj.addrs.push(reader.bytes()) @@ -507,21 +952,87 @@ export namespace ConnectRequest { } } } - - return obj + + return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + addrs: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}peer`, + value: reader.bytes() + } + break + } + case 2: { + if (opts.limits?.addrs != null && obj.addrs === opts.limits.addrs) { + throw new MaxLengthError('Streaming decode error - repeated field "addrs" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}addrs`, + index: obj.addrs, + value: reader.bytes() + } + + obj.addrs++ + + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}timeout`, + value: reader.int64() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface ConnectRequestPeerFieldEvent { + field: 'peer' + value: Uint8Array + } + + export interface ConnectRequestAddrsFieldEvent { + field: 'addrs$entry' + index: number + value: Uint8Array + } + + export interface ConnectRequestTimeoutFieldEvent { + field: 'timeout' + value: bigint + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, ConnectRequest.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): ConnectRequest => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): ConnectRequest { return decodeMessage(buf, ConnectRequest.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, ConnectRequest.codec(), opts) + } } export interface StreamOpenRequest { @@ -578,7 +1089,7 @@ export namespace StreamOpenRequest { } case 2: { if (opts.limits?.proto != null && obj.proto.length === opts.limits.proto) { - throw new MaxLengthError('Decode error - map field "proto" had too many elements') + throw new MaxLengthError('Decode error - repeated field "proto" had too many elements') } obj.proto.push(reader.string()) @@ -596,19 +1107,85 @@ export namespace StreamOpenRequest { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + proto: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}peer`, + value: reader.bytes() + } + break + } + case 2: { + if (opts.limits?.proto != null && obj.proto === opts.limits.proto) { + throw new MaxLengthError('Streaming decode error - repeated field "proto" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}proto`, + index: obj.proto, + value: reader.string() + } + + obj.proto++ + + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}timeout`, + value: reader.int64() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface StreamOpenRequestPeerFieldEvent { + field: 'peer' + value: Uint8Array + } + + export interface StreamOpenRequestProtoFieldEvent { + field: 'proto$entry' + index: number + value: string + } + + export interface StreamOpenRequestTimeoutFieldEvent { + field: 'timeout' + value: bigint + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, StreamOpenRequest.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): StreamOpenRequest => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): StreamOpenRequest { return decodeMessage(buf, StreamOpenRequest.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, StreamOpenRequest.codec(), opts) + } } export interface StreamHandlerRequest { @@ -659,7 +1236,7 @@ export namespace StreamHandlerRequest { } case 2: { if (opts.limits?.proto != null && obj.proto.length === opts.limits.proto) { - throw new MaxLengthError('Decode error - map field "proto" had too many elements') + throw new MaxLengthError('Decode error - repeated field "proto" had too many elements') } obj.proto.push(reader.string()) @@ -673,19 +1250,73 @@ export namespace StreamHandlerRequest { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + proto: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}addr`, + value: reader.bytes() + } + break + } + case 2: { + if (opts.limits?.proto != null && obj.proto === opts.limits.proto) { + throw new MaxLengthError('Streaming decode error - repeated field "proto" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}proto`, + index: obj.proto, + value: reader.string() + } + + obj.proto++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface StreamHandlerRequestAddrFieldEvent { + field: 'addr' + value: Uint8Array + } + + export interface StreamHandlerRequestProtoFieldEvent { + field: 'proto$entry' + index: number + value: string + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, StreamHandlerRequest.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): StreamHandlerRequest => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): StreamHandlerRequest { return decodeMessage(buf, StreamHandlerRequest.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, StreamHandlerRequest.codec(), opts) + } } export interface ErrorResponse { @@ -733,19 +1364,48 @@ export namespace ErrorResponse { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}msg`, + value: reader.string() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface ErrorResponseMsgFieldEvent { + field: 'msg' + value: string + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, ErrorResponse.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): ErrorResponse => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): ErrorResponse { return decodeMessage(buf, ErrorResponse.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, ErrorResponse.codec(), opts) + } } export interface StreamInfo { @@ -815,19 +1475,72 @@ export namespace StreamInfo { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}peer`, + value: reader.bytes() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}addr`, + value: reader.bytes() + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}proto`, + value: reader.string() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface StreamInfoPeerFieldEvent { + field: 'peer' + value: Uint8Array + } + + export interface StreamInfoAddrFieldEvent { + field: 'addr' + value: Uint8Array + } + + export interface StreamInfoProtoFieldEvent { + field: 'proto' + value: string + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, StreamInfo.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): StreamInfo => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): StreamInfo { return decodeMessage(buf, StreamInfo.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, StreamInfo.codec(), opts) + } } export interface DHTRequest { @@ -965,19 +1678,120 @@ export namespace DHTRequest { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}type`, + value: DHTRequest.Type.codec().decode(reader) + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}peer`, + value: reader.bytes() + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}cid`, + value: reader.bytes() + } + break + } + case 4: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}key`, + value: reader.bytes() + } + break + } + case 5: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}value`, + value: reader.bytes() + } + break + } + case 6: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}count`, + value: reader.int32() + } + break + } + case 7: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}timeout`, + value: reader.int64() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface DHTRequestTypeFieldEvent { + field: 'type' + value: DHTRequest.Type + } + + export interface DHTRequestPeerFieldEvent { + field: 'peer' + value: Uint8Array + } + + export interface DHTRequestCidFieldEvent { + field: 'cid' + value: Uint8Array + } + + export interface DHTRequestKeyFieldEvent { + field: 'key' + value: Uint8Array + } + + export interface DHTRequestValueFieldEvent { + field: 'value' + value: Uint8Array + } + + export interface DHTRequestCountFieldEvent { + field: 'count' + value: number + } + + export interface DHTRequestTimeoutFieldEvent { + field: 'timeout' + value: bigint + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, DHTRequest.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): DHTRequest => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): DHTRequest { return decodeMessage(buf, DHTRequest.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, DHTRequest.codec(), opts) + } } export interface DHTResponse { @@ -1065,19 +1879,78 @@ export namespace DHTResponse { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}type`, + value: DHTResponse.Type.codec().decode(reader) + } + break + } + case 2: { + yield * PeerInfo.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}peer`, { + limits: opts.limits?.peer + }) + + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}value`, + value: reader.bytes() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface DHTResponseTypeFieldEvent { + field: 'type' + value: DHTResponse.Type + } + + export interface DHTResponsePeerPeerInfoIdFieldEvent { + field: 'id' + value: Uint8Array + } + + export interface DHTResponsePeerPeerInfoAddrsFieldEvent { + field: 'addrs$entry' + index: number + value: Uint8Array + } + + export interface DHTResponseValueFieldEvent { + field: 'value' + value: Uint8Array + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, DHTResponse.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): DHTResponse => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): DHTResponse { return decodeMessage(buf, DHTResponse.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, DHTResponse.codec(), opts) + } } export interface PeerInfo { @@ -1128,7 +2001,7 @@ export namespace PeerInfo { } case 2: { if (opts.limits?.addrs != null && obj.addrs.length === opts.limits.addrs) { - throw new MaxLengthError('Decode error - map field "addrs" had too many elements') + throw new MaxLengthError('Decode error - repeated field "addrs" had too many elements') } obj.addrs.push(reader.bytes()) @@ -1142,19 +2015,73 @@ export namespace PeerInfo { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + addrs: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}id`, + value: reader.bytes() + } + break + } + case 2: { + if (opts.limits?.addrs != null && obj.addrs === opts.limits.addrs) { + throw new MaxLengthError('Streaming decode error - repeated field "addrs" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}addrs`, + index: obj.addrs, + value: reader.bytes() + } + + obj.addrs++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface PeerInfoIdFieldEvent { + field: 'id' + value: Uint8Array + } + + export interface PeerInfoAddrsFieldEvent { + field: 'addrs$entry' + index: number + value: Uint8Array + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, PeerInfo.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): PeerInfo => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): PeerInfo { return decodeMessage(buf, PeerInfo.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, PeerInfo.codec(), opts) + } } export interface ConnManagerRequest { @@ -1250,19 +2177,84 @@ export namespace ConnManagerRequest { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}type`, + value: ConnManagerRequest.Type.codec().decode(reader) + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}peer`, + value: reader.bytes() + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}tag`, + value: reader.string() + } + break + } + case 4: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}weight`, + value: reader.int64() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface ConnManagerRequestTypeFieldEvent { + field: 'type' + value: ConnManagerRequest.Type + } + + export interface ConnManagerRequestPeerFieldEvent { + field: 'peer' + value: Uint8Array + } + + export interface ConnManagerRequestTagFieldEvent { + field: 'tag' + value: string + } + + export interface ConnManagerRequestWeightFieldEvent { + field: 'weight' + value: bigint + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, ConnManagerRequest.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): ConnManagerRequest => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): ConnManagerRequest { return decodeMessage(buf, ConnManagerRequest.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, ConnManagerRequest.codec(), opts) + } } export interface DisconnectRequest { @@ -1310,19 +2302,48 @@ export namespace DisconnectRequest { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}peer`, + value: reader.bytes() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface DisconnectRequestPeerFieldEvent { + field: 'peer' + value: Uint8Array + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, DisconnectRequest.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): DisconnectRequest => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): DisconnectRequest { return decodeMessage(buf, DisconnectRequest.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, DisconnectRequest.codec(), opts) + } } export interface PSRequest { @@ -1410,19 +2431,72 @@ export namespace PSRequest { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}type`, + value: PSRequest.Type.codec().decode(reader) + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}topic`, + value: reader.string() + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}data`, + value: reader.bytes() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface PSRequestTypeFieldEvent { + field: 'type' + value: PSRequest.Type + } + + export interface PSRequestTopicFieldEvent { + field: 'topic' + value: string + } + + export interface PSRequestDataFieldEvent { + field: 'data' + value: Uint8Array + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, PSRequest.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): PSRequest => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): PSRequest { return decodeMessage(buf, PSRequest.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, PSRequest.codec(), opts) + } } export interface PSMessage { @@ -1504,7 +2578,7 @@ export namespace PSMessage { } case 4: { if (opts.limits?.topicIDs != null && obj.topicIDs.length === opts.limits.topicIDs) { - throw new MaxLengthError('Decode error - map field "topicIDs" had too many elements') + throw new MaxLengthError('Decode error - repeated field "topicIDs" had too many elements') } obj.topicIDs.push(reader.string()) @@ -1526,19 +2600,121 @@ export namespace PSMessage { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + topicIDs: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}from`, + value: reader.bytes() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}data`, + value: reader.bytes() + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}seqno`, + value: reader.bytes() + } + break + } + case 4: { + if (opts.limits?.topicIDs != null && obj.topicIDs === opts.limits.topicIDs) { + throw new MaxLengthError('Streaming decode error - repeated field "topicIDs" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}topicIDs`, + index: obj.topicIDs, + value: reader.string() + } + + obj.topicIDs++ + + break + } + case 5: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}signature`, + value: reader.bytes() + } + break + } + case 6: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}key`, + value: reader.bytes() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface PSMessageFromFieldEvent { + field: 'from' + value: Uint8Array + } + + export interface PSMessageDataFieldEvent { + field: 'data' + value: Uint8Array + } + + export interface PSMessageSeqnoFieldEvent { + field: 'seqno' + value: Uint8Array + } + + export interface PSMessageTopicIDsFieldEvent { + field: 'topicIDs$entry' + index: number + value: string + } + + export interface PSMessageSignatureFieldEvent { + field: 'signature' + value: Uint8Array + } + + export interface PSMessageKeyFieldEvent { + field: 'key' + value: Uint8Array + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, PSMessage.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): PSMessage => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): PSMessage { return decodeMessage(buf, PSMessage.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, PSMessage.codec(), opts) + } } export interface PSResponse { @@ -1587,7 +2763,7 @@ export namespace PSResponse { switch (tag >>> 3) { case 1: { if (opts.limits?.topics != null && obj.topics.length === opts.limits.topics) { - throw new MaxLengthError('Decode error - map field "topics" had too many elements') + throw new MaxLengthError('Decode error - repeated field "topics" had too many elements') } obj.topics.push(reader.string()) @@ -1595,7 +2771,7 @@ export namespace PSResponse { } case 2: { if (opts.limits?.peerIDs != null && obj.peerIDs.length === opts.limits.peerIDs) { - throw new MaxLengthError('Decode error - map field "peerIDs" had too many elements') + throw new MaxLengthError('Decode error - repeated field "peerIDs" had too many elements') } obj.peerIDs.push(reader.bytes()) @@ -1609,19 +2785,83 @@ export namespace PSResponse { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + topics: 0, + peerIDs: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + if (opts.limits?.topics != null && obj.topics === opts.limits.topics) { + throw new MaxLengthError('Streaming decode error - repeated field "topics" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}topics`, + index: obj.topics, + value: reader.string() + } + + obj.topics++ + + break + } + case 2: { + if (opts.limits?.peerIDs != null && obj.peerIDs === opts.limits.peerIDs) { + throw new MaxLengthError('Streaming decode error - repeated field "peerIDs" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}peerIDs`, + index: obj.peerIDs, + value: reader.bytes() + } + + obj.peerIDs++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface PSResponseTopicsFieldEvent { + field: 'topics$entry' + index: number + value: string + } + + export interface PSResponsePeerIDsFieldEvent { + field: 'peerIDs$entry' + index: number + value: Uint8Array + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, PSResponse.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): PSResponse => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): PSResponse { return decodeMessage(buf, PSResponse.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, PSResponse.codec(), opts) + } } export interface PeerstoreRequest { @@ -1700,7 +2940,7 @@ export namespace PeerstoreRequest { } case 3: { if (opts.limits?.protos != null && obj.protos.length === opts.limits.protos) { - throw new MaxLengthError('Decode error - map field "protos" had too many elements') + throw new MaxLengthError('Decode error - repeated field "protos" had too many elements') } obj.protos.push(reader.string()) @@ -1714,19 +2954,85 @@ export namespace PeerstoreRequest { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + protos: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}type`, + value: PeerstoreRequest.Type.codec().decode(reader) + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}id`, + value: reader.bytes() + } + break + } + case 3: { + if (opts.limits?.protos != null && obj.protos === opts.limits.protos) { + throw new MaxLengthError('Streaming decode error - repeated field "protos" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}protos`, + index: obj.protos, + value: reader.string() + } + + obj.protos++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface PeerstoreRequestTypeFieldEvent { + field: 'type' + value: PeerstoreRequest.Type + } + + export interface PeerstoreRequestIdFieldEvent { + field: 'id' + value: Uint8Array + } + + export interface PeerstoreRequestProtosFieldEvent { + field: 'protos$entry' + index: number + value: string + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, PeerstoreRequest.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): PeerstoreRequest => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): PeerstoreRequest { return decodeMessage(buf, PeerstoreRequest.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, PeerstoreRequest.codec(), opts) + } } export interface PeerstoreResponse { @@ -1778,7 +3084,7 @@ export namespace PeerstoreResponse { } case 2: { if (opts.limits?.protos != null && obj.protos.length === opts.limits.protos) { - throw new MaxLengthError('Decode error - map field "protos" had too many elements') + throw new MaxLengthError('Decode error - repeated field "protos" had too many elements') } obj.protos.push(reader.string()) @@ -1792,17 +3098,77 @@ export namespace PeerstoreResponse { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + protos: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield * PeerInfo.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}peer`, { + limits: opts.limits?.peer + }) + + break + } + case 2: { + if (opts.limits?.protos != null && obj.protos === opts.limits.protos) { + throw new MaxLengthError('Streaming decode error - repeated field "protos" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}protos`, + index: obj.protos, + value: reader.string() + } + + obj.protos++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface PeerstoreResponsePeerPeerInfoIdFieldEvent { + field: 'id' + value: Uint8Array + } + + export interface PeerstoreResponsePeerPeerInfoAddrsFieldEvent { + field: 'addrs$entry' + index: number + value: Uint8Array + } + + export interface PeerstoreResponseProtosFieldEvent { + field: 'protos$entry' + index: number + value: string + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, PeerstoreResponse.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): PeerstoreResponse => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): PeerstoreResponse { return decodeMessage(buf, PeerstoreResponse.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, PeerstoreResponse.codec(), opts) + } } diff --git a/packages/protons/test/fixtures/dht.ts b/packages/protons/test/fixtures/dht.ts index 3298357..2799413 100644 --- a/packages/protons/test/fixtures/dht.ts +++ b/packages/protons/test/fixtures/dht.ts @@ -1,4 +1,4 @@ -import { decodeMessage, encodeMessage, enumeration, MaxLengthError, message } from 'protons-runtime' +import { decodeMessage, encodeMessage, enumeration, MaxLengthError, message, streamMessage } from 'protons-runtime' import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' @@ -85,19 +85,96 @@ export namespace Record { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}key`, + value: reader.bytes() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}value`, + value: reader.bytes() + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}author`, + value: reader.bytes() + } + break + } + case 4: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}signature`, + value: reader.bytes() + } + break + } + case 5: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}timeReceived`, + value: reader.string() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface RecordKeyFieldEvent { + field: 'key' + value: Uint8Array + } + + export interface RecordValueFieldEvent { + field: 'value' + value: Uint8Array + } + + export interface RecordAuthorFieldEvent { + field: 'author' + value: Uint8Array + } + + export interface RecordSignatureFieldEvent { + field: 'signature' + value: Uint8Array + } + + export interface RecordTimeReceivedFieldEvent { + field: 'timeReceived' + value: string + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Record.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Record => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Record { return decodeMessage(buf, Record.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Record.codec(), opts) + } } export interface Message { @@ -207,7 +284,7 @@ export namespace Message { } case 2: { if (opts.limits?.addrs != null && obj.addrs.length === opts.limits.addrs) { - throw new MaxLengthError('Decode error - map field "addrs" had too many elements') + throw new MaxLengthError('Decode error - repeated field "addrs" had too many elements') } obj.addrs.push(reader.bytes()) @@ -225,19 +302,85 @@ export namespace Message { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + addrs: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}id`, + value: reader.bytes() + } + break + } + case 2: { + if (opts.limits?.addrs != null && obj.addrs === opts.limits.addrs) { + throw new MaxLengthError('Streaming decode error - repeated field "addrs" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}addrs`, + index: obj.addrs, + value: reader.bytes() + } + + obj.addrs++ + + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}connection`, + value: Message.ConnectionType.codec().decode(reader) + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface PeerIdFieldEvent { + field: 'id' + value: Uint8Array + } + + export interface PeerAddrsFieldEvent { + field: 'addrs$entry' + index: number + value: Uint8Array + } + + export interface PeerConnectionFieldEvent { + field: 'connection' + value: Message.ConnectionType + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Peer.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Peer => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Peer { return decodeMessage(buf, Peer.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Peer.codec(), opts) + } } let _codec: Codec @@ -316,7 +459,7 @@ export namespace Message { } case 8: { if (opts.limits?.closerPeers != null && obj.closerPeers.length === opts.limits.closerPeers) { - throw new MaxLengthError('Decode error - map field "closerPeers" had too many elements') + throw new MaxLengthError('Decode error - repeated field "closerPeers" had too many elements') } obj.closerPeers.push(Message.Peer.codec().decode(reader, reader.uint32(), { @@ -326,7 +469,7 @@ export namespace Message { } case 9: { if (opts.limits?.providerPeers != null && obj.providerPeers.length === opts.limits.providerPeers) { - throw new MaxLengthError('Decode error - map field "providerPeers" had too many elements') + throw new MaxLengthError('Decode error - repeated field "providerPeers" had too many elements') } obj.providerPeers.push(Message.Peer.codec().decode(reader, reader.uint32(), { @@ -342,17 +485,123 @@ export namespace Message { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + closerPeers: 0, + providerPeers: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}type`, + value: Message.MessageType.codec().decode(reader) + } + break + } + case 10: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}clusterLevelRaw`, + value: reader.int32() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}key`, + value: reader.bytes() + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}record`, + value: reader.bytes() + } + break + } + case 8: { + if (opts.limits?.closerPeers != null && obj.closerPeers === opts.limits.closerPeers) { + throw new MaxLengthError('Streaming decode error - repeated field "closerPeers" had too many elements') + } + + for (const evt of Message.Peer.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}closerPeers`, { + limits: opts.limits?.closerPeers$ + })) { + yield { + ...evt, + index: obj.closerPeers + } + } + + obj.closerPeers++ + + break + } + case 9: { + if (opts.limits?.providerPeers != null && obj.providerPeers === opts.limits.providerPeers) { + throw new MaxLengthError('Streaming decode error - repeated field "providerPeers" had too many elements') + } + + for (const evt of Message.Peer.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}providerPeers`, { + limits: opts.limits?.providerPeers$ + })) { + yield { + ...evt, + index: obj.providerPeers + } + } + + obj.providerPeers++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface MessageTypeFieldEvent { + field: 'type' + value: Message.MessageType + } + + export interface MessageClusterLevelRawFieldEvent { + field: 'clusterLevelRaw' + value: number + } + + export interface MessageKeyFieldEvent { + field: 'key' + value: Uint8Array + } + + export interface MessageRecordFieldEvent { + field: 'record' + value: Uint8Array + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Message.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Message => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Message { return decodeMessage(buf, Message.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Message.codec(), opts) + } } diff --git a/packages/protons/test/fixtures/maps.ts b/packages/protons/test/fixtures/maps.ts index 74f6f60..692e889 100644 --- a/packages/protons/test/fixtures/maps.ts +++ b/packages/protons/test/fixtures/maps.ts @@ -1,6 +1,4 @@ -/* eslint-disable complexity */ - -import { decodeMessage, encodeMessage, enumeration, MaxLengthError, MaxSizeError, message } from 'protons-runtime' +import { decodeMessage, encodeMessage, enumeration, MaxLengthError, MaxSizeError, message, streamMessage } from 'protons-runtime' import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' @@ -70,7 +68,7 @@ export namespace SubMessage { } case 2: { if (opts.limits?.bar != null && obj.bar.length === opts.limits.bar) { - throw new MaxLengthError('Decode error - map field "bar" had too many elements') + throw new MaxLengthError('Decode error - repeated field "bar" had too many elements') } obj.bar.push(reader.uint32()) @@ -84,19 +82,73 @@ export namespace SubMessage { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + bar: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}foo`, + value: reader.string() + } + break + } + case 2: { + if (opts.limits?.bar != null && obj.bar === opts.limits.bar) { + throw new MaxLengthError('Streaming decode error - repeated field "bar" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}bar`, + index: obj.bar, + value: reader.uint32() + } + + obj.bar++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface SubMessageFooFieldEvent { + field: 'foo' + value: string + } + + export interface SubMessageBarFieldEvent { + field: 'bar$entry' + index: number + value: number + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, SubMessage.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): SubMessage => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): SubMessage { return decodeMessage(buf, SubMessage.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, SubMessage.codec(), opts) + } } export interface MapTypes { @@ -164,19 +216,60 @@ export namespace MapTypes { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}key`, + value: reader.string() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}value`, + value: reader.string() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface MapTypes$stringMapEntryKeyFieldEvent { + field: 'key' + value: string + } + + export interface MapTypes$stringMapEntryValueFieldEvent { + field: 'value' + value: string + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, MapTypes$stringMapEntry.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MapTypes$stringMapEntry => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MapTypes$stringMapEntry { return decodeMessage(buf, MapTypes$stringMapEntry.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MapTypes$stringMapEntry.codec(), opts) + } } export interface MapTypes$intMapEntry { @@ -235,19 +328,60 @@ export namespace MapTypes { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}key`, + value: reader.int32() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}value`, + value: reader.int32() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface MapTypes$intMapEntryKeyFieldEvent { + field: 'key' + value: number + } + + export interface MapTypes$intMapEntryValueFieldEvent { + field: 'value' + value: number + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, MapTypes$intMapEntry.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MapTypes$intMapEntry => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MapTypes$intMapEntry { return decodeMessage(buf, MapTypes$intMapEntry.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MapTypes$intMapEntry.codec(), opts) + } } export interface MapTypes$boolMapEntry { @@ -306,19 +440,60 @@ export namespace MapTypes { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}key`, + value: reader.bool() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}value`, + value: reader.bool() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface MapTypes$boolMapEntryKeyFieldEvent { + field: 'key' + value: boolean + } + + export interface MapTypes$boolMapEntryValueFieldEvent { + field: 'value' + value: boolean + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, MapTypes$boolMapEntry.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MapTypes$boolMapEntry => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MapTypes$boolMapEntry { return decodeMessage(buf, MapTypes$boolMapEntry.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MapTypes$boolMapEntry.codec(), opts) + } } export interface MapTypes$messageMapEntry { @@ -378,19 +553,66 @@ export namespace MapTypes { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}key`, + value: reader.string() + } + break + } + case 2: { + yield * SubMessage.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}value`, { + limits: opts.limits?.value + }) + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface MapTypes$messageMapEntryKeyFieldEvent { + field: 'key' + value: string + } + + export interface MapTypes$messageMapEntryValueSubMessageFooFieldEvent { + field: 'foo' + value: string + } + + export interface MapTypes$messageMapEntryValueSubMessageBarFieldEvent { + field: 'bar$entry' + index: number + value: number + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, MapTypes$messageMapEntry.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MapTypes$messageMapEntry => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MapTypes$messageMapEntry { return decodeMessage(buf, MapTypes$messageMapEntry.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MapTypes$messageMapEntry.codec(), opts) + } } export interface MapTypes$enumMapEntry { @@ -449,19 +671,60 @@ export namespace MapTypes { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}key`, + value: reader.string() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}value`, + value: EnumValue.codec().decode(reader) + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface MapTypes$enumMapEntryKeyFieldEvent { + field: 'key' + value: string + } + + export interface MapTypes$enumMapEntryValueFieldEvent { + field: 'value' + value: EnumValue + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, MapTypes$enumMapEntry.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MapTypes$enumMapEntry => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MapTypes$enumMapEntry { return decodeMessage(buf, MapTypes$enumMapEntry.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MapTypes$enumMapEntry.codec(), opts) + } } let _codec: Codec @@ -473,35 +736,35 @@ export namespace MapTypes { w.fork() } - if (obj.stringMap != null && obj.stringMap.size !== 0) { + if (obj.stringMap != null) { for (const [key, value] of obj.stringMap.entries()) { w.uint32(10) MapTypes.MapTypes$stringMapEntry.codec().encode({ key, value }, w) } } - if (obj.intMap != null && obj.intMap.size !== 0) { + if (obj.intMap != null) { for (const [key, value] of obj.intMap.entries()) { w.uint32(18) MapTypes.MapTypes$intMapEntry.codec().encode({ key, value }, w) } } - if (obj.boolMap != null && obj.boolMap.size !== 0) { + if (obj.boolMap != null) { for (const [key, value] of obj.boolMap.entries()) { w.uint32(26) MapTypes.MapTypes$boolMapEntry.codec().encode({ key, value }, w) } } - if (obj.messageMap != null && obj.messageMap.size !== 0) { + if (obj.messageMap != null) { for (const [key, value] of obj.messageMap.entries()) { w.uint32(34) MapTypes.MapTypes$messageMapEntry.codec().encode({ key, value }, w) } } - if (obj.enumMap != null && obj.enumMap.size !== 0) { + if (obj.enumMap != null) { for (const [key, value] of obj.enumMap.entries()) { w.uint32(42) MapTypes.MapTypes$enumMapEntry.codec().encode({ key, value }, w) @@ -516,8 +779,8 @@ export namespace MapTypes { stringMap: new Map(), intMap: new Map(), boolMap: new Map(), - messageMap: new Map(), - enumMap: new Map() + messageMap: new Map(), + enumMap: new Map() } const end = length == null ? reader.len : reader.pos + length @@ -531,7 +794,11 @@ export namespace MapTypes { throw new MaxSizeError('Decode error - map field "stringMap" had too many elements') } - const entry = MapTypes.MapTypes$stringMapEntry.codec().decode(reader, reader.uint32()) + const entry = MapTypes.MapTypes$stringMapEntry.codec().decode(reader, reader.uint32(), { + limits: { + value: opts.limits?.stringMap$value + } + }) obj.stringMap.set(entry.key, entry.value) break } @@ -540,7 +807,11 @@ export namespace MapTypes { throw new MaxSizeError('Decode error - map field "intMap" had too many elements') } - const entry = MapTypes.MapTypes$intMapEntry.codec().decode(reader, reader.uint32()) + const entry = MapTypes.MapTypes$intMapEntry.codec().decode(reader, reader.uint32(), { + limits: { + value: opts.limits?.intMap$value + } + }) obj.intMap.set(entry.key, entry.value) break } @@ -549,7 +820,11 @@ export namespace MapTypes { throw new MaxSizeError('Decode error - map field "boolMap" had too many elements') } - const entry = MapTypes.MapTypes$boolMapEntry.codec().decode(reader, reader.uint32()) + const entry = MapTypes.MapTypes$boolMapEntry.codec().decode(reader, reader.uint32(), { + limits: { + value: opts.limits?.boolMap$value + } + }) obj.boolMap.set(entry.key, entry.value) break } @@ -571,7 +846,11 @@ export namespace MapTypes { throw new MaxSizeError('Decode error - map field "enumMap" had too many elements') } - const entry = MapTypes.MapTypes$enumMapEntry.codec().decode(reader, reader.uint32()) + const entry = MapTypes.MapTypes$enumMapEntry.codec().decode(reader, reader.uint32(), { + limits: { + value: opts.limits?.enumMap$value + } + }) obj.enumMap.set(entry.key, entry.value) break } @@ -583,17 +862,135 @@ export namespace MapTypes { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + stringMap: 0, + intMap: 0, + boolMap: 0, + messageMap: 0, + enumMap: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + if (opts.limits?.stringMap != null && obj.stringMap === opts.limits.stringMap) { + throw new MaxLengthError('Decode error - map field "stringMap" had too many elements') + } + + yield * MapTypes.MapTypes$stringMapEntry.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}stringMap`, { + limits: { + value: opts.limits?.stringMap$value + } + }) + + obj.stringMap++ + + break + } + case 2: { + if (opts.limits?.intMap != null && obj.intMap === opts.limits.intMap) { + throw new MaxLengthError('Decode error - map field "intMap" had too many elements') + } + + yield * MapTypes.MapTypes$intMapEntry.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}intMap`, { + limits: { + value: opts.limits?.intMap$value + } + }) + + obj.intMap++ + + break + } + case 3: { + if (opts.limits?.boolMap != null && obj.boolMap === opts.limits.boolMap) { + throw new MaxLengthError('Decode error - map field "boolMap" had too many elements') + } + + yield * MapTypes.MapTypes$boolMapEntry.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}boolMap`, { + limits: { + value: opts.limits?.boolMap$value + } + }) + + obj.boolMap++ + + break + } + case 4: { + if (opts.limits?.messageMap != null && obj.messageMap === opts.limits.messageMap) { + throw new MaxLengthError('Decode error - map field "messageMap" had too many elements') + } + + yield * MapTypes.MapTypes$messageMapEntry.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}messageMap`, { + limits: { + value: opts.limits?.messageMap$value + } + }) + + obj.messageMap++ + + break + } + case 5: { + if (opts.limits?.enumMap != null && obj.enumMap === opts.limits.enumMap) { + throw new MaxLengthError('Decode error - map field "enumMap" had too many elements') + } + + yield * MapTypes.MapTypes$enumMapEntry.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}enumMap`, { + limits: { + value: opts.limits?.enumMap$value + } + }) + + obj.enumMap++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface MapTypesStringMapFieldEvent { + field: 'stringMap$entry' + key: string + value: string + } + + export interface MapTypesIntMapFieldEvent { + field: 'intMap$entry' + key: number + value: number + } + + export interface MapTypesBoolMapFieldEvent { + field: 'boolMap$entry' + key: boolean + value: boolean + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, MapTypes.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MapTypes => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MapTypes { return decodeMessage(buf, MapTypes.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MapTypes.codec(), opts) + } } diff --git a/packages/protons/test/fixtures/noise.ts b/packages/protons/test/fixtures/noise.ts index 73e4545..aab5e56 100644 --- a/packages/protons/test/fixtures/noise.ts +++ b/packages/protons/test/fixtures/noise.ts @@ -1,4 +1,6 @@ -import { decodeMessage, encodeMessage, message } from 'protons-runtime' +/* eslint-disable require-yield */ + +import { decodeMessage, encodeMessage, message, streamMessage } from 'protons-runtime' import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' @@ -73,19 +75,72 @@ export namespace pb { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}identityKey`, + value: reader.bytes() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}identitySig`, + value: reader.bytes() + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}data`, + value: reader.bytes() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface NoiseHandshakePayloadIdentityKeyFieldEvent { + field: 'identityKey' + value: Uint8Array + } + + export interface NoiseHandshakePayloadIdentitySigFieldEvent { + field: 'identitySig' + value: Uint8Array + } + + export interface NoiseHandshakePayloadDataFieldEvent { + field: 'data' + value: Uint8Array + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, NoiseHandshakePayload.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): NoiseHandshakePayload => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): NoiseHandshakePayload { return decodeMessage(buf, NoiseHandshakePayload.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, NoiseHandshakePayload.codec(), opts) + } } let _codec: Codec @@ -117,17 +172,34 @@ export namespace pb { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, pb.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): pb => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): pb { return decodeMessage(buf, pb.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator<{}> { + return streamMessage(buf, pb.codec(), opts) + } } diff --git a/packages/protons/test/fixtures/oneof.ts b/packages/protons/test/fixtures/oneof.ts index 71e2ef6..5a69e3b 100644 --- a/packages/protons/test/fixtures/oneof.ts +++ b/packages/protons/test/fixtures/oneof.ts @@ -1,4 +1,4 @@ -import { decodeMessage, encodeMessage, enumeration, message } from 'protons-runtime' +import { decodeMessage, encodeMessage, enumeration, message, streamMessage } from 'protons-runtime' import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' @@ -137,19 +137,96 @@ export namespace OneOfMessage { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}fieldOne`, + value: reader.string() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}fieldTwo`, + value: reader.string() + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}fieldThree`, + value: EnumType.codec().decode(reader) + } + break + } + case 4: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}fieldFour`, + value: EnumType.codec().decode(reader) + } + break + } + case 5: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}fieldFive`, + value: reader.string() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface OneOfMessageFieldOneFieldEvent { + field: 'fieldOne' + value: string + } + + export interface OneOfMessageFieldTwoFieldEvent { + field: 'fieldTwo' + value: string + } + + export interface OneOfMessageFieldThreeFieldEvent { + field: 'fieldThree' + value: EnumType + } + + export interface OneOfMessageFieldFourFieldEvent { + field: 'fieldFour' + value: EnumType + } + + export interface OneOfMessageFieldFiveFieldEvent { + field: 'fieldFive' + value: string + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, OneOfMessage.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): OneOfMessage => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): OneOfMessage { return decodeMessage(buf, OneOfMessage.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, OneOfMessage.codec(), opts) + } } export interface MessageWithoutOneOfs { @@ -241,17 +318,94 @@ export namespace MessageWithoutOneOfs { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}fieldOne`, + value: reader.string() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}fieldTwo`, + value: reader.string() + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}fieldThree`, + value: EnumType.codec().decode(reader) + } + break + } + case 4: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}fieldFour`, + value: EnumType.codec().decode(reader) + } + break + } + case 5: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}fieldFive`, + value: reader.string() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface MessageWithoutOneOfsFieldOneFieldEvent { + field: 'fieldOne' + value: string + } + + export interface MessageWithoutOneOfsFieldTwoFieldEvent { + field: 'fieldTwo' + value: string + } + + export interface MessageWithoutOneOfsFieldThreeFieldEvent { + field: 'fieldThree' + value: EnumType + } + + export interface MessageWithoutOneOfsFieldFourFieldEvent { + field: 'fieldFour' + value: EnumType + } + + export interface MessageWithoutOneOfsFieldFiveFieldEvent { + field: 'fieldFive' + value: string + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, MessageWithoutOneOfs.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithoutOneOfs => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithoutOneOfs { return decodeMessage(buf, MessageWithoutOneOfs.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MessageWithoutOneOfs.codec(), opts) + } } diff --git a/packages/protons/test/fixtures/optional.ts b/packages/protons/test/fixtures/optional.ts index ff7a99e..d00b800 100644 --- a/packages/protons/test/fixtures/optional.ts +++ b/packages/protons/test/fixtures/optional.ts @@ -1,6 +1,4 @@ -/* eslint-disable complexity */ - -import { decodeMessage, encodeMessage, enumeration, message } from 'protons-runtime' +import { decodeMessage, encodeMessage, enumeration, message, streamMessage } from 'protons-runtime' import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' @@ -75,19 +73,60 @@ export namespace OptionalSubMessage { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}foo`, + value: reader.string() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}bar`, + value: reader.int32() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface OptionalSubMessageFooFieldEvent { + field: 'foo' + value: string + } + + export interface OptionalSubMessageBarFieldEvent { + field: 'bar' + value: number + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, OptionalSubMessage.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): OptionalSubMessage => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): OptionalSubMessage { return decodeMessage(buf, OptionalSubMessage.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, OptionalSubMessage.codec(), opts) + } } export interface Optional { @@ -295,17 +334,243 @@ export namespace Optional { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}double`, + value: reader.double() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}float`, + value: reader.float() + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}int32`, + value: reader.int32() + } + break + } + case 4: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}int64`, + value: reader.int64() + } + break + } + case 5: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}uint32`, + value: reader.uint32() + } + break + } + case 6: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}uint64`, + value: reader.uint64() + } + break + } + case 7: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}sint32`, + value: reader.sint32() + } + break + } + case 8: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}sint64`, + value: reader.sint64() + } + break + } + case 9: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}fixed32`, + value: reader.fixed32() + } + break + } + case 10: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}fixed64`, + value: reader.fixed64() + } + break + } + case 11: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}sfixed32`, + value: reader.sfixed32() + } + break + } + case 12: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}sfixed64`, + value: reader.sfixed64() + } + break + } + case 13: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}bool`, + value: reader.bool() + } + break + } + case 14: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}string`, + value: reader.string() + } + break + } + case 15: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}bytes`, + value: reader.bytes() + } + break + } + case 16: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}enum`, + value: OptionalEnum.codec().decode(reader) + } + break + } + case 17: { + yield * OptionalSubMessage.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}subMessage`, { + limits: opts.limits?.subMessage + }) + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface OptionalDoubleFieldEvent { + field: 'double' + value: number + } + + export interface OptionalFloatFieldEvent { + field: 'float' + value: number + } + + export interface OptionalInt32FieldEvent { + field: 'int32' + value: number + } + + export interface OptionalInt64FieldEvent { + field: 'int64' + value: bigint + } + + export interface OptionalUint32FieldEvent { + field: 'uint32' + value: number + } + + export interface OptionalUint64FieldEvent { + field: 'uint64' + value: bigint + } + + export interface OptionalSint32FieldEvent { + field: 'sint32' + value: number + } + + export interface OptionalSint64FieldEvent { + field: 'sint64' + value: bigint + } + + export interface OptionalFixed32FieldEvent { + field: 'fixed32' + value: number + } + + export interface OptionalFixed64FieldEvent { + field: 'fixed64' + value: bigint + } + + export interface OptionalSfixed32FieldEvent { + field: 'sfixed32' + value: number + } + + export interface OptionalSfixed64FieldEvent { + field: 'sfixed64' + value: bigint + } + + export interface OptionalBoolFieldEvent { + field: 'bool' + value: boolean + } + + export interface OptionalStringFieldEvent { + field: 'string' + value: string + } + + export interface OptionalBytesFieldEvent { + field: 'bytes' + value: Uint8Array + } + + export interface OptionalEnumFieldEvent { + field: 'enum' + value: OptionalEnum + } + + export interface OptionalSubMessageOptionalSubMessageFooFieldEvent { + field: 'foo' + value: string + } + + export interface OptionalSubMessageOptionalSubMessageBarFieldEvent { + field: 'bar' + value: number + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Optional.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Optional => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Optional { return decodeMessage(buf, Optional.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Optional.codec(), opts) + } } diff --git a/packages/protons/test/fixtures/peer.ts b/packages/protons/test/fixtures/peer.ts index 69c2716..271e5e5 100644 --- a/packages/protons/test/fixtures/peer.ts +++ b/packages/protons/test/fixtures/peer.ts @@ -1,4 +1,4 @@ -import { decodeMessage, encodeMessage, MaxLengthError, message } from 'protons-runtime' +import { decodeMessage, encodeMessage, MaxLengthError, message, streamMessage } from 'protons-runtime' import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' @@ -70,7 +70,7 @@ export namespace Peer { switch (tag >>> 3) { case 1: { if (opts.limits?.addresses != null && obj.addresses.length === opts.limits.addresses) { - throw new MaxLengthError('Decode error - map field "addresses" had too many elements') + throw new MaxLengthError('Decode error - repeated field "addresses" had too many elements') } obj.addresses.push(Address.codec().decode(reader, reader.uint32(), { @@ -80,7 +80,7 @@ export namespace Peer { } case 2: { if (opts.limits?.protocols != null && obj.protocols.length === opts.limits.protocols) { - throw new MaxLengthError('Decode error - map field "protocols" had too many elements') + throw new MaxLengthError('Decode error - repeated field "protocols" had too many elements') } obj.protocols.push(reader.string()) @@ -88,7 +88,7 @@ export namespace Peer { } case 3: { if (opts.limits?.metadata != null && obj.metadata.length === opts.limits.metadata) { - throw new MaxLengthError('Decode error - map field "metadata" had too many elements') + throw new MaxLengthError('Decode error - repeated field "metadata" had too many elements') } obj.metadata.push(Metadata.codec().decode(reader, reader.uint32(), { @@ -112,19 +112,123 @@ export namespace Peer { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + addresses: 0, + protocols: 0, + metadata: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + if (opts.limits?.addresses != null && obj.addresses === opts.limits.addresses) { + throw new MaxLengthError('Streaming decode error - repeated field "addresses" had too many elements') + } + + for (const evt of Address.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}addresses`, { + limits: opts.limits?.addresses$ + })) { + yield { + ...evt, + index: obj.addresses + } + } + + obj.addresses++ + + break + } + case 2: { + if (opts.limits?.protocols != null && obj.protocols === opts.limits.protocols) { + throw new MaxLengthError('Streaming decode error - repeated field "protocols" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}protocols`, + index: obj.protocols, + value: reader.string() + } + + obj.protocols++ + + break + } + case 3: { + if (opts.limits?.metadata != null && obj.metadata === opts.limits.metadata) { + throw new MaxLengthError('Streaming decode error - repeated field "metadata" had too many elements') + } + + for (const evt of Metadata.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}metadata`, { + limits: opts.limits?.metadata$ + })) { + yield { + ...evt, + index: obj.metadata + } + } + + obj.metadata++ + + break + } + case 4: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}pubKey`, + value: reader.bytes() + } + break + } + case 5: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}peerRecordEnvelope`, + value: reader.bytes() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface PeerProtocolsFieldEvent { + field: 'protocols$entry' + index: number + value: string + } + + export interface PeerPubKeyFieldEvent { + field: 'pubKey' + value: Uint8Array + } + + export interface PeerPeerRecordEnvelopeFieldEvent { + field: 'peerRecordEnvelope' + value: Uint8Array + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Peer.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Peer => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Peer { return decodeMessage(buf, Peer.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Peer.codec(), opts) + } } export interface Address { @@ -182,19 +286,60 @@ export namespace Address { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}multiaddr`, + value: reader.bytes() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}isCertified`, + value: reader.bool() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial
): Uint8Array => { + export interface AddressMultiaddrFieldEvent { + field: 'multiaddr' + value: Uint8Array + } + + export interface AddressIsCertifiedFieldEvent { + field: 'isCertified' + value: boolean + } + + export function encode (obj: Partial
): Uint8Array { return encodeMessage(obj, Address.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions
): Address => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions
): Address { return decodeMessage(buf, Address.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions
): Generator { + return streamMessage(buf, Address.codec(), opts) + } } export interface Metadata { @@ -253,17 +398,58 @@ export namespace Metadata { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}key`, + value: reader.string() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}value`, + value: reader.bytes() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface MetadataKeyFieldEvent { + field: 'key' + value: string + } + + export interface MetadataValueFieldEvent { + field: 'value' + value: Uint8Array + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Metadata.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Metadata => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Metadata { return decodeMessage(buf, Metadata.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Metadata.codec(), opts) + } } diff --git a/packages/protons/test/fixtures/proto2.ts b/packages/protons/test/fixtures/proto2.ts index 9392d43..432a1d8 100644 --- a/packages/protons/test/fixtures/proto2.ts +++ b/packages/protons/test/fixtures/proto2.ts @@ -1,4 +1,4 @@ -import { decodeMessage, encodeMessage, message } from 'protons-runtime' +import { decodeMessage, encodeMessage, message, streamMessage } from 'protons-runtime' import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' @@ -47,17 +47,46 @@ export namespace MessageWithRequired { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}scalarField`, + value: reader.int32() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface MessageWithRequiredScalarFieldFieldEvent { + field: 'scalarField' + value: number + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, MessageWithRequired.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithRequired => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithRequired { return decodeMessage(buf, MessageWithRequired.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MessageWithRequired.codec(), opts) + } } diff --git a/packages/protons/test/fixtures/protons-options.ts b/packages/protons/test/fixtures/protons-options.ts index 3ed8c10..2ca72ff 100644 --- a/packages/protons/test/fixtures/protons-options.ts +++ b/packages/protons/test/fixtures/protons-options.ts @@ -1,4 +1,4 @@ -import { decodeMessage, encodeMessage, MaxLengthError, MaxSizeError, message } from 'protons-runtime' +import { decodeMessage, encodeMessage, MaxLengthError, MaxSizeError, message, streamMessage } from 'protons-runtime' import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' @@ -39,7 +39,7 @@ export namespace MessageWithSizeLimitedRepeatedField { switch (tag >>> 3) { case 1: { if (opts.limits?.repeatedField != null && obj.repeatedField.length === opts.limits.repeatedField) { - throw new MaxLengthError('Decode error - map field "repeatedField" had too many elements') + throw new MaxLengthError('Decode error - repeated field "repeatedField" had too many elements') } if (obj.repeatedField.length === 1) { @@ -57,19 +57,65 @@ export namespace MessageWithSizeLimitedRepeatedField { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + repeatedField: 1 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + if (opts.limits?.repeatedField != null && obj.repeatedField === opts.limits.repeatedField) { + throw new MaxLengthError('Streaming decode error - repeated field "repeatedField" had too many elements') + } + + if (obj.repeatedField === 1) { + throw new MaxLengthError('Streaming decode error - repeated field "repeatedField" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}repeatedField`, + index: obj.repeatedField, + value: reader.string() + } + + obj.repeatedField++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface MessageWithSizeLimitedRepeatedFieldRepeatedFieldFieldEvent { + field: 'repeatedField$entry' + index: number + value: string + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, MessageWithSizeLimitedRepeatedField.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithSizeLimitedRepeatedField => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithSizeLimitedRepeatedField { return decodeMessage(buf, MessageWithSizeLimitedRepeatedField.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MessageWithSizeLimitedRepeatedField.codec(), opts) + } } export interface MessageWithSizeLimitedMap { @@ -133,19 +179,60 @@ export namespace MessageWithSizeLimitedMap { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}key`, + value: reader.string() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}value`, + value: reader.string() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface MessageWithSizeLimitedMap$mapFieldEntryKeyFieldEvent { + field: 'key' + value: string + } + + export interface MessageWithSizeLimitedMap$mapFieldEntryValueFieldEvent { + field: 'value' + value: string + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, MessageWithSizeLimitedMap$mapFieldEntry.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithSizeLimitedMap$mapFieldEntry => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithSizeLimitedMap$mapFieldEntry { return decodeMessage(buf, MessageWithSizeLimitedMap$mapFieldEntry.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MessageWithSizeLimitedMap$mapFieldEntry.codec(), opts) + } } let _codec: Codec @@ -157,7 +244,7 @@ export namespace MessageWithSizeLimitedMap { w.fork() } - if (obj.mapField != null && obj.mapField.size !== 0) { + if (obj.mapField != null) { for (const [key, value] of obj.mapField.entries()) { w.uint32(10) MessageWithSizeLimitedMap.MessageWithSizeLimitedMap$mapFieldEntry.codec().encode({ key, value }, w) @@ -187,7 +274,11 @@ export namespace MessageWithSizeLimitedMap { throw new MaxSizeError('Decode error - map field "mapField" had too many elements') } - const entry = MessageWithSizeLimitedMap.MessageWithSizeLimitedMap$mapFieldEntry.codec().decode(reader, reader.uint32()) + const entry = MessageWithSizeLimitedMap.MessageWithSizeLimitedMap$mapFieldEntry.codec().decode(reader, reader.uint32(), { + limits: { + value: opts.limits?.mapField$value + } + }) obj.mapField.set(entry.key, entry.value) break } @@ -199,17 +290,63 @@ export namespace MessageWithSizeLimitedMap { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + mapField: 1 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + if (opts.limits?.mapField != null && obj.mapField === opts.limits.mapField) { + throw new MaxLengthError('Decode error - map field "mapField" had too many elements') + } + + if (obj.mapField === 1) { + throw new MaxLengthError('Decode error - repeated field "mapField" had too many elements') + } + + yield * MessageWithSizeLimitedMap.MessageWithSizeLimitedMap$mapFieldEntry.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}mapField`, { + limits: { + value: opts.limits?.mapField$value + } + }) + + obj.mapField++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface MessageWithSizeLimitedMapMapFieldFieldEvent { + field: 'mapField$entry' + key: string + value: string + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, MessageWithSizeLimitedMap.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithSizeLimitedMap => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithSizeLimitedMap { return decodeMessage(buf, MessageWithSizeLimitedMap.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MessageWithSizeLimitedMap.codec(), opts) + } } diff --git a/packages/protons/test/fixtures/repeated.ts b/packages/protons/test/fixtures/repeated.ts index e971889..aaf2f35 100644 --- a/packages/protons/test/fixtures/repeated.ts +++ b/packages/protons/test/fixtures/repeated.ts @@ -1,6 +1,4 @@ -/* eslint-disable complexity */ - -import { decodeMessage, encodeMessage, MaxLengthError, message } from 'protons-runtime' +import { decodeMessage, encodeMessage, MaxLengthError, message, streamMessage } from 'protons-runtime' import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' @@ -47,7 +45,7 @@ export namespace SubSubMessage { switch (tag >>> 3) { case 1: { if (opts.limits?.foo != null && obj.foo.length === opts.limits.foo) { - throw new MaxLengthError('Decode error - map field "foo" had too many elements') + throw new MaxLengthError('Decode error - repeated field "foo" had too many elements') } obj.foo.push(reader.string()) @@ -65,19 +63,73 @@ export namespace SubSubMessage { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + foo: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + if (opts.limits?.foo != null && obj.foo === opts.limits.foo) { + throw new MaxLengthError('Streaming decode error - repeated field "foo" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}foo`, + index: obj.foo, + value: reader.string() + } + + obj.foo++ + + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}nonRepeating`, + value: reader.uint32() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface SubSubMessageFooFieldEvent { + field: 'foo$entry' + index: number + value: string + } + + export interface SubSubMessageNonRepeatingFieldEvent { + field: 'nonRepeating' + value: number + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, SubSubMessage.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): SubSubMessage => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): SubSubMessage { return decodeMessage(buf, SubSubMessage.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, SubSubMessage.codec(), opts) + } } export interface SubMessage { @@ -138,7 +190,7 @@ export namespace SubMessage { switch (tag >>> 3) { case 1: { if (opts.limits?.foo != null && obj.foo.length === opts.limits.foo) { - throw new MaxLengthError('Decode error - map field "foo" had too many elements') + throw new MaxLengthError('Decode error - repeated field "foo" had too many elements') } obj.foo.push(reader.string()) @@ -156,7 +208,7 @@ export namespace SubMessage { } case 4: { if (opts.limits?.messages != null && obj.messages.length === opts.limits.messages) { - throw new MaxLengthError('Decode error - map field "messages" had too many elements') + throw new MaxLengthError('Decode error - repeated field "messages" had too many elements') } obj.messages.push(SubSubMessage.codec().decode(reader, reader.uint32(), { @@ -172,19 +224,110 @@ export namespace SubMessage { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + foo: 0, + messages: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + if (opts.limits?.foo != null && obj.foo === opts.limits.foo) { + throw new MaxLengthError('Streaming decode error - repeated field "foo" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}foo`, + index: obj.foo, + value: reader.string() + } + + obj.foo++ + + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}nonRepeating`, + value: reader.uint32() + } + break + } + case 3: { + yield * SubSubMessage.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}message`, { + limits: opts.limits?.message + }) + + break + } + case 4: { + if (opts.limits?.messages != null && obj.messages === opts.limits.messages) { + throw new MaxLengthError('Streaming decode error - repeated field "messages" had too many elements') + } + + for (const evt of SubSubMessage.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}messages`, { + limits: opts.limits?.messages$ + })) { + yield { + ...evt, + index: obj.messages + } + } + + obj.messages++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface SubMessageFooFieldEvent { + field: 'foo$entry' + index: number + value: string + } + + export interface SubMessageNonRepeatingFieldEvent { + field: 'nonRepeating' + value: number + } + + export interface SubMessageMessageSubSubMessageFooFieldEvent { + field: 'foo$entry' + index: number + value: string + } + + export interface SubMessageMessageSubSubMessageNonRepeatingFieldEvent { + field: 'nonRepeating' + value: number + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, SubMessage.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): SubMessage => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): SubMessage { return decodeMessage(buf, SubMessage.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, SubMessage.codec(), opts) + } } export interface RepeatedTypes { @@ -254,7 +397,7 @@ export namespace RepeatedTypes { switch (tag >>> 3) { case 1: { if (opts.limits?.number != null && obj.number.length === opts.limits.number) { - throw new MaxLengthError('Decode error - map field "number" had too many elements') + throw new MaxLengthError('Decode error - repeated field "number" had too many elements') } obj.number.push(reader.uint32()) @@ -262,7 +405,7 @@ export namespace RepeatedTypes { } case 2: { if (opts.limits?.limitedNumber != null && obj.limitedNumber.length === opts.limits.limitedNumber) { - throw new MaxLengthError('Decode error - map field "limitedNumber" had too many elements') + throw new MaxLengthError('Decode error - repeated field "limitedNumber" had too many elements') } if (obj.limitedNumber.length === 1) { @@ -274,7 +417,7 @@ export namespace RepeatedTypes { } case 3: { if (opts.limits?.messages != null && obj.messages.length === opts.limits.messages) { - throw new MaxLengthError('Decode error - map field "messages" had too many elements') + throw new MaxLengthError('Decode error - repeated field "messages" had too many elements') } obj.messages.push(SubMessage.codec().decode(reader, reader.uint32(), { @@ -300,17 +443,145 @@ export namespace RepeatedTypes { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + number: 0, + limitedNumber: 1, + messages: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + if (opts.limits?.number != null && obj.number === opts.limits.number) { + throw new MaxLengthError('Streaming decode error - repeated field "number" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}number`, + index: obj.number, + value: reader.uint32() + } + + obj.number++ + + break + } + case 2: { + if (opts.limits?.limitedNumber != null && obj.limitedNumber === opts.limits.limitedNumber) { + throw new MaxLengthError('Streaming decode error - repeated field "limitedNumber" had too many elements') + } + + if (obj.limitedNumber === 1) { + throw new MaxLengthError('Streaming decode error - repeated field "limitedNumber" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}limitedNumber`, + index: obj.limitedNumber, + value: reader.uint32() + } + + obj.limitedNumber++ + + break + } + case 3: { + if (opts.limits?.messages != null && obj.messages === opts.limits.messages) { + throw new MaxLengthError('Streaming decode error - repeated field "messages" had too many elements') + } + + for (const evt of SubMessage.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}messages`, { + limits: opts.limits?.messages$ + })) { + yield { + ...evt, + index: obj.messages + } + } + + obj.messages++ + + break + } + case 4: { + yield * SubMessage.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}message`, { + limits: opts.limits?.message + }) + + break + } + case 5: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}nonRepeating`, + value: reader.uint32() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface RepeatedTypesNumberFieldEvent { + field: 'number$entry' + index: number + value: number + } + + export interface RepeatedTypesLimitedNumberFieldEvent { + field: 'limitedNumber$entry' + index: number + value: number + } + + export interface RepeatedTypesMessageSubMessageFooFieldEvent { + field: 'foo$entry' + index: number + value: string + } + + export interface RepeatedTypesMessageSubMessageNonRepeatingFieldEvent { + field: 'nonRepeating' + value: number + } + + export interface RepeatedTypesMessageSubMessageMessageSubSubMessageFooFieldEvent { + field: 'foo$entry' + index: number + value: string + } + + export interface RepeatedTypesMessageSubMessageMessageSubSubMessageNonRepeatingFieldEvent { + field: 'nonRepeating' + value: number + } + + export interface RepeatedTypesNonRepeatingFieldEvent { + field: 'nonRepeating' + value: number + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, RepeatedTypes.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): RepeatedTypes => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): RepeatedTypes { return decodeMessage(buf, RepeatedTypes.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, RepeatedTypes.codec(), opts) + } } diff --git a/packages/protons/test/fixtures/singular.ts b/packages/protons/test/fixtures/singular.ts index f8e5238..84611b2 100644 --- a/packages/protons/test/fixtures/singular.ts +++ b/packages/protons/test/fixtures/singular.ts @@ -1,6 +1,4 @@ -/* eslint-disable complexity */ - -import { decodeMessage, encodeMessage, enumeration, message } from 'protons-runtime' +import { decodeMessage, encodeMessage, enumeration, message, streamMessage } from 'protons-runtime' import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' @@ -79,19 +77,60 @@ export namespace SingularSubMessage { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}foo`, + value: reader.string() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}bar`, + value: reader.int32() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface SingularSubMessageFooFieldEvent { + field: 'foo' + value: string + } + + export interface SingularSubMessageBarFieldEvent { + field: 'bar' + value: number + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, SingularSubMessage.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): SingularSubMessage => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): SingularSubMessage { return decodeMessage(buf, SingularSubMessage.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, SingularSubMessage.codec(), opts) + } } export interface Singular { @@ -316,17 +355,243 @@ export namespace Singular { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}double`, + value: reader.double() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}float`, + value: reader.float() + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}int32`, + value: reader.int32() + } + break + } + case 4: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}int64`, + value: reader.int64() + } + break + } + case 5: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}uint32`, + value: reader.uint32() + } + break + } + case 6: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}uint64`, + value: reader.uint64() + } + break + } + case 7: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}sint32`, + value: reader.sint32() + } + break + } + case 8: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}sint64`, + value: reader.sint64() + } + break + } + case 9: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}fixed32`, + value: reader.fixed32() + } + break + } + case 10: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}fixed64`, + value: reader.fixed64() + } + break + } + case 11: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}sfixed32`, + value: reader.sfixed32() + } + break + } + case 12: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}sfixed64`, + value: reader.sfixed64() + } + break + } + case 13: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}bool`, + value: reader.bool() + } + break + } + case 14: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}string`, + value: reader.string() + } + break + } + case 15: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}bytes`, + value: reader.bytes() + } + break + } + case 16: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}enum`, + value: SingularEnum.codec().decode(reader) + } + break + } + case 17: { + yield * SingularSubMessage.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}subMessage`, { + limits: opts.limits?.subMessage + }) + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface SingularDoubleFieldEvent { + field: 'double' + value: number + } + + export interface SingularFloatFieldEvent { + field: 'float' + value: number + } + + export interface SingularInt32FieldEvent { + field: 'int32' + value: number + } + + export interface SingularInt64FieldEvent { + field: 'int64' + value: bigint + } + + export interface SingularUint32FieldEvent { + field: 'uint32' + value: number + } + + export interface SingularUint64FieldEvent { + field: 'uint64' + value: bigint + } + + export interface SingularSint32FieldEvent { + field: 'sint32' + value: number + } + + export interface SingularSint64FieldEvent { + field: 'sint64' + value: bigint + } + + export interface SingularFixed32FieldEvent { + field: 'fixed32' + value: number + } + + export interface SingularFixed64FieldEvent { + field: 'fixed64' + value: bigint + } + + export interface SingularSfixed32FieldEvent { + field: 'sfixed32' + value: number + } + + export interface SingularSfixed64FieldEvent { + field: 'sfixed64' + value: bigint + } + + export interface SingularBoolFieldEvent { + field: 'bool' + value: boolean + } + + export interface SingularStringFieldEvent { + field: 'string' + value: string + } + + export interface SingularBytesFieldEvent { + field: 'bytes' + value: Uint8Array + } + + export interface SingularEnumFieldEvent { + field: 'enum' + value: SingularEnum + } + + export interface SingularSubMessageSingularSubMessageFooFieldEvent { + field: 'foo' + value: string + } + + export interface SingularSubMessageSingularSubMessageBarFieldEvent { + field: 'bar' + value: number + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, Singular.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Singular => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Singular { return decodeMessage(buf, Singular.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, Singular.codec(), opts) + } } diff --git a/packages/protons/test/fixtures/streaming.proto b/packages/protons/test/fixtures/streaming.proto new file mode 100644 index 0000000..f187c37 --- /dev/null +++ b/packages/protons/test/fixtures/streaming.proto @@ -0,0 +1,36 @@ +syntax = "proto3"; + +message MessageWithArrayField { + optional bool field1 = 1; + optional uint32 field2 = 2; + repeated string arr = 3; +} + +message NestedMessage { + string nestedValue = 1; + } + +message MessageWithNestedMessage { + bool field1 = 1; + NestedMessage nestedMessage = 2; +} + +message MessageWithDeeplyNestedMessage { + bool field1 = 1; + MessageWithNestedMessage nestedMessage = 2; +} + +message MessageWithRepeatedMessage { + bool field1 = 1; + repeated NestedMessage nestedMessages = 2; +} + +message MessageWithMapMessage { + bool field1 = 1; + map nestedMessages = 2; +} + +message MessageWithPrimitiveMap { + bool field1 = 1; + map nestedStrings = 2; +} diff --git a/packages/protons/test/fixtures/streaming.ts b/packages/protons/test/fixtures/streaming.ts new file mode 100644 index 0000000..45d746e --- /dev/null +++ b/packages/protons/test/fixtures/streaming.ts @@ -0,0 +1,1096 @@ +import { decodeMessage, encodeMessage, MaxLengthError, MaxSizeError, message, streamMessage } from 'protons-runtime' +import type { Codec, DecodeOptions } from 'protons-runtime' +import type { Uint8ArrayList } from 'uint8arraylist' + +export interface MessageWithArrayField { + field1?: boolean + field2?: number + arr: string[] +} + +export namespace MessageWithArrayField { + let _codec: Codec + + export const codec = (): Codec => { + if (_codec == null) { + _codec = message((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + } + + if (obj.field1 != null) { + w.uint32(8) + w.bool(obj.field1) + } + + if (obj.field2 != null) { + w.uint32(16) + w.uint32(obj.field2) + } + + if (obj.arr != null) { + for (const value of obj.arr) { + w.uint32(26) + w.string(value) + } + } + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = { + arr: [] + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + obj.field1 = reader.bool() + break + } + case 2: { + obj.field2 = reader.uint32() + break + } + case 3: { + if (opts.limits?.arr != null && obj.arr.length === opts.limits.arr) { + throw new MaxLengthError('Decode error - repeated field "arr" had too many elements') + } + + obj.arr.push(reader.string()) + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + + return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + arr: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field1`, + value: reader.bool() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field2`, + value: reader.uint32() + } + break + } + case 3: { + if (opts.limits?.arr != null && obj.arr === opts.limits.arr) { + throw new MaxLengthError('Streaming decode error - repeated field "arr" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}arr`, + index: obj.arr, + value: reader.string() + } + + obj.arr++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + }) + } + + return _codec + } + + export interface MessageWithArrayFieldField1FieldEvent { + field: 'field1' + value: boolean + } + + export interface MessageWithArrayFieldField2FieldEvent { + field: 'field2' + value: number + } + + export interface MessageWithArrayFieldArrFieldEvent { + field: 'arr$entry' + index: number + value: string + } + + export function encode (obj: Partial): Uint8Array { + return encodeMessage(obj, MessageWithArrayField.codec()) + } + + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithArrayField { + return decodeMessage(buf, MessageWithArrayField.codec(), opts) + } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MessageWithArrayField.codec(), opts) + } +} + +export interface NestedMessage { + nestedValue: string +} + +export namespace NestedMessage { + let _codec: Codec + + export const codec = (): Codec => { + if (_codec == null) { + _codec = message((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + } + + if ((obj.nestedValue != null && obj.nestedValue !== '')) { + w.uint32(10) + w.string(obj.nestedValue) + } + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = { + nestedValue: '' + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + obj.nestedValue = reader.string() + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + + return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}nestedValue`, + value: reader.string() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + }) + } + + return _codec + } + + export interface NestedMessageNestedValueFieldEvent { + field: 'nestedValue' + value: string + } + + export function encode (obj: Partial): Uint8Array { + return encodeMessage(obj, NestedMessage.codec()) + } + + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): NestedMessage { + return decodeMessage(buf, NestedMessage.codec(), opts) + } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, NestedMessage.codec(), opts) + } +} + +export interface MessageWithNestedMessage { + field1: boolean + nestedMessage?: NestedMessage +} + +export namespace MessageWithNestedMessage { + let _codec: Codec + + export const codec = (): Codec => { + if (_codec == null) { + _codec = message((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + } + + if ((obj.field1 != null && obj.field1 !== false)) { + w.uint32(8) + w.bool(obj.field1) + } + + if (obj.nestedMessage != null) { + w.uint32(18) + NestedMessage.codec().encode(obj.nestedMessage, w) + } + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = { + field1: false + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + obj.field1 = reader.bool() + break + } + case 2: { + obj.nestedMessage = NestedMessage.codec().decode(reader, reader.uint32(), { + limits: opts.limits?.nestedMessage + }) + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + + return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field1`, + value: reader.bool() + } + break + } + case 2: { + yield * NestedMessage.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}nestedMessage`, { + limits: opts.limits?.nestedMessage + }) + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + }) + } + + return _codec + } + + export interface MessageWithNestedMessageField1FieldEvent { + field: 'field1' + value: boolean + } + + export interface MessageWithNestedMessageNestedMessageNestedMessageNestedValueFieldEvent { + field: 'nestedValue' + value: string + } + + export function encode (obj: Partial): Uint8Array { + return encodeMessage(obj, MessageWithNestedMessage.codec()) + } + + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithNestedMessage { + return decodeMessage(buf, MessageWithNestedMessage.codec(), opts) + } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MessageWithNestedMessage.codec(), opts) + } +} + +export interface MessageWithDeeplyNestedMessage { + field1: boolean + nestedMessage?: MessageWithNestedMessage +} + +export namespace MessageWithDeeplyNestedMessage { + let _codec: Codec + + export const codec = (): Codec => { + if (_codec == null) { + _codec = message((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + } + + if ((obj.field1 != null && obj.field1 !== false)) { + w.uint32(8) + w.bool(obj.field1) + } + + if (obj.nestedMessage != null) { + w.uint32(18) + MessageWithNestedMessage.codec().encode(obj.nestedMessage, w) + } + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = { + field1: false + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + obj.field1 = reader.bool() + break + } + case 2: { + obj.nestedMessage = MessageWithNestedMessage.codec().decode(reader, reader.uint32(), { + limits: opts.limits?.nestedMessage + }) + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + + return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field1`, + value: reader.bool() + } + break + } + case 2: { + yield * MessageWithNestedMessage.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}nestedMessage`, { + limits: opts.limits?.nestedMessage + }) + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + }) + } + + return _codec + } + + export interface MessageWithDeeplyNestedMessageField1FieldEvent { + field: 'field1' + value: boolean + } + + export interface MessageWithDeeplyNestedMessageNestedMessageMessageWithNestedMessageField1FieldEvent { + field: 'field1' + value: boolean + } + + export interface MessageWithDeeplyNestedMessageNestedMessageMessageWithNestedMessageNestedMessageNestedMessageNestedValueFieldEvent { + field: 'nestedValue' + value: string + } + + export function encode (obj: Partial): Uint8Array { + return encodeMessage(obj, MessageWithDeeplyNestedMessage.codec()) + } + + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithDeeplyNestedMessage { + return decodeMessage(buf, MessageWithDeeplyNestedMessage.codec(), opts) + } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MessageWithDeeplyNestedMessage.codec(), opts) + } +} + +export interface MessageWithRepeatedMessage { + field1: boolean + nestedMessages: NestedMessage[] +} + +export namespace MessageWithRepeatedMessage { + let _codec: Codec + + export const codec = (): Codec => { + if (_codec == null) { + _codec = message((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + } + + if ((obj.field1 != null && obj.field1 !== false)) { + w.uint32(8) + w.bool(obj.field1) + } + + if (obj.nestedMessages != null) { + for (const value of obj.nestedMessages) { + w.uint32(18) + NestedMessage.codec().encode(value, w) + } + } + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = { + field1: false, + nestedMessages: [] + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + obj.field1 = reader.bool() + break + } + case 2: { + if (opts.limits?.nestedMessages != null && obj.nestedMessages.length === opts.limits.nestedMessages) { + throw new MaxLengthError('Decode error - repeated field "nestedMessages" had too many elements') + } + + obj.nestedMessages.push(NestedMessage.codec().decode(reader, reader.uint32(), { + limits: opts.limits?.nestedMessages$ + })) + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + + return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + nestedMessages: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field1`, + value: reader.bool() + } + break + } + case 2: { + if (opts.limits?.nestedMessages != null && obj.nestedMessages === opts.limits.nestedMessages) { + throw new MaxLengthError('Streaming decode error - repeated field "nestedMessages" had too many elements') + } + + for (const evt of NestedMessage.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}nestedMessages`, { + limits: opts.limits?.nestedMessages$ + })) { + yield { + ...evt, + index: obj.nestedMessages + } + } + + obj.nestedMessages++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + }) + } + + return _codec + } + + export interface MessageWithRepeatedMessageField1FieldEvent { + field: 'field1' + value: boolean + } + + export function encode (obj: Partial): Uint8Array { + return encodeMessage(obj, MessageWithRepeatedMessage.codec()) + } + + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithRepeatedMessage { + return decodeMessage(buf, MessageWithRepeatedMessage.codec(), opts) + } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MessageWithRepeatedMessage.codec(), opts) + } +} + +export interface MessageWithMapMessage { + field1: boolean + nestedMessages: Map +} + +export namespace MessageWithMapMessage { + export interface MessageWithMapMessage$nestedMessagesEntry { + key: string + value?: NestedMessage + } + + export namespace MessageWithMapMessage$nestedMessagesEntry { + let _codec: Codec + + export const codec = (): Codec => { + if (_codec == null) { + _codec = message((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + } + + if ((obj.key != null && obj.key !== '')) { + w.uint32(10) + w.string(obj.key) + } + + if (obj.value != null) { + w.uint32(18) + NestedMessage.codec().encode(obj.value, w) + } + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = { + key: '' + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + obj.key = reader.string() + break + } + case 2: { + obj.value = NestedMessage.codec().decode(reader, reader.uint32(), { + limits: opts.limits?.value + }) + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + + return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}key`, + value: reader.string() + } + break + } + case 2: { + yield * NestedMessage.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}value`, { + limits: opts.limits?.value + }) + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + }) + } + + return _codec + } + + export interface MessageWithMapMessage$nestedMessagesEntryKeyFieldEvent { + field: 'key' + value: string + } + + export interface MessageWithMapMessage$nestedMessagesEntryValueNestedMessageNestedValueFieldEvent { + field: 'nestedValue' + value: string + } + + export function encode (obj: Partial): Uint8Array { + return encodeMessage(obj, MessageWithMapMessage$nestedMessagesEntry.codec()) + } + + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithMapMessage$nestedMessagesEntry { + return decodeMessage(buf, MessageWithMapMessage$nestedMessagesEntry.codec(), opts) + } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MessageWithMapMessage$nestedMessagesEntry.codec(), opts) + } + } + + let _codec: Codec + + export const codec = (): Codec => { + if (_codec == null) { + _codec = message((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + } + + if ((obj.field1 != null && obj.field1 !== false)) { + w.uint32(8) + w.bool(obj.field1) + } + + if (obj.nestedMessages != null) { + for (const [key, value] of obj.nestedMessages.entries()) { + w.uint32(18) + MessageWithMapMessage.MessageWithMapMessage$nestedMessagesEntry.codec().encode({ key, value }, w) + } + } + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = { + field1: false, + nestedMessages: new Map() + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + obj.field1 = reader.bool() + break + } + case 2: { + if (opts.limits?.nestedMessages != null && obj.nestedMessages.size === opts.limits.nestedMessages) { + throw new MaxSizeError('Decode error - map field "nestedMessages" had too many elements') + } + + const entry = MessageWithMapMessage.MessageWithMapMessage$nestedMessagesEntry.codec().decode(reader, reader.uint32(), { + limits: { + value: opts.limits?.nestedMessages$value + } + }) + obj.nestedMessages.set(entry.key, entry.value) + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + + return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + nestedMessages: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field1`, + value: reader.bool() + } + break + } + case 2: { + if (opts.limits?.nestedMessages != null && obj.nestedMessages === opts.limits.nestedMessages) { + throw new MaxLengthError('Decode error - map field "nestedMessages" had too many elements') + } + + yield * MessageWithMapMessage.MessageWithMapMessage$nestedMessagesEntry.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}nestedMessages`, { + limits: { + value: opts.limits?.nestedMessages$value + } + }) + + obj.nestedMessages++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + }) + } + + return _codec + } + + export interface MessageWithMapMessageField1FieldEvent { + field: 'field1' + value: boolean + } + + export function encode (obj: Partial): Uint8Array { + return encodeMessage(obj, MessageWithMapMessage.codec()) + } + + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithMapMessage { + return decodeMessage(buf, MessageWithMapMessage.codec(), opts) + } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MessageWithMapMessage.codec(), opts) + } +} + +export interface MessageWithPrimitiveMap { + field1: boolean + nestedStrings: Map +} + +export namespace MessageWithPrimitiveMap { + export interface MessageWithPrimitiveMap$nestedStringsEntry { + key: string + value: string + } + + export namespace MessageWithPrimitiveMap$nestedStringsEntry { + let _codec: Codec + + export const codec = (): Codec => { + if (_codec == null) { + _codec = message((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + } + + if ((obj.key != null && obj.key !== '')) { + w.uint32(10) + w.string(obj.key) + } + + if ((obj.value != null && obj.value !== '')) { + w.uint32(18) + w.string(obj.value) + } + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = { + key: '', + value: '' + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + obj.key = reader.string() + break + } + case 2: { + obj.value = reader.string() + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + + return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}key`, + value: reader.string() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}value`, + value: reader.string() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + }) + } + + return _codec + } + + export interface MessageWithPrimitiveMap$nestedStringsEntryKeyFieldEvent { + field: 'key' + value: string + } + + export interface MessageWithPrimitiveMap$nestedStringsEntryValueFieldEvent { + field: 'value' + value: string + } + + export function encode (obj: Partial): Uint8Array { + return encodeMessage(obj, MessageWithPrimitiveMap$nestedStringsEntry.codec()) + } + + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithPrimitiveMap$nestedStringsEntry { + return decodeMessage(buf, MessageWithPrimitiveMap$nestedStringsEntry.codec(), opts) + } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MessageWithPrimitiveMap$nestedStringsEntry.codec(), opts) + } + } + + let _codec: Codec + + export const codec = (): Codec => { + if (_codec == null) { + _codec = message((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + } + + if ((obj.field1 != null && obj.field1 !== false)) { + w.uint32(8) + w.bool(obj.field1) + } + + if (obj.nestedStrings != null) { + for (const [key, value] of obj.nestedStrings.entries()) { + w.uint32(18) + MessageWithPrimitiveMap.MessageWithPrimitiveMap$nestedStringsEntry.codec().encode({ key, value }, w) + } + } + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = { + field1: false, + nestedStrings: new Map() + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + obj.field1 = reader.bool() + break + } + case 2: { + if (opts.limits?.nestedStrings != null && obj.nestedStrings.size === opts.limits.nestedStrings) { + throw new MaxSizeError('Decode error - map field "nestedStrings" had too many elements') + } + + const entry = MessageWithPrimitiveMap.MessageWithPrimitiveMap$nestedStringsEntry.codec().decode(reader, reader.uint32(), { + limits: { + value: opts.limits?.nestedStrings$value + } + }) + obj.nestedStrings.set(entry.key, entry.value) + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + + return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + nestedStrings: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field1`, + value: reader.bool() + } + break + } + case 2: { + if (opts.limits?.nestedStrings != null && obj.nestedStrings === opts.limits.nestedStrings) { + throw new MaxLengthError('Decode error - map field "nestedStrings" had too many elements') + } + + yield * MessageWithPrimitiveMap.MessageWithPrimitiveMap$nestedStringsEntry.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}nestedStrings`, { + limits: { + value: opts.limits?.nestedStrings$value + } + }) + + obj.nestedStrings++ + + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + }) + } + + return _codec + } + + export interface MessageWithPrimitiveMapField1FieldEvent { + field: 'field1' + value: boolean + } + + export interface MessageWithPrimitiveMapNestedStringsFieldEvent { + field: 'nestedStrings$entry' + key: string + value: string + } + + export function encode (obj: Partial): Uint8Array { + return encodeMessage(obj, MessageWithPrimitiveMap.codec()) + } + + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): MessageWithPrimitiveMap { + return decodeMessage(buf, MessageWithPrimitiveMap.codec(), opts) + } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, MessageWithPrimitiveMap.codec(), opts) + } +} diff --git a/packages/protons/test/fixtures/test.ts b/packages/protons/test/fixtures/test.ts index 5fc17f6..3276a37 100644 --- a/packages/protons/test/fixtures/test.ts +++ b/packages/protons/test/fixtures/test.ts @@ -1,6 +1,4 @@ -/* eslint-disable complexity */ - -import { decodeMessage, encodeMessage, enumeration, MaxLengthError, message } from 'protons-runtime' +import { decodeMessage, encodeMessage, enumeration, MaxLengthError, message, streamMessage } from 'protons-runtime' import type { Codec, DecodeOptions } from 'protons-runtime' import type { Uint8ArrayList } from 'uint8arraylist' @@ -65,19 +63,48 @@ export namespace SubMessage { } return obj + }, function * (reader, length, prefix, opts = {}) { + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}foo`, + value: reader.string() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface SubMessageFooFieldEvent { + field: 'foo' + value: string + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, SubMessage.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): SubMessage => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): SubMessage { return decodeMessage(buf, SubMessage.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, SubMessage.codec(), opts) + } } export interface AllTheTypes { @@ -273,7 +300,7 @@ export namespace AllTheTypes { } case 14: { if (opts.limits?.field14 != null && obj.field14.length === opts.limits.field14) { - throw new MaxLengthError('Decode error - map field "field14" had too many elements') + throw new MaxLengthError('Decode error - repeated field "field14" had too many elements') } obj.field14.push(reader.string()) @@ -303,17 +330,263 @@ export namespace AllTheTypes { } return obj + }, function * (reader, length, prefix, opts = {}) { + const obj = { + field14: 0 + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field1`, + value: reader.bool() + } + break + } + case 2: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field2`, + value: reader.int32() + } + break + } + case 3: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field3`, + value: reader.int64() + } + break + } + case 4: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field4`, + value: reader.uint32() + } + break + } + case 5: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field5`, + value: reader.uint64() + } + break + } + case 6: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field6`, + value: reader.sint32() + } + break + } + case 7: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field7`, + value: reader.sint64() + } + break + } + case 8: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field8`, + value: reader.double() + } + break + } + case 9: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field9`, + value: reader.float() + } + break + } + case 10: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field10`, + value: reader.string() + } + break + } + case 11: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field11`, + value: reader.bytes() + } + break + } + case 12: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field12`, + value: AnEnum.codec().decode(reader) + } + break + } + case 13: { + yield * SubMessage.codec().stream(reader, reader.uint32(), `${prefix != null ? `${prefix}.` : ''}field13`, { + limits: opts.limits?.field13 + }) + + break + } + case 14: { + if (opts.limits?.field14 != null && obj.field14 === opts.limits.field14) { + throw new MaxLengthError('Streaming decode error - repeated field "field14" had too many elements') + } + + yield { + field: `${prefix != null ? `${prefix}.` : ''}field14`, + index: obj.field14, + value: reader.string() + } + + obj.field14++ + + break + } + case 15: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field15`, + value: reader.fixed32() + } + break + } + case 16: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field16`, + value: reader.fixed64() + } + break + } + case 17: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field17`, + value: reader.sfixed32() + } + break + } + case 18: { + yield { + field: `${prefix != null ? `${prefix}.` : ''}field18`, + value: reader.sfixed64() + } + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } }) } return _codec } - export const encode = (obj: Partial): Uint8Array => { + export interface AllTheTypesField1FieldEvent { + field: 'field1' + value: boolean + } + + export interface AllTheTypesField2FieldEvent { + field: 'field2' + value: number + } + + export interface AllTheTypesField3FieldEvent { + field: 'field3' + value: bigint + } + + export interface AllTheTypesField4FieldEvent { + field: 'field4' + value: number + } + + export interface AllTheTypesField5FieldEvent { + field: 'field5' + value: bigint + } + + export interface AllTheTypesField6FieldEvent { + field: 'field6' + value: number + } + + export interface AllTheTypesField7FieldEvent { + field: 'field7' + value: bigint + } + + export interface AllTheTypesField8FieldEvent { + field: 'field8' + value: number + } + + export interface AllTheTypesField9FieldEvent { + field: 'field9' + value: number + } + + export interface AllTheTypesField10FieldEvent { + field: 'field10' + value: string + } + + export interface AllTheTypesField11FieldEvent { + field: 'field11' + value: Uint8Array + } + + export interface AllTheTypesField12FieldEvent { + field: 'field12' + value: AnEnum + } + + export interface AllTheTypesField13SubMessageFooFieldEvent { + field: 'foo' + value: string + } + + export interface AllTheTypesField14FieldEvent { + field: 'field14$entry' + index: number + value: string + } + + export interface AllTheTypesField15FieldEvent { + field: 'field15' + value: number + } + + export interface AllTheTypesField16FieldEvent { + field: 'field16' + value: bigint + } + + export interface AllTheTypesField17FieldEvent { + field: 'field17' + value: number + } + + export interface AllTheTypesField18FieldEvent { + field: 'field18' + value: bigint + } + + export function encode (obj: Partial): Uint8Array { return encodeMessage(obj, AllTheTypes.codec()) } - export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): AllTheTypes => { + export function decode (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): AllTheTypes { return decodeMessage(buf, AllTheTypes.codec(), opts) } + + export function stream (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Generator { + return streamMessage(buf, AllTheTypes.codec(), opts) + } } diff --git a/packages/protons/test/streaming-decode.spec.ts b/packages/protons/test/streaming-decode.spec.ts new file mode 100644 index 0000000..fa4519d --- /dev/null +++ b/packages/protons/test/streaming-decode.spec.ts @@ -0,0 +1,183 @@ +import { expect } from 'aegir/chai' +import all from 'it-all' +import { MessageWithArrayField, MessageWithNestedMessage, MessageWithRepeatedMessage, MessageWithMapMessage, MessageWithPrimitiveMap, MessageWithDeeplyNestedMessage } from './fixtures/streaming.ts' + +describe('streaming-decode', () => { + it('should include indexes in field values', async () => { + const input = MessageWithArrayField.encode({ + arr: [ + '1', '2', '3' + ] + }) + + const output = all(MessageWithArrayField.stream(input)) + + expect(output).to.deep.equal([{ + field: 'arr', + index: 0, + value: '1' + }, { + field: 'arr', + index: 1, + value: '2' + }, { + field: 'arr', + index: 2, + value: '3' + }]) + }) + + it('should not parse input after exiting loop', () => { + const input = MessageWithArrayField.encode({ + field1: true, + field2: 5, + arr: [ + '1', '2', '3' + ] + }) + + const output = [] + + // make input invalid + input[9] = 0 + input[10] = 0 + input[11] = 0 + input[12] = 0 + + // cannot read input to completion + expect(() => { + all(MessageWithArrayField.stream(input)) + }).to.throw().with.property('name', 'RangeError') + + // can read first couple of values + for (const evt of MessageWithArrayField.stream(input)) { + output.push(evt) + + if (evt.field === 'field2') { + break + } + } + + expect(output).to.have.lengthOf(2) + }) + + it('should stream nested message fields', () => { + const input = MessageWithNestedMessage.encode({ + field1: true, + nestedMessage: { + nestedValue: 'hello' + } + }) + + const output = all(MessageWithNestedMessage.stream(input)) + + expect(output).to.deep.equal([{ + field: 'field1', + value: true + }, { + field: 'nestedMessage.nestedValue', + value: 'hello' + }]) + }) + + it('should stream deeply nested message fields', () => { + const input = MessageWithDeeplyNestedMessage.encode({ + field1: true, + nestedMessage: { + field1: true, + nestedMessage: { + nestedValue: 'hello' + } + } + }) + + const output = all(MessageWithDeeplyNestedMessage.stream(input)) + + expect(output).to.deep.equal([{ + field: 'field1', + value: true + }, { + field: 'nestedMessage.field1', + value: true + }, { + field: 'nestedMessage.nestedMessage.nestedValue', + value: 'hello' + }]) + }) + + it('should stream message fields in lists', () => { + const input = MessageWithRepeatedMessage.encode({ + field1: true, + nestedMessages: [{ + nestedValue: 'hello' + }] + }) + + const output = all(MessageWithRepeatedMessage.stream(input)) + + expect(output).to.deep.equal([{ + field: 'field1', + value: true + }, { + field: 'nestedMessages.nestedValue', + index: 0, + value: 'hello' + }]) + }) + + it('should stream message fields in maps', () => { + const input = MessageWithMapMessage.encode({ + field1: true, + nestedMessages: new Map([['this-is-a-key', { + nestedValue: 'hello' + }], ['this-is-another-key', { + nestedValue: 'world' + }]]) + }) + + const output = all(MessageWithMapMessage.stream(input)) + + expect(output).to.deep.equal([{ + field: 'field1', + value: true + }, { + field: 'nestedMessages.key', + value: 'this-is-a-key' + }, { + field: 'nestedMessages.value.nestedValue', + value: 'hello' + }, { + field: 'nestedMessages.key', + value: 'this-is-another-key' + }, { + field: 'nestedMessages.value.nestedValue', + value: 'world' + }]) + }) + + it('should stream primitive fields in maps', () => { + const input = MessageWithPrimitiveMap.encode({ + field1: true, + nestedStrings: new Map([['this-is-a-key', 'this-is-a-value'], ['this-is-another-key', 'this-is-another-value']]) + }) + + const output = all(MessageWithPrimitiveMap.stream(input)) + + expect(output).to.deep.equal([{ + field: 'field1', + value: true + }, { + field: 'nestedStrings.key', + value: 'this-is-a-key' + }, { + field: 'nestedStrings.value', + value: 'this-is-a-value' + }, { + field: 'nestedStrings.key', + value: 'this-is-another-key' + }, { + field: 'nestedStrings.value', + value: 'this-is-another-value' + }]) + }) +})