@fable-org/fable-library-ts 1.0.0-beta-001
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/Array.ts +1362 -0
- package/Async.ts +207 -0
- package/AsyncBuilder.ts +222 -0
- package/BigInt.ts +337 -0
- package/BitConverter.ts +165 -0
- package/Boolean.ts +22 -0
- package/CHANGELOG.md +15 -0
- package/Char.ts +222 -0
- package/Choice.ts +300 -0
- package/Date.ts +495 -0
- package/DateOffset.ts +324 -0
- package/DateOnly.ts +146 -0
- package/Decimal.ts +250 -0
- package/Double.ts +55 -0
- package/Encoding.ts +170 -0
- package/Event.ts +119 -0
- package/FSharp.Collections.ts +34 -0
- package/FSharp.Core.CompilerServices.ts +37 -0
- package/FSharp.Core.ts +86 -0
- package/Global.ts +37 -0
- package/Guid.ts +143 -0
- package/Int32.ts +156 -0
- package/List.ts +1417 -0
- package/Long.ts +49 -0
- package/MailboxProcessor.ts +125 -0
- package/Map.ts +1552 -0
- package/MapUtil.ts +120 -0
- package/MutableMap.ts +344 -0
- package/MutableSet.ts +248 -0
- package/Native.ts +11 -0
- package/Numeric.ts +80 -0
- package/Observable.ts +156 -0
- package/Option.ts +137 -0
- package/README.md +3 -0
- package/Random.ts +196 -0
- package/Range.ts +56 -0
- package/Reflection.ts +539 -0
- package/RegExp.ts +143 -0
- package/Result.ts +196 -0
- package/Seq.ts +1526 -0
- package/Seq2.ts +129 -0
- package/Set.ts +1955 -0
- package/String.ts +589 -0
- package/System.Collections.Generic.ts +380 -0
- package/System.Text.ts +137 -0
- package/SystemException.ts +7 -0
- package/TimeOnly.ts +131 -0
- package/TimeSpan.ts +194 -0
- package/Timer.ts +80 -0
- package/Types.ts +231 -0
- package/Unicode.13.0.0.ts +4 -0
- package/Uri.ts +206 -0
- package/Util.ts +928 -0
- package/lib/big.d.ts +338 -0
- package/lib/big.js +1054 -0
- package/package.json +24 -0
- package/tsconfig.json +103 -0
package/Async.ts
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { OperationCanceledError, Trampoline } from "./AsyncBuilder.js";
|
|
2
|
+
import { Continuation, Continuations } from "./AsyncBuilder.js";
|
|
3
|
+
import { CancellationToken } from "./AsyncBuilder.js";
|
|
4
|
+
import { IAsync } from "./AsyncBuilder.js";
|
|
5
|
+
import { IAsyncContext } from "./AsyncBuilder.js";
|
|
6
|
+
import { protectedCont } from "./AsyncBuilder.js";
|
|
7
|
+
import { protectedBind } from "./AsyncBuilder.js";
|
|
8
|
+
import { protectedReturn } from "./AsyncBuilder.js";
|
|
9
|
+
import { FSharpChoice$2_$union, Choice_makeChoice1Of2, Choice_makeChoice2Of2 } from "./Choice.js";
|
|
10
|
+
import { TimeoutException } from "./SystemException.js";
|
|
11
|
+
|
|
12
|
+
// Implemented just for type references
|
|
13
|
+
export class Async<_T> { }
|
|
14
|
+
|
|
15
|
+
function emptyContinuation<T>(_x: T) {
|
|
16
|
+
// NOP
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// see AsyncBuilder.Delay
|
|
20
|
+
function delay<T>(generator: () => IAsync<T>) {
|
|
21
|
+
return protectedCont((ctx: IAsyncContext<T>) => generator()(ctx));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// MakeAsync: body:(AsyncActivation<'T> -> AsyncReturn) -> Async<'T>
|
|
25
|
+
export function makeAsync<T>(body: IAsync<T>) {
|
|
26
|
+
return body;
|
|
27
|
+
}
|
|
28
|
+
// Invoke: computation: Async<'T> -> ctxt:AsyncActivation<'T> -> AsyncReturn
|
|
29
|
+
export function invoke<T>(computation: IAsync<T>, ctx: IAsyncContext<T>) {
|
|
30
|
+
return computation(ctx);
|
|
31
|
+
}
|
|
32
|
+
// CallThenInvoke: ctxt:AsyncActivation<'T> -> result1:'U -> part2:('U -> Async<'T>) -> AsyncReturn
|
|
33
|
+
export function callThenInvoke<T, U>(ctx: IAsyncContext<T>, result1: U, part2: (x: U) => IAsync<T>) {
|
|
34
|
+
return part2(result1)(ctx);
|
|
35
|
+
}
|
|
36
|
+
// Bind: ctxt:AsyncActivation<'T> -> part1:Async<'U> -> part2:('U -> Async<'T>) -> AsyncReturn
|
|
37
|
+
export function bind<T, U>(ctx: IAsyncContext<T>, part1: IAsync<U>, part2: (x: U) => IAsync<T>) {
|
|
38
|
+
return protectedBind(part1, part2)(ctx);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function createCancellationToken(arg?: boolean | number): CancellationToken {
|
|
42
|
+
const token = new CancellationToken(typeof arg === "boolean" ? arg : false);
|
|
43
|
+
if (typeof arg === "number") {
|
|
44
|
+
setTimeout(() => { token.cancel(); }, arg);
|
|
45
|
+
}
|
|
46
|
+
return token;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function cancel(token: CancellationToken) {
|
|
50
|
+
token.cancel();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function cancelAfter(token: CancellationToken, ms: number) {
|
|
54
|
+
setTimeout(() => { token.cancel(); }, ms);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function isCancellationRequested(token: CancellationToken) {
|
|
58
|
+
return token != null && token.isCancelled;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function throwIfCancellationRequested(token: CancellationToken) {
|
|
62
|
+
if (token != null && token.isCancelled) {
|
|
63
|
+
throw new Error("Operation is cancelled");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function throwAfter(millisecondsDueTime: number) : IAsync<void> {
|
|
68
|
+
return protectedCont((ctx: IAsyncContext<void>) => {
|
|
69
|
+
let tokenId: number;
|
|
70
|
+
const timeoutId = setTimeout(() => {
|
|
71
|
+
ctx.cancelToken.removeListener(tokenId);
|
|
72
|
+
ctx.onError(new TimeoutException() as Error);
|
|
73
|
+
}, millisecondsDueTime);
|
|
74
|
+
tokenId = ctx.cancelToken.addListener(() => {
|
|
75
|
+
clearTimeout(timeoutId);
|
|
76
|
+
ctx.onCancel(new OperationCanceledError());
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function startChild<T>(computation: IAsync<T>, ms?: number): IAsync<IAsync<T>> {
|
|
82
|
+
if (ms) {
|
|
83
|
+
const computationWithTimeout = protectedBind(
|
|
84
|
+
parallel2(
|
|
85
|
+
computation,
|
|
86
|
+
throwAfter(ms)),
|
|
87
|
+
xs => protectedReturn(xs[0]));
|
|
88
|
+
|
|
89
|
+
return startChild(computationWithTimeout);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const promise = startAsPromise(computation);
|
|
93
|
+
|
|
94
|
+
// JS Promises are hot, computation has already started
|
|
95
|
+
// but we delay returning the result
|
|
96
|
+
return protectedCont((ctx) =>
|
|
97
|
+
protectedReturn(awaitPromise(promise))(ctx));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function awaitPromise<T>(p: Promise<T>) {
|
|
101
|
+
return fromContinuations((conts: Continuations<T>) =>
|
|
102
|
+
p.then(conts[0]).catch((err) =>
|
|
103
|
+
(err instanceof OperationCanceledError
|
|
104
|
+
? conts[2] : conts[1])(err)));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function cancellationToken() {
|
|
108
|
+
return protectedCont((ctx: IAsyncContext<CancellationToken>) => ctx.onSuccess(ctx.cancelToken));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export const defaultCancellationToken = new CancellationToken();
|
|
112
|
+
|
|
113
|
+
export function catchAsync<T>(work: IAsync<T>) {
|
|
114
|
+
return protectedCont((ctx: IAsyncContext<FSharpChoice$2_$union<T, Error>>) => {
|
|
115
|
+
work({
|
|
116
|
+
onSuccess: (x) => ctx.onSuccess(Choice_makeChoice1Of2(x)),
|
|
117
|
+
onError: (ex) => ctx.onSuccess(Choice_makeChoice2Of2(ex)),
|
|
118
|
+
onCancel: ctx.onCancel,
|
|
119
|
+
cancelToken: ctx.cancelToken,
|
|
120
|
+
trampoline: ctx.trampoline,
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function fromContinuations<T>(f: (conts: Continuations<T>) => void) {
|
|
126
|
+
return protectedCont((ctx: IAsyncContext<T>) =>
|
|
127
|
+
f([ctx.onSuccess, ctx.onError, ctx.onCancel]));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function ignore<T>(computation: IAsync<T>) {
|
|
131
|
+
return protectedBind(computation, (_x) => protectedReturn(void 0));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function parallel<T>(computations: Iterable<IAsync<T>>) {
|
|
135
|
+
return delay(() => awaitPromise(Promise.all(Array.from(computations, (w) => startAsPromise(w)))));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function parallel2<T, U>(a: IAsync<T>, b: IAsync<U>): IAsync<[T, U]> {
|
|
139
|
+
return delay(() => awaitPromise(Promise.all([ startAsPromise(a), startAsPromise(b) ])));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function sequential<T>(computations: Iterable<IAsync<T>>) {
|
|
143
|
+
|
|
144
|
+
function _sequential<T>(computations: Iterable<IAsync<T>>): Promise<T[]> {
|
|
145
|
+
let pr: Promise<T[]> = Promise.resolve([]);
|
|
146
|
+
for (const c of computations) {
|
|
147
|
+
pr = pr.then(results => startAsPromise(c).then(r => results.concat([r])))
|
|
148
|
+
}
|
|
149
|
+
return pr;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return delay(() => awaitPromise<T[]>(_sequential<T>(computations)));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function sleep(millisecondsDueTime: number) {
|
|
156
|
+
return protectedCont((ctx: IAsyncContext<void>) => {
|
|
157
|
+
let tokenId: number;
|
|
158
|
+
const timeoutId = setTimeout(() => {
|
|
159
|
+
ctx.cancelToken.removeListener(tokenId);
|
|
160
|
+
ctx.onSuccess(void 0);
|
|
161
|
+
}, millisecondsDueTime);
|
|
162
|
+
tokenId = ctx.cancelToken.addListener(() => {
|
|
163
|
+
clearTimeout(timeoutId);
|
|
164
|
+
ctx.onCancel(new OperationCanceledError());
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function runSynchronously(): never {
|
|
170
|
+
throw new Error("Asynchronous code cannot be run synchronously in JS");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function start<T>(computation: IAsync<T>, cancellationToken?: CancellationToken) {
|
|
174
|
+
return startWithContinuations(computation, cancellationToken);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function startImmediate<T>(computation: IAsync<T>, cancellationToken?: CancellationToken) {
|
|
178
|
+
return start(computation, cancellationToken);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function startWithContinuations<T>(
|
|
182
|
+
computation: IAsync<T>,
|
|
183
|
+
continuation?: Continuation<T> | CancellationToken,
|
|
184
|
+
exceptionContinuation?: Continuation<any>,
|
|
185
|
+
cancellationContinuation?: Continuation<any>,
|
|
186
|
+
cancelToken?: CancellationToken) {
|
|
187
|
+
if (typeof continuation !== "function") {
|
|
188
|
+
cancelToken = continuation as CancellationToken;
|
|
189
|
+
continuation = undefined;
|
|
190
|
+
}
|
|
191
|
+
const trampoline = new Trampoline();
|
|
192
|
+
computation({
|
|
193
|
+
onSuccess: continuation ? continuation as Continuation<T> : emptyContinuation,
|
|
194
|
+
onError: exceptionContinuation ? exceptionContinuation : emptyContinuation,
|
|
195
|
+
onCancel: cancellationContinuation ? cancellationContinuation : emptyContinuation,
|
|
196
|
+
cancelToken: cancelToken ? cancelToken : defaultCancellationToken,
|
|
197
|
+
trampoline,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function startAsPromise<T>(computation: IAsync<T>, cancellationToken?: CancellationToken) {
|
|
202
|
+
return new Promise((resolve: Continuation<T>, reject: Continuation<any>) =>
|
|
203
|
+
startWithContinuations(computation, resolve, reject, reject,
|
|
204
|
+
cancellationToken ? cancellationToken : defaultCancellationToken));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export default Async;
|
package/AsyncBuilder.ts
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { ensureErrorOrException } from './Types.js';
|
|
2
|
+
import { IDisposable } from "./Util.js";
|
|
3
|
+
|
|
4
|
+
export interface AsyncReplyChannel<Reply> {
|
|
5
|
+
reply(value: Reply): void
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type Continuation<T> = (x: T) => void;
|
|
9
|
+
|
|
10
|
+
export type Continuations<T> = [
|
|
11
|
+
Continuation<T>,
|
|
12
|
+
Continuation<Error>,
|
|
13
|
+
Continuation<OperationCanceledError>
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
export class CancellationToken implements IDisposable {
|
|
17
|
+
private _id: number;
|
|
18
|
+
private _cancelled: boolean;
|
|
19
|
+
private _listeners: Map<number, () => void>;
|
|
20
|
+
constructor(cancelled = false) {
|
|
21
|
+
this._id = 0;
|
|
22
|
+
this._cancelled = cancelled;
|
|
23
|
+
this._listeners = new Map();
|
|
24
|
+
}
|
|
25
|
+
get isCancelled() {
|
|
26
|
+
return this._cancelled;
|
|
27
|
+
}
|
|
28
|
+
public cancel() {
|
|
29
|
+
if (!this._cancelled) {
|
|
30
|
+
this._cancelled = true;
|
|
31
|
+
for (const [, listener] of this._listeners) {
|
|
32
|
+
listener();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
public addListener(f: () => void) {
|
|
37
|
+
const id = this._id;
|
|
38
|
+
this._listeners.set(this._id++, f);
|
|
39
|
+
return id;
|
|
40
|
+
}
|
|
41
|
+
public removeListener(id: number) {
|
|
42
|
+
return this._listeners.delete(id);
|
|
43
|
+
}
|
|
44
|
+
public register(f: (state?: any) => void, state?: any) {
|
|
45
|
+
const $ = this;
|
|
46
|
+
const id = this.addListener(state == null ? f : () => f(state));
|
|
47
|
+
return { Dispose() { $.removeListener(id); } };
|
|
48
|
+
}
|
|
49
|
+
public Dispose() {
|
|
50
|
+
// Implement IDisposable for compatibility but do nothing
|
|
51
|
+
// According to docs, calling Dispose does not trigger cancellation
|
|
52
|
+
// https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource.dispose?view=net-6.0
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export class OperationCanceledError extends Error {
|
|
57
|
+
constructor() {
|
|
58
|
+
super("The operation was canceled");
|
|
59
|
+
Object.setPrototypeOf(this, OperationCanceledError.prototype);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export class Trampoline {
|
|
64
|
+
static get maxTrampolineCallCount() {
|
|
65
|
+
return 2000;
|
|
66
|
+
}
|
|
67
|
+
private callCount: number;
|
|
68
|
+
constructor() {
|
|
69
|
+
this.callCount = 0;
|
|
70
|
+
}
|
|
71
|
+
public incrementAndCheck() {
|
|
72
|
+
return this.callCount++ > Trampoline.maxTrampolineCallCount;
|
|
73
|
+
}
|
|
74
|
+
public hijack(f: () => void) {
|
|
75
|
+
this.callCount = 0;
|
|
76
|
+
setTimeout(f, 0);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface IAsyncContext<T> {
|
|
81
|
+
onSuccess: Continuation<T>;
|
|
82
|
+
onError: Continuation<Error>;
|
|
83
|
+
onCancel: Continuation<OperationCanceledError>;
|
|
84
|
+
|
|
85
|
+
cancelToken: CancellationToken;
|
|
86
|
+
trampoline: Trampoline;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type IAsync<T> = (x: IAsyncContext<T>) => void;
|
|
90
|
+
|
|
91
|
+
export function protectedCont<T>(f: IAsync<T>) {
|
|
92
|
+
return (ctx: IAsyncContext<T>) => {
|
|
93
|
+
if (ctx.cancelToken.isCancelled) {
|
|
94
|
+
ctx.onCancel(new OperationCanceledError());
|
|
95
|
+
} else if (ctx.trampoline.incrementAndCheck()) {
|
|
96
|
+
ctx.trampoline.hijack(() => {
|
|
97
|
+
try {
|
|
98
|
+
f(ctx);
|
|
99
|
+
} catch (err) {
|
|
100
|
+
ctx.onError(ensureErrorOrException(err));
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
} else {
|
|
104
|
+
try {
|
|
105
|
+
f(ctx);
|
|
106
|
+
} catch (err) {
|
|
107
|
+
ctx.onError(ensureErrorOrException(err));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function protectedBind<T, U>(computation: IAsync<T>, binder: (x: T) => IAsync<U>) {
|
|
114
|
+
return protectedCont((ctx: IAsyncContext<U>) => {
|
|
115
|
+
computation({
|
|
116
|
+
onSuccess: (x: T) => {
|
|
117
|
+
try {
|
|
118
|
+
binder(x)(ctx);
|
|
119
|
+
} catch (err) {
|
|
120
|
+
ctx.onError(ensureErrorOrException(err));
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
onError: ctx.onError,
|
|
124
|
+
onCancel: ctx.onCancel,
|
|
125
|
+
cancelToken: ctx.cancelToken,
|
|
126
|
+
trampoline: ctx.trampoline,
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function protectedReturn<T>(value: T) {
|
|
132
|
+
return protectedCont((ctx: IAsyncContext<T>) => ctx.onSuccess(value));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export class AsyncBuilder {
|
|
136
|
+
public Bind<T, U>(computation: IAsync<T>, binder: (x: T) => IAsync<U>) {
|
|
137
|
+
return protectedBind(computation, binder);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
public Combine<T>(computation1: IAsync<void>, computation2: IAsync<T>) {
|
|
141
|
+
return this.Bind(computation1, () => computation2);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public Delay<T>(generator: () => IAsync<T>) {
|
|
145
|
+
return protectedCont((ctx: IAsyncContext<T>) => generator()(ctx));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public For<T>(sequence: Iterable<T>, body: (x: T) => IAsync<void>) {
|
|
149
|
+
const iter = sequence[Symbol.iterator]();
|
|
150
|
+
let cur = iter.next();
|
|
151
|
+
return this.While(() => !cur.done, this.Delay(() => {
|
|
152
|
+
const res = body(cur.value);
|
|
153
|
+
cur = iter.next();
|
|
154
|
+
return res;
|
|
155
|
+
}));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
public Return<T>(value?: T) {
|
|
159
|
+
return protectedReturn(value);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
public ReturnFrom<T>(computation: IAsync<T>) {
|
|
163
|
+
return computation;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public TryFinally<T>(computation: IAsync<T>, compensation: () => void) {
|
|
167
|
+
return protectedCont((ctx: IAsyncContext<T>) => {
|
|
168
|
+
computation({
|
|
169
|
+
onSuccess: (x: T) => {
|
|
170
|
+
compensation();
|
|
171
|
+
ctx.onSuccess(x);
|
|
172
|
+
},
|
|
173
|
+
onError: (x: any) => {
|
|
174
|
+
compensation();
|
|
175
|
+
ctx.onError(x);
|
|
176
|
+
},
|
|
177
|
+
onCancel: (x: any) => {
|
|
178
|
+
compensation();
|
|
179
|
+
ctx.onCancel(x);
|
|
180
|
+
},
|
|
181
|
+
cancelToken: ctx.cancelToken,
|
|
182
|
+
trampoline: ctx.trampoline,
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
public TryWith<T>(computation: IAsync<T>, catchHandler: (e: any) => IAsync<T>) {
|
|
188
|
+
return protectedCont((ctx: IAsyncContext<T>) => {
|
|
189
|
+
computation({
|
|
190
|
+
onSuccess: ctx.onSuccess,
|
|
191
|
+
onCancel: ctx.onCancel,
|
|
192
|
+
cancelToken: ctx.cancelToken,
|
|
193
|
+
trampoline: ctx.trampoline,
|
|
194
|
+
onError: (ex: any) => {
|
|
195
|
+
try {
|
|
196
|
+
catchHandler(ex)(ctx);
|
|
197
|
+
} catch (err) {
|
|
198
|
+
ctx.onError(ensureErrorOrException(err));
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
public Using<T extends IDisposable, U>(resource: T, binder: (x: T) => IAsync<U>) {
|
|
206
|
+
return this.TryFinally(binder(resource), () => resource.Dispose());
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
public While(guard: () => boolean, computation: IAsync<void>): IAsync<void> {
|
|
210
|
+
if (guard()) {
|
|
211
|
+
return this.Bind(computation, () => this.While(guard, computation));
|
|
212
|
+
} else {
|
|
213
|
+
return this.Return(void 0);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
public Zero() {
|
|
218
|
+
return protectedCont((ctx: IAsyncContext<void>) => ctx.onSuccess(void 0));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export const singleton = new AsyncBuilder();
|