goscript 0.0.16 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +3 -1
- package/builtin/builtin.ts +323 -45
- package/compiler/compiler.go +537 -140
- package/compiler/writer.go +14 -0
- package/dist/builtin/builtin.d.ts +79 -6
- package/dist/builtin/builtin.js +228 -37
- package/dist/builtin/builtin.js.map +1 -1
- package/go.mod +1 -3
- package/package.json +1 -1
package/compiler/writer.go
CHANGED
|
@@ -65,6 +65,15 @@ func (w *TSCodeWriter) WriteCommentLine(commentText string) {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
// WriteCommentLinef writes a formatted comment as a // line.
|
|
69
|
+
func (w *TSCodeWriter) WriteCommentLinef(format string, args ...any) {
|
|
70
|
+
commentText := fmt.Sprintf(format, args...)
|
|
71
|
+
lines := strings.SplitSeq(commentText, "\n")
|
|
72
|
+
for line := range lines {
|
|
73
|
+
w.WriteLinef("// %s", line)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
68
77
|
// WriteCommentInline write a comment within /* */.
|
|
69
78
|
func (w *TSCodeWriter) WriteCommentInline(commentText string) {
|
|
70
79
|
w.w.Write([]byte("/* ")) //nolint:errcheck
|
|
@@ -72,6 +81,11 @@ func (w *TSCodeWriter) WriteCommentInline(commentText string) {
|
|
|
72
81
|
w.w.Write([]byte(" */")) //nolint:errcheck
|
|
73
82
|
}
|
|
74
83
|
|
|
84
|
+
// WriteCommentInlinef writes a formatted comment within /* */.
|
|
85
|
+
func (w *TSCodeWriter) WriteCommentInlinef(format string, args ...any) {
|
|
86
|
+
w.WriteCommentInline(fmt.Sprintf(format, args...))
|
|
87
|
+
}
|
|
88
|
+
|
|
75
89
|
// WriteLiterally writes something to the output without processing
|
|
76
90
|
func (w *TSCodeWriter) WriteLiterally(literal string) {
|
|
77
91
|
w.sectionWrittenFlag = true
|
|
@@ -177,8 +177,7 @@ export interface StructTypeInfo extends BaseTypeInfo {
|
|
|
177
177
|
kind: TypeKind.Struct;
|
|
178
178
|
methods: Set<string>;
|
|
179
179
|
ctor?: new (...args: any[]) => any;
|
|
180
|
-
fields
|
|
181
|
-
fieldTypes?: Record<string, TypeInfo | string>;
|
|
180
|
+
fields: Record<string, TypeInfo | string>;
|
|
182
181
|
}
|
|
183
182
|
/**
|
|
184
183
|
* Type information for interface types
|
|
@@ -261,7 +260,7 @@ export declare function isChannelTypeInfo(info: TypeInfo): info is ChannelTypeIn
|
|
|
261
260
|
* @param ctor Constructor for the struct.
|
|
262
261
|
* @returns The struct type information object.
|
|
263
262
|
*/
|
|
264
|
-
export declare const registerStructType: (name: string, zeroValue: any, methods: Set<string>, ctor: new (...args: any[]) => any) => StructTypeInfo;
|
|
263
|
+
export declare const registerStructType: (name: string, zeroValue: any, methods: Set<string>, ctor: new (...args: any[]) => any, fields?: Record<string, TypeInfo | string>) => StructTypeInfo;
|
|
265
264
|
/**
|
|
266
265
|
* Registers an interface type with the runtime type system.
|
|
267
266
|
*
|
|
@@ -350,13 +349,86 @@ export interface Channel<T> {
|
|
|
350
349
|
*/
|
|
351
350
|
canSendNonBlocking(): boolean;
|
|
352
351
|
}
|
|
352
|
+
/**
|
|
353
|
+
* Represents a reference to a channel with a specific direction.
|
|
354
|
+
*/
|
|
355
|
+
export interface ChannelRef<T> {
|
|
356
|
+
/**
|
|
357
|
+
* The underlying channel
|
|
358
|
+
*/
|
|
359
|
+
channel: Channel<T>;
|
|
360
|
+
/**
|
|
361
|
+
* The direction of this channel reference
|
|
362
|
+
*/
|
|
363
|
+
direction: 'send' | 'receive' | 'both';
|
|
364
|
+
send(value: T): Promise<void>;
|
|
365
|
+
receive(): Promise<T>;
|
|
366
|
+
receiveWithOk(): Promise<ChannelReceiveResult<T>>;
|
|
367
|
+
close(): void;
|
|
368
|
+
canSendNonBlocking(): boolean;
|
|
369
|
+
canReceiveNonBlocking(): boolean;
|
|
370
|
+
selectSend(value: T, id: number): Promise<SelectResult<boolean>>;
|
|
371
|
+
selectReceive(id: number): Promise<SelectResult<T>>;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* A bidirectional channel reference.
|
|
375
|
+
*/
|
|
376
|
+
export declare class BidirectionalChannelRef<T> implements ChannelRef<T> {
|
|
377
|
+
channel: Channel<T>;
|
|
378
|
+
direction: 'both';
|
|
379
|
+
constructor(channel: Channel<T>);
|
|
380
|
+
send(value: T): Promise<void>;
|
|
381
|
+
receive(): Promise<T>;
|
|
382
|
+
receiveWithOk(): Promise<ChannelReceiveResult<T>>;
|
|
383
|
+
close(): void;
|
|
384
|
+
canSendNonBlocking(): boolean;
|
|
385
|
+
canReceiveNonBlocking(): boolean;
|
|
386
|
+
selectSend(value: T, id: number): Promise<SelectResult<boolean>>;
|
|
387
|
+
selectReceive(id: number): Promise<SelectResult<T>>;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* A send-only channel reference.
|
|
391
|
+
*/
|
|
392
|
+
export declare class SendOnlyChannelRef<T> implements ChannelRef<T> {
|
|
393
|
+
channel: Channel<T>;
|
|
394
|
+
direction: 'send';
|
|
395
|
+
constructor(channel: Channel<T>);
|
|
396
|
+
send(value: T): Promise<void>;
|
|
397
|
+
close(): void;
|
|
398
|
+
canSendNonBlocking(): boolean;
|
|
399
|
+
selectSend(value: T, id: number): Promise<SelectResult<boolean>>;
|
|
400
|
+
receive(): Promise<T>;
|
|
401
|
+
receiveWithOk(): Promise<ChannelReceiveResult<T>>;
|
|
402
|
+
canReceiveNonBlocking(): boolean;
|
|
403
|
+
selectReceive(id: number): Promise<SelectResult<T>>;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* A receive-only channel reference.
|
|
407
|
+
*/
|
|
408
|
+
export declare class ReceiveOnlyChannelRef<T> implements ChannelRef<T> {
|
|
409
|
+
channel: Channel<T>;
|
|
410
|
+
direction: 'receive';
|
|
411
|
+
constructor(channel: Channel<T>);
|
|
412
|
+
receive(): Promise<T>;
|
|
413
|
+
receiveWithOk(): Promise<ChannelReceiveResult<T>>;
|
|
414
|
+
canReceiveNonBlocking(): boolean;
|
|
415
|
+
selectReceive(id: number): Promise<SelectResult<T>>;
|
|
416
|
+
send(value: T): Promise<void>;
|
|
417
|
+
close(): void;
|
|
418
|
+
canSendNonBlocking(): boolean;
|
|
419
|
+
selectSend(value: T, id: number): Promise<SelectResult<boolean>>;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Creates a new channel reference with the specified direction.
|
|
423
|
+
*/
|
|
424
|
+
export declare function makeChannelRef<T>(channel: Channel<T>, direction: 'send' | 'receive' | 'both'): ChannelRef<T>;
|
|
353
425
|
/**
|
|
354
426
|
* Represents a case in a select statement.
|
|
355
427
|
*/
|
|
356
428
|
export interface SelectCase<T> {
|
|
357
429
|
id: number;
|
|
358
430
|
isSend: boolean;
|
|
359
|
-
channel: Channel<any> | null;
|
|
431
|
+
channel: Channel<any> | ChannelRef<any> | null;
|
|
360
432
|
value?: any;
|
|
361
433
|
onSelected?: (result: SelectResult<T>) => Promise<void>;
|
|
362
434
|
}
|
|
@@ -373,9 +445,10 @@ export declare function selectStatement<T>(cases: SelectCase<T>[], hasDefault?:
|
|
|
373
445
|
* Creates a new channel with the specified buffer size and zero value.
|
|
374
446
|
* @param bufferSize The size of the channel buffer. If 0, creates an unbuffered channel.
|
|
375
447
|
* @param zeroValue The zero value for the channel's element type.
|
|
376
|
-
* @
|
|
448
|
+
* @param direction Optional direction for the channel. Default is 'both' (bidirectional).
|
|
449
|
+
* @returns A new channel instance or channel reference.
|
|
377
450
|
*/
|
|
378
|
-
export declare const makeChannel: <T>(bufferSize: number, zeroValue: T) => Channel<T>;
|
|
451
|
+
export declare const makeChannel: <T>(bufferSize: number, zeroValue: T, direction?: "send" | "receive" | "both") => Channel<T> | ChannelRef<T>;
|
|
379
452
|
/**
|
|
380
453
|
* DisposableStack manages synchronous disposable resources, mimicking Go's defer behavior.
|
|
381
454
|
* Functions added via `defer` are executed in LIFO order when the stack is disposed.
|
package/dist/builtin/builtin.js
CHANGED
|
@@ -585,13 +585,14 @@ const typeRegistry = new Map();
|
|
|
585
585
|
* @param ctor Constructor for the struct.
|
|
586
586
|
* @returns The struct type information object.
|
|
587
587
|
*/
|
|
588
|
-
export const registerStructType = (name, zeroValue, methods, ctor) => {
|
|
588
|
+
export const registerStructType = (name, zeroValue, methods, ctor, fields = {}) => {
|
|
589
589
|
const typeInfo = {
|
|
590
590
|
name,
|
|
591
591
|
kind: TypeKind.Struct,
|
|
592
592
|
zeroValue,
|
|
593
593
|
methods,
|
|
594
|
-
ctor
|
|
594
|
+
ctor,
|
|
595
|
+
fields,
|
|
595
596
|
};
|
|
596
597
|
typeRegistry.set(name, typeInfo);
|
|
597
598
|
return typeInfo;
|
|
@@ -689,21 +690,24 @@ function matchesStructType(value, info) {
|
|
|
689
690
|
if (info.ctor && value instanceof info.ctor) {
|
|
690
691
|
return true;
|
|
691
692
|
}
|
|
692
|
-
if (info.
|
|
693
|
-
|
|
694
|
-
|
|
693
|
+
if (info.methods && typeof value === 'object' && value !== null) {
|
|
694
|
+
const allMethodsMatch = Array.from(info.methods).every((method) => typeof value[method] === 'function');
|
|
695
|
+
if (allMethodsMatch) {
|
|
696
|
+
return true;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
if (typeof value === 'object' && value !== null) {
|
|
700
|
+
const fieldNames = Object.keys(info.fields || {});
|
|
695
701
|
const valueFields = Object.keys(value);
|
|
696
|
-
const
|
|
697
|
-
const
|
|
698
|
-
const
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
});
|
|
706
|
-
return condition1 && condition2 && condition3;
|
|
702
|
+
const fieldsExist = fieldNames.every((field) => field in value);
|
|
703
|
+
const sameFieldCount = valueFields.length === fieldNames.length;
|
|
704
|
+
const allFieldsInStruct = valueFields.every((field) => fieldNames.includes(field));
|
|
705
|
+
if (fieldsExist && sameFieldCount && allFieldsInStruct) {
|
|
706
|
+
return Object.entries(info.fields).every(([fieldName, fieldType]) => {
|
|
707
|
+
return matchesType(value[fieldName], normalizeTypeInfo(fieldType));
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
return false;
|
|
707
711
|
}
|
|
708
712
|
return false;
|
|
709
713
|
}
|
|
@@ -796,9 +800,10 @@ function matchesArrayOrSliceType(value, info) {
|
|
|
796
800
|
* @returns True if the value matches the pointer type, false otherwise.
|
|
797
801
|
*/
|
|
798
802
|
function matchesPointerType(value, info) {
|
|
799
|
-
//
|
|
803
|
+
// Allow null/undefined values to match pointer types to support nil pointer assertions
|
|
804
|
+
// This enables Go's nil pointer type assertions like `ptr, ok := i.(*SomeType)` to work correctly
|
|
800
805
|
if (value === null || value === undefined) {
|
|
801
|
-
return
|
|
806
|
+
return true;
|
|
802
807
|
}
|
|
803
808
|
// Check if the value is a Box (has a 'value' property)
|
|
804
809
|
if (typeof value !== 'object' || !('value' in value)) {
|
|
@@ -820,8 +825,15 @@ function matchesPointerType(value, info) {
|
|
|
820
825
|
* @returns True if the value matches the function type, false otherwise.
|
|
821
826
|
*/
|
|
822
827
|
function matchesFunctionType(value, info) {
|
|
823
|
-
//
|
|
824
|
-
|
|
828
|
+
// First check if the value is a function
|
|
829
|
+
if (typeof value !== 'function') {
|
|
830
|
+
return false;
|
|
831
|
+
}
|
|
832
|
+
// This is important for named function types
|
|
833
|
+
if (info.name && value.__goTypeName) {
|
|
834
|
+
return info.name === value.__goTypeName;
|
|
835
|
+
}
|
|
836
|
+
return true;
|
|
825
837
|
}
|
|
826
838
|
/**
|
|
827
839
|
* Checks if a value matches a channel type info.
|
|
@@ -831,14 +843,42 @@ function matchesFunctionType(value, info) {
|
|
|
831
843
|
* @returns True if the value matches the channel type, false otherwise.
|
|
832
844
|
*/
|
|
833
845
|
function matchesChannelType(value, info) {
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
846
|
+
// First check if it's a channel or channel reference
|
|
847
|
+
if (typeof value !== 'object' || value === null) {
|
|
848
|
+
return false;
|
|
849
|
+
}
|
|
850
|
+
// If it's a ChannelRef, get the underlying channel
|
|
851
|
+
let channel = value;
|
|
852
|
+
let valueDirection = 'both';
|
|
853
|
+
if ('channel' in value && 'direction' in value) {
|
|
854
|
+
channel = value.channel;
|
|
855
|
+
valueDirection = value.direction;
|
|
856
|
+
}
|
|
857
|
+
// Check if it has channel methods
|
|
858
|
+
if (!('send' in channel) ||
|
|
859
|
+
!('receive' in channel) ||
|
|
860
|
+
!('close' in channel) ||
|
|
861
|
+
typeof channel.send !== 'function' ||
|
|
862
|
+
typeof channel.receive !== 'function' ||
|
|
863
|
+
typeof channel.close !== 'function') {
|
|
864
|
+
return false;
|
|
865
|
+
}
|
|
866
|
+
if (info.elemType) {
|
|
867
|
+
if (info.elemType === 'string' &&
|
|
868
|
+
'zeroValue' in channel &&
|
|
869
|
+
channel.zeroValue !== '') {
|
|
870
|
+
return false;
|
|
871
|
+
}
|
|
872
|
+
if (info.elemType === 'number' &&
|
|
873
|
+
'zeroValue' in channel &&
|
|
874
|
+
typeof channel.zeroValue !== 'number') {
|
|
875
|
+
return false;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
if (info.direction) {
|
|
879
|
+
return valueDirection === info.direction;
|
|
880
|
+
}
|
|
881
|
+
return true;
|
|
842
882
|
}
|
|
843
883
|
/**
|
|
844
884
|
* Checks if a value matches a type info.
|
|
@@ -876,18 +916,36 @@ function matchesType(value, info) {
|
|
|
876
916
|
}
|
|
877
917
|
export function typeAssert(value, typeInfo) {
|
|
878
918
|
const normalizedType = normalizeTypeInfo(typeInfo);
|
|
919
|
+
if (isPointerTypeInfo(normalizedType) && value === null) {
|
|
920
|
+
return { value: null, ok: true };
|
|
921
|
+
}
|
|
922
|
+
if (isStructTypeInfo(normalizedType) &&
|
|
923
|
+
normalizedType.methods &&
|
|
924
|
+
typeof value === 'object' &&
|
|
925
|
+
value !== null) {
|
|
926
|
+
// Check if the value implements all methods of the struct type
|
|
927
|
+
const allMethodsMatch = Array.from(normalizedType.methods).every((method) => typeof value[method] === 'function');
|
|
928
|
+
const hasAnyMethod = Array.from(normalizedType.methods).some((method) => typeof value[method] === 'function');
|
|
929
|
+
if (allMethodsMatch && hasAnyMethod && normalizedType.methods.size > 0) {
|
|
930
|
+
// For interface-to-concrete type assertions, we just need to check methods
|
|
931
|
+
return { value: value, ok: true };
|
|
932
|
+
}
|
|
933
|
+
}
|
|
879
934
|
if (isStructTypeInfo(normalizedType) &&
|
|
880
935
|
normalizedType.fields &&
|
|
881
936
|
typeof value === 'object' &&
|
|
882
937
|
value !== null) {
|
|
883
|
-
const
|
|
938
|
+
const fieldNames = Object.keys(normalizedType.fields);
|
|
884
939
|
const valueFields = Object.keys(value);
|
|
885
940
|
// For struct type assertions, we need exact field matching
|
|
886
|
-
const
|
|
887
|
-
|
|
888
|
-
valueFields.every((field) =>
|
|
889
|
-
if (
|
|
890
|
-
|
|
941
|
+
const structFieldsMatch = fieldNames.length === valueFields.length &&
|
|
942
|
+
fieldNames.every((field) => field in value) &&
|
|
943
|
+
valueFields.every((field) => fieldNames.includes(field));
|
|
944
|
+
if (structFieldsMatch) {
|
|
945
|
+
const typesMatch = Object.entries(normalizedType.fields).every(([fieldName, fieldType]) => {
|
|
946
|
+
return matchesType(value[fieldName], normalizeTypeInfo(fieldType));
|
|
947
|
+
});
|
|
948
|
+
return { value: value, ok: typesMatch };
|
|
891
949
|
}
|
|
892
950
|
else {
|
|
893
951
|
return { value: null, ok: false };
|
|
@@ -1124,6 +1182,128 @@ class BufferedChannel {
|
|
|
1124
1182
|
return !this.closed && this.buffer.length < this.capacity;
|
|
1125
1183
|
}
|
|
1126
1184
|
}
|
|
1185
|
+
/**
|
|
1186
|
+
* A bidirectional channel reference.
|
|
1187
|
+
*/
|
|
1188
|
+
export class BidirectionalChannelRef {
|
|
1189
|
+
channel;
|
|
1190
|
+
direction = 'both';
|
|
1191
|
+
constructor(channel) {
|
|
1192
|
+
this.channel = channel;
|
|
1193
|
+
}
|
|
1194
|
+
// Delegate all methods to the underlying channel
|
|
1195
|
+
send(value) {
|
|
1196
|
+
return this.channel.send(value);
|
|
1197
|
+
}
|
|
1198
|
+
receive() {
|
|
1199
|
+
return this.channel.receive();
|
|
1200
|
+
}
|
|
1201
|
+
receiveWithOk() {
|
|
1202
|
+
return this.channel.receiveWithOk();
|
|
1203
|
+
}
|
|
1204
|
+
close() {
|
|
1205
|
+
this.channel.close();
|
|
1206
|
+
}
|
|
1207
|
+
canSendNonBlocking() {
|
|
1208
|
+
return this.channel.canSendNonBlocking();
|
|
1209
|
+
}
|
|
1210
|
+
canReceiveNonBlocking() {
|
|
1211
|
+
return this.channel.canReceiveNonBlocking();
|
|
1212
|
+
}
|
|
1213
|
+
selectSend(value, id) {
|
|
1214
|
+
return this.channel.selectSend(value, id);
|
|
1215
|
+
}
|
|
1216
|
+
selectReceive(id) {
|
|
1217
|
+
return this.channel.selectReceive(id);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* A send-only channel reference.
|
|
1222
|
+
*/
|
|
1223
|
+
export class SendOnlyChannelRef {
|
|
1224
|
+
channel;
|
|
1225
|
+
direction = 'send';
|
|
1226
|
+
constructor(channel) {
|
|
1227
|
+
this.channel = channel;
|
|
1228
|
+
}
|
|
1229
|
+
// Allow send operations
|
|
1230
|
+
send(value) {
|
|
1231
|
+
return this.channel.send(value);
|
|
1232
|
+
}
|
|
1233
|
+
// Allow close operations
|
|
1234
|
+
close() {
|
|
1235
|
+
this.channel.close();
|
|
1236
|
+
}
|
|
1237
|
+
canSendNonBlocking() {
|
|
1238
|
+
return this.channel.canSendNonBlocking();
|
|
1239
|
+
}
|
|
1240
|
+
selectSend(value, id) {
|
|
1241
|
+
return this.channel.selectSend(value, id);
|
|
1242
|
+
}
|
|
1243
|
+
// Disallow receive operations
|
|
1244
|
+
receive() {
|
|
1245
|
+
throw new Error('Cannot receive from send-only channel');
|
|
1246
|
+
}
|
|
1247
|
+
receiveWithOk() {
|
|
1248
|
+
throw new Error('Cannot receive from send-only channel');
|
|
1249
|
+
}
|
|
1250
|
+
canReceiveNonBlocking() {
|
|
1251
|
+
return false;
|
|
1252
|
+
}
|
|
1253
|
+
selectReceive(id) {
|
|
1254
|
+
throw new Error('Cannot receive from send-only channel');
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
/**
|
|
1258
|
+
* A receive-only channel reference.
|
|
1259
|
+
*/
|
|
1260
|
+
export class ReceiveOnlyChannelRef {
|
|
1261
|
+
channel;
|
|
1262
|
+
direction = 'receive';
|
|
1263
|
+
constructor(channel) {
|
|
1264
|
+
this.channel = channel;
|
|
1265
|
+
}
|
|
1266
|
+
// Allow receive operations
|
|
1267
|
+
receive() {
|
|
1268
|
+
return this.channel.receive();
|
|
1269
|
+
}
|
|
1270
|
+
receiveWithOk() {
|
|
1271
|
+
return this.channel.receiveWithOk();
|
|
1272
|
+
}
|
|
1273
|
+
canReceiveNonBlocking() {
|
|
1274
|
+
return this.channel.canReceiveNonBlocking();
|
|
1275
|
+
}
|
|
1276
|
+
selectReceive(id) {
|
|
1277
|
+
return this.channel.selectReceive(id);
|
|
1278
|
+
}
|
|
1279
|
+
// Disallow send operations
|
|
1280
|
+
send(value) {
|
|
1281
|
+
throw new Error('Cannot send to receive-only channel');
|
|
1282
|
+
}
|
|
1283
|
+
// Disallow close operations
|
|
1284
|
+
close() {
|
|
1285
|
+
throw new Error('Cannot close receive-only channel');
|
|
1286
|
+
}
|
|
1287
|
+
canSendNonBlocking() {
|
|
1288
|
+
return false;
|
|
1289
|
+
}
|
|
1290
|
+
selectSend(value, id) {
|
|
1291
|
+
throw new Error('Cannot send to receive-only channel');
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
/**
|
|
1295
|
+
* Creates a new channel reference with the specified direction.
|
|
1296
|
+
*/
|
|
1297
|
+
export function makeChannelRef(channel, direction) {
|
|
1298
|
+
switch (direction) {
|
|
1299
|
+
case 'send':
|
|
1300
|
+
return new SendOnlyChannelRef(channel);
|
|
1301
|
+
case 'receive':
|
|
1302
|
+
return new ReceiveOnlyChannelRef(channel);
|
|
1303
|
+
default: // 'both'
|
|
1304
|
+
return new BidirectionalChannelRef(channel);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1127
1307
|
/**
|
|
1128
1308
|
* Helper for 'select' statements. Takes an array of select cases
|
|
1129
1309
|
* and resolves when one of them completes, following Go's select rules.
|
|
@@ -1224,10 +1404,21 @@ export async function selectStatement(cases, hasDefault = false) {
|
|
|
1224
1404
|
* Creates a new channel with the specified buffer size and zero value.
|
|
1225
1405
|
* @param bufferSize The size of the channel buffer. If 0, creates an unbuffered channel.
|
|
1226
1406
|
* @param zeroValue The zero value for the channel's element type.
|
|
1227
|
-
* @
|
|
1407
|
+
* @param direction Optional direction for the channel. Default is 'both' (bidirectional).
|
|
1408
|
+
* @returns A new channel instance or channel reference.
|
|
1228
1409
|
*/
|
|
1229
|
-
export const makeChannel = (bufferSize, zeroValue) => {
|
|
1230
|
-
|
|
1410
|
+
export const makeChannel = (bufferSize, zeroValue, direction = 'both') => {
|
|
1411
|
+
const channel = new BufferedChannel(bufferSize, zeroValue);
|
|
1412
|
+
// Wrap the channel with the appropriate ChannelRef based on direction
|
|
1413
|
+
if (direction === 'send') {
|
|
1414
|
+
return new SendOnlyChannelRef(channel);
|
|
1415
|
+
}
|
|
1416
|
+
else if (direction === 'receive') {
|
|
1417
|
+
return new ReceiveOnlyChannelRef(channel);
|
|
1418
|
+
}
|
|
1419
|
+
else {
|
|
1420
|
+
return channel;
|
|
1421
|
+
}
|
|
1231
1422
|
};
|
|
1232
1423
|
/**
|
|
1233
1424
|
* DisposableStack manages synchronous disposable resources, mimicking Go's defer behavior.
|