-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Start generator runner * Update run * Start async generator * Update run * Fix blocking in async generator * Add test * Remove todo * Fix function return type * Remove unused import * Simplify runAsync * Remove unnecessary transforms * Add wrapper methods * Fix tests * Add docs * Add benchmark script * Remove unnecessary helper function
- Loading branch information
Showing
15 changed files
with
553 additions
and
187 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import {Err, Ok, asyncFn, asyncGenFn} from "../src" | ||
import {performance} from "perf_hooks" | ||
|
||
const getOne = asyncFn(async () => Ok(1)) | ||
|
||
function formatTime(ms: number) { | ||
return `${ms.toFixed(5)}ms` | ||
} | ||
|
||
const a = asyncFn(async () => { | ||
const one = await getOne() | ||
if (one.isErr) { | ||
return one | ||
} | ||
const rand = Math.random() | ||
if (Math.random() < 0.5) { | ||
return Err("error") | ||
} | ||
return Ok(rand + one.value) | ||
}) | ||
|
||
const b = asyncGenFn(async function* () { | ||
const one = yield* getOne() | ||
const rand = Math.random() | ||
if (Math.random() < 0.5) { | ||
yield* Err("error") | ||
} | ||
return rand + one | ||
}) | ||
|
||
const iterations = 10_000_000 | ||
|
||
async function main() { | ||
console.log("iterations:", iterations) | ||
|
||
let start = performance.now() | ||
for (let i = 0; i < iterations; i++) { | ||
await a() | ||
} | ||
let end = performance.now() | ||
const asyncDiff = end - start | ||
const oneAsyncDiff = asyncDiff / iterations | ||
console.log("asyncFn:", formatTime(oneAsyncDiff)) | ||
|
||
start = performance.now() | ||
for (let i = 0; i < iterations; i++) { | ||
await b() | ||
} | ||
end = performance.now() | ||
const asyncGenDiff = end - start | ||
const oneAsyncGenDiff = asyncGenDiff / iterations | ||
console.log("asyncGenFn:", formatTime(oneAsyncGenDiff)) | ||
|
||
console.log("difference:", formatTime(oneAsyncGenDiff - oneAsyncDiff)) | ||
console.log("ratio:", (oneAsyncGenDiff / oneAsyncDiff).toFixed(2)) | ||
} | ||
|
||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import {ResultPromise} from "./result_promise" | ||
import {type Result, Ok, ResultImpl} from "./result" | ||
import type {InferErr} from "./util" | ||
|
||
function _run<T extends Result<any, any>, U>( | ||
fn: () => Generator<T, U, any>, | ||
): Result<U, InferErr<T>> { | ||
const gen = fn() | ||
let done = false | ||
let returnResult = Ok() | ||
while (!done) { | ||
const iter = gen.next(returnResult.unwrap()) | ||
if (iter.value instanceof ResultImpl) { | ||
if (iter.value.isErr) { | ||
done = true | ||
gen.return?.(iter.value as any) | ||
} | ||
returnResult = iter.value as any | ||
} else { | ||
done = true | ||
returnResult = Ok(iter.value) as any | ||
} | ||
} | ||
return returnResult as any | ||
} | ||
|
||
/** | ||
* Runs a generator function that returns a `Result` and infers its return type as `Result<T, E>`. | ||
* | ||
* `yield*` must be used to yield the result of a `Result`. | ||
* | ||
* **Examples** | ||
* | ||
* ```ts | ||
* // $ExpectType Result<number, string> | ||
* const result = run(function* () { | ||
* const a = yield* Ok(1) | ||
* const random = Math.random() | ||
* if (random > 0.5) { | ||
* yield* Err("error") | ||
* } | ||
* return a + random | ||
* }) | ||
* ``` | ||
*/ | ||
export function run<T extends Result<any, any>, U>(fn: () => Generator<T, U, any>) { | ||
// Variable assignment helps with type inference | ||
const result = _run(fn) | ||
return result | ||
} | ||
|
||
async function toPromiseResult<T, E>(value: any): Promise<Result<T, E>> { | ||
const awaited = await value | ||
if (value instanceof ResultImpl) { | ||
return awaited as any | ||
} | ||
return Ok(awaited) | ||
} | ||
|
||
function _runAsync<T extends ResultPromise<any, any> | Result<any, any>, U>( | ||
fn: () => AsyncGenerator<T, U, any>, | ||
): ResultPromise<U, InferErr<Awaited<T>>> { | ||
const gen = fn() | ||
const yieldedResultChain = Promise.resolve<Result<any, any>>(Ok()).then( | ||
async function fulfill(nextResult): Promise<Result<any, any>> { | ||
const iter = await gen.next(nextResult.unwrap()) | ||
const result = await toPromiseResult(iter.value) | ||
if (iter.done) { | ||
return result | ||
} | ||
if (result.isErr) { | ||
gen.return?.(iter.value as any) | ||
return result | ||
} | ||
return Promise.resolve(result).then(fulfill) | ||
}, | ||
) | ||
return new ResultPromise(yieldedResultChain) | ||
} | ||
|
||
/** | ||
* Runs an async generator function that returns a `Result` and infers its return type as `ResultPromise<T, E>`. | ||
* | ||
* `yield*` must be used to yield the result of a `ResultPromise` or `Result`. | ||
* | ||
* **Examples** | ||
* | ||
* ```ts | ||
* const okOne = () => new ResultPromise(Promise.resolve(Ok(1))) | ||
* | ||
* // $ExpectType ResultPromise<number, string> | ||
* const result = runAsync(async function* () { | ||
* const a = yield* okOne() | ||
* const random = Math.random() | ||
* if (random > 0.5) { | ||
* yield* Err("error") | ||
* } | ||
* return a + random | ||
* }) | ||
* ``` | ||
*/ | ||
export function runAsync<T extends ResultPromise<any, any> | Result<any, any>, U>( | ||
fn: () => AsyncGenerator<T, U, any>, | ||
) { | ||
// Variable assignment helps with type inference | ||
const result = _runAsync(fn) | ||
return result | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.