diff --git a/jsr.json b/jsr.json index 94e5ffa..a26d61e 100644 --- a/jsr.json +++ b/jsr.json @@ -2,16 +2,13 @@ "name": "@ihate-work/ts-commonutil", "version": "0.1.0", "exports": { - "./algebra/monoid": "./src/algebra/monoid.ts", "./algebra/topological-sort": "./src/algebra/topological-sort.ts", - "./algebra/total-ordered": "./src/algebra/total-ordered.ts", - "./binary-conversion/array-buffer": "./src/binary-conversion/array-buffer.ts", - "./binary-conversion/string": "./src/binary-conversion/string.ts", - "./binary-conversion/web": "./src/binary-conversion/web.ts", + "./bytes/array-buffer": "./src/bytes/array-buffer.ts", + "./bytes/string": "./src/bytes/string.ts", + "./bytes/web": "./src/bytes/web.ts", "./collection/btree": "./src/collection/btree.ts", "./collection/default-map": "./src/collection/default-map.ts", "./collection/iterables": "./src/collection/iterables.ts", - "./collection/maps": "./src/collection/maps.ts", "./collection/min-heap": "./src/collection/min-heap.ts", "./collection/multiset": "./src/collection/multiset.ts", "./collection/segment-tree": "./src/collection/segment-tree.ts", @@ -20,17 +17,10 @@ "./concurrency/deferred": "./src/concurrency/deferred.ts", "./concurrency/lazy-thenable": "./src/concurrency/lazy-thenable.ts", "./concurrency/lease": "./src/concurrency/lease.ts", - "./concurrency/lockable": "./src/concurrency/lockable.ts", - "./concurrency/promise-container": "./src/concurrency/promise-container.ts", "./concurrency/resource-pool": "./src/concurrency/resource-pool.ts", "./concurrency/tic-toc": "./src/concurrency/tic-toc.ts", "./concurrency/timing": "./src/concurrency/timing.ts", - "./event-emitter/typed-event-emitter": "./src/event-emitter/typed-event-emitter.ts", "./fp-ts/monoid": "./src/fp-ts/monoid.ts", - "./frontend/dummy-img": "./src/frontend/dummy-img.ts", - "./frontend/fps-observable": "./src/frontend/fps-observable.ts", - "./frontend/measure-img": "./src/frontend/measure-img.ts", - "./frontend/observe-dom-mutation": "./src/frontend/observe-dom-mutation.ts", "./index": "./src/index.ts", "./logging/console-logger": "./src/logging/console-logger.ts", "./logging/get-debug-namespace": "./src/logging/get-debug-namespace.ts", @@ -39,6 +29,8 @@ "./node/fsp": "./src/node/fsp.ts", "./node/index": "./src/node/index.ts", "./node/subprocess": "./src/node/subprocess.ts", + "./random/number": "./src/random/number.ts", + "./random/series": "./src/random/series.ts", "./react/component/font-awesome": "./src/react/component/font-awesome.tsx", "./react/component/inspect-render-count": "./src/react/component/inspect-render-count.tsx", "./react/component/pre-json": "./src/react/component/pre-json.tsx", @@ -54,17 +46,21 @@ "./react/hook/use-promised": "./src/react/hook/use-promised.ts", "./react/hook/use-versioned-memo": "./src/react/hook/use-versioned-memo.ts", "./react/mobx/use-derived": "./src/react/mobx/use-derived.ts", + "./react/mobx/use-mobx-derived": "./src/react/mobx/use-mobx-derived.ts", "./react/util/prop-of": "./src/react/util/prop-of.ts", - "./rxjs/distributions": "./src/rxjs/distributions.ts", - "./rxjs/stochastic-processes": "./src/rxjs/stochastic-processes.ts", + "./rxjs/poisson-observable": "./src/rxjs/poisson-observable.ts", + "./stress/chunk": "./src/stress/chunk.ts", + "./stress/groupBy": "./src/stress/groupBy.ts", + "./stress/sortBy": "./src/stress/sortBy.ts", "./text/chunk-to-lines": "./src/text/chunk-to-lines.ts", "./text/random-string": "./src/text/random-string.ts", "./type/freeze": "./src/type/freeze.ts", "./type/index": "./src/type/index.ts", "./type/omit": "./src/type/omit.ts", - "./util/lru": "./src/util/lru.ts", - "./util/proxys": "./src/util/proxys.ts", - "./util/randoms": "./src/util/randoms.ts", - "./util/with-retry": "./src/util/with-retry.ts" + "./util/with-retry": "./src/util/with-retry.ts", + "./web/dummy-img": "./src/web/dummy-img.ts", + "./web/fps-observable": "./src/web/fps-observable.ts", + "./web/measure-img": "./src/web/measure-img.ts", + "./web/observe-dom-mutation": "./src/web/observe-dom-mutation.ts" } } \ No newline at end of file diff --git a/obsolete/algebra/promise.spec.ts b/obsolete/algebra/promise.spec.ts new file mode 100644 index 0000000..1abda42 --- /dev/null +++ b/obsolete/algebra/promise.spec.ts @@ -0,0 +1,9 @@ +import { liftA2 } from './promise'; + +describe('liftA2', () => { + it('lifts a sync function to promise', async () => { + const liftedPlus = liftA2((a: number, b: number) => a + b); + const sum = await liftedPlus(3, Promise.resolve(5)); + expect(sum).toEqual(8); + }); +}); diff --git a/obsolete/algebra/promise.ts b/obsolete/algebra/promise.ts new file mode 100644 index 0000000..bf2e1cc --- /dev/null +++ b/obsolete/algebra/promise.ts @@ -0,0 +1,13 @@ + +/** + * lift2 f to Promise + */ +export function liftA2(f: (a1: T1, a2: T2) => T3) { + async function transformed(pa1: PromiseLike | T1, pa2: PromiseLike | T2): Promise { + const v1 = await pa1; + const v2 = await pa2; + return Promise.resolve(f(v1, v2)); + } + + return transformed; +} diff --git a/src/concurrency/promise-container.spec.ts b/obsolete/concurrency/promise-container.spec.ts similarity index 96% rename from src/concurrency/promise-container.spec.ts rename to obsolete/concurrency/promise-container.spec.ts index c362604..53de664 100644 --- a/src/concurrency/promise-container.spec.ts +++ b/obsolete/concurrency/promise-container.spec.ts @@ -1,6 +1,6 @@ import { PromiseContainer, PromiseState } from './promise-container'; -import { wait } from './timing'; -import { TicToc } from './tic-toc'; +import { wait } from '../../src/concurrency/timing'; +import { TicToc } from '../../src/concurrency/tic-toc'; describe('promise-container', () => { it('keeps promised value', async () => { diff --git a/src/concurrency/promise-container.ts b/obsolete/concurrency/promise-container.ts similarity index 98% rename from src/concurrency/promise-container.ts rename to obsolete/concurrency/promise-container.ts index c791119..2a4861b 100644 --- a/src/concurrency/promise-container.ts +++ b/obsolete/concurrency/promise-container.ts @@ -1,4 +1,4 @@ -import { Doomed } from './timing'; +import { Doomed } from '../../src/concurrency/timing'; export enum PromiseState { pending = 'pending', diff --git a/obsolete/node/read-stream.ts b/obsolete/node/read-stream.ts new file mode 100644 index 0000000..f253f7b --- /dev/null +++ b/obsolete/node/read-stream.ts @@ -0,0 +1,22 @@ +/** + * Read stream until end + * @deprecated use 'node:stream/consumers' instead. + * @see https://nodejs.org/api/webstreams.html#streamconsumersjsonstream + */ +export function readStream(stream: NodeJS.ReadableStream | NodeJS.ReadStream): Promise { + return new Promise((resolve, reject) => { + const buffers = [] as Buffer[]; + + stream.once('end', () => resolve(Buffer.concat(buffers))); + + stream.on('error', reject); + + stream.on('data', (chunk: string | Buffer) => { + if (Buffer.isBuffer(chunk)) { + buffers.push(chunk); + } /* (typeof chunk === "string") */ else { + buffers.push(Buffer.from(chunk)); + } + }); + }); +} diff --git a/package.json b/package.json index 0b90cf5..169c8d2 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "fp-ts": "^2", "gts": "^5.2.0", "jest": "^29", + "jsr": "^0.12.4", "loglevel": "^1.8.0", "mobx": "^6.6.1", "react": "^18.2.0", @@ -57,35 +58,25 @@ "winston": "^3.8.0" }, "exports": { - "./lib/algebra/monoid": { - "import": "./lib/__esm/algebra/monoid.js", - "require": "./lib/algebra/monoid.js", - "type": "./lib/algebra/monoid.d.ts" - }, "./lib/algebra/topological-sort": { "import": "./lib/__esm/algebra/topological-sort.js", "require": "./lib/algebra/topological-sort.js", "type": "./lib/algebra/topological-sort.d.ts" }, - "./lib/algebra/total-ordered": { - "import": "./lib/__esm/algebra/total-ordered.js", - "require": "./lib/algebra/total-ordered.js", - "type": "./lib/algebra/total-ordered.d.ts" - }, - "./lib/binary-conversion/array-buffer": { - "import": "./lib/__esm/binary-conversion/array-buffer.js", - "require": "./lib/binary-conversion/array-buffer.js", - "type": "./lib/binary-conversion/array-buffer.d.ts" + "./lib/bytes/array-buffer": { + "import": "./lib/__esm/bytes/array-buffer.js", + "require": "./lib/bytes/array-buffer.js", + "type": "./lib/bytes/array-buffer.d.ts" }, - "./lib/binary-conversion/string": { - "import": "./lib/__esm/binary-conversion/string.js", - "require": "./lib/binary-conversion/string.js", - "type": "./lib/binary-conversion/string.d.ts" + "./lib/bytes/string": { + "import": "./lib/__esm/bytes/string.js", + "require": "./lib/bytes/string.js", + "type": "./lib/bytes/string.d.ts" }, - "./lib/binary-conversion/web": { - "import": "./lib/__esm/binary-conversion/web.js", - "require": "./lib/binary-conversion/web.js", - "type": "./lib/binary-conversion/web.d.ts" + "./lib/bytes/web": { + "import": "./lib/__esm/bytes/web.js", + "require": "./lib/bytes/web.js", + "type": "./lib/bytes/web.d.ts" }, "./lib/collection/btree": { "import": "./lib/__esm/collection/btree.js", @@ -102,11 +93,6 @@ "require": "./lib/collection/iterables.js", "type": "./lib/collection/iterables.d.ts" }, - "./lib/collection/maps": { - "import": "./lib/__esm/collection/maps.js", - "require": "./lib/collection/maps.js", - "type": "./lib/collection/maps.d.ts" - }, "./lib/collection/min-heap": { "import": "./lib/__esm/collection/min-heap.js", "require": "./lib/collection/min-heap.js", @@ -147,16 +133,6 @@ "require": "./lib/concurrency/lease.js", "type": "./lib/concurrency/lease.d.ts" }, - "./lib/concurrency/lockable": { - "import": "./lib/__esm/concurrency/lockable.js", - "require": "./lib/concurrency/lockable.js", - "type": "./lib/concurrency/lockable.d.ts" - }, - "./lib/concurrency/promise-container": { - "import": "./lib/__esm/concurrency/promise-container.js", - "require": "./lib/concurrency/promise-container.js", - "type": "./lib/concurrency/promise-container.d.ts" - }, "./lib/concurrency/resource-pool": { "import": "./lib/__esm/concurrency/resource-pool.js", "require": "./lib/concurrency/resource-pool.js", @@ -172,36 +148,11 @@ "require": "./lib/concurrency/timing.js", "type": "./lib/concurrency/timing.d.ts" }, - "./lib/event-emitter/typed-event-emitter": { - "import": "./lib/__esm/event-emitter/typed-event-emitter.js", - "require": "./lib/event-emitter/typed-event-emitter.js", - "type": "./lib/event-emitter/typed-event-emitter.d.ts" - }, "./lib/fp-ts/monoid": { "import": "./lib/__esm/fp-ts/monoid.js", "require": "./lib/fp-ts/monoid.js", "type": "./lib/fp-ts/monoid.d.ts" }, - "./lib/frontend/dummy-img": { - "import": "./lib/__esm/frontend/dummy-img.js", - "require": "./lib/frontend/dummy-img.js", - "type": "./lib/frontend/dummy-img.d.ts" - }, - "./lib/frontend/fps-observable": { - "import": "./lib/__esm/frontend/fps-observable.js", - "require": "./lib/frontend/fps-observable.js", - "type": "./lib/frontend/fps-observable.d.ts" - }, - "./lib/frontend/measure-img": { - "import": "./lib/__esm/frontend/measure-img.js", - "require": "./lib/frontend/measure-img.js", - "type": "./lib/frontend/measure-img.d.ts" - }, - "./lib/frontend/observe-dom-mutation": { - "import": "./lib/__esm/frontend/observe-dom-mutation.js", - "require": "./lib/frontend/observe-dom-mutation.js", - "type": "./lib/frontend/observe-dom-mutation.d.ts" - }, "./lib/index": { "import": "./lib/__esm/index.js", "require": "./lib/index.js", @@ -242,6 +193,16 @@ "require": "./lib/node/subprocess.js", "type": "./lib/node/subprocess.d.ts" }, + "./lib/random/number": { + "import": "./lib/__esm/random/number.js", + "require": "./lib/random/number.js", + "type": "./lib/random/number.d.ts" + }, + "./lib/random/series": { + "import": "./lib/__esm/random/series.js", + "require": "./lib/random/series.js", + "type": "./lib/random/series.d.ts" + }, "./lib/react/component/font-awesome": { "import": "./lib/__esm/react/component/font-awesome.jsx", "require": "./lib/react/component/font-awesome.jsx", @@ -317,20 +278,35 @@ "require": "./lib/react/mobx/use-derived.js", "type": "./lib/react/mobx/use-derived.d.ts" }, + "./lib/react/mobx/use-mobx-derived": { + "import": "./lib/__esm/react/mobx/use-mobx-derived.js", + "require": "./lib/react/mobx/use-mobx-derived.js", + "type": "./lib/react/mobx/use-mobx-derived.d.ts" + }, "./lib/react/util/prop-of": { "import": "./lib/__esm/react/util/prop-of.js", "require": "./lib/react/util/prop-of.js", "type": "./lib/react/util/prop-of.d.ts" }, - "./lib/rxjs/distributions": { - "import": "./lib/__esm/rxjs/distributions.js", - "require": "./lib/rxjs/distributions.js", - "type": "./lib/rxjs/distributions.d.ts" + "./lib/rxjs/poisson-observable": { + "import": "./lib/__esm/rxjs/poisson-observable.js", + "require": "./lib/rxjs/poisson-observable.js", + "type": "./lib/rxjs/poisson-observable.d.ts" + }, + "./lib/stress/chunk": { + "import": "./lib/__esm/stress/chunk.js", + "require": "./lib/stress/chunk.js", + "type": "./lib/stress/chunk.d.ts" + }, + "./lib/stress/groupBy": { + "import": "./lib/__esm/stress/groupBy.js", + "require": "./lib/stress/groupBy.js", + "type": "./lib/stress/groupBy.d.ts" }, - "./lib/rxjs/stochastic-processes": { - "import": "./lib/__esm/rxjs/stochastic-processes.js", - "require": "./lib/rxjs/stochastic-processes.js", - "type": "./lib/rxjs/stochastic-processes.d.ts" + "./lib/stress/sortBy": { + "import": "./lib/__esm/stress/sortBy.js", + "require": "./lib/stress/sortBy.js", + "type": "./lib/stress/sortBy.d.ts" }, "./lib/text/chunk-to-lines": { "import": "./lib/__esm/text/chunk-to-lines.js", @@ -357,29 +333,34 @@ "require": "./lib/type/omit.js", "type": "./lib/type/omit.d.ts" }, - "./lib/util/lru": { - "import": "./lib/__esm/util/lru.js", - "require": "./lib/util/lru.js", - "type": "./lib/util/lru.d.ts" - }, - "./lib/util/proxys": { - "import": "./lib/__esm/util/proxys.js", - "require": "./lib/util/proxys.js", - "type": "./lib/util/proxys.d.ts" - }, - "./lib/util/randoms": { - "import": "./lib/__esm/util/randoms.js", - "require": "./lib/util/randoms.js", - "type": "./lib/util/randoms.d.ts" - }, "./lib/util/with-retry": { "import": "./lib/__esm/util/with-retry.js", "require": "./lib/util/with-retry.js", "type": "./lib/util/with-retry.d.ts" + }, + "./lib/web/dummy-img": { + "import": "./lib/__esm/web/dummy-img.js", + "require": "./lib/web/dummy-img.js", + "type": "./lib/web/dummy-img.d.ts" + }, + "./lib/web/fps-observable": { + "import": "./lib/__esm/web/fps-observable.js", + "require": "./lib/web/fps-observable.js", + "type": "./lib/web/fps-observable.d.ts" + }, + "./lib/web/measure-img": { + "import": "./lib/__esm/web/measure-img.js", + "require": "./lib/web/measure-img.js", + "type": "./lib/web/measure-img.d.ts" + }, + "./lib/web/observe-dom-mutation": { + "import": "./lib/__esm/web/observe-dom-mutation.js", + "require": "./lib/web/observe-dom-mutation.js", + "type": "./lib/web/observe-dom-mutation.d.ts" } }, "resolutions": { "@types/node": "18", "@types/react": "^18" } -} \ No newline at end of file +} diff --git a/src/binary-conversion/array-buffer.ts b/src/bytes/array-buffer.ts similarity index 100% rename from src/binary-conversion/array-buffer.ts rename to src/bytes/array-buffer.ts diff --git a/src/binary-conversion/string.ts b/src/bytes/string.ts similarity index 100% rename from src/binary-conversion/string.ts rename to src/bytes/string.ts diff --git a/src/binary-conversion/web.ts b/src/bytes/web.ts similarity index 100% rename from src/binary-conversion/web.ts rename to src/bytes/web.ts diff --git a/src/concurrency/deferred.ts b/src/concurrency/deferred.ts index 0e4f4ff..65043a7 100644 --- a/src/concurrency/deferred.ts +++ b/src/concurrency/deferred.ts @@ -19,7 +19,7 @@ export class Deferred implements PromiseLike { return d; } - private readonly _promise = new Promise((fulfill, reject) => { + readonly #promise = new Promise((fulfill, reject) => { this.#fulfill = (v: T | PromiseLike) => { fulfill(v); this.#resolved = true; @@ -38,7 +38,7 @@ export class Deferred implements PromiseLike { return this.#resolved; } - readonly then = this._promise.then.bind(this._promise); + readonly then = this.#promise.then.bind(this.#promise); /** * @param v the value diff --git a/src/concurrency/lockable.ts b/src/concurrency/lockable.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/node/fsp.ts b/src/node/fsp.ts index e04cc55..9ed8fc9 100644 --- a/src/node/fsp.ts +++ b/src/node/fsp.ts @@ -1,4 +1,4 @@ -import { promises as fsPromised } from 'fs'; +import fsPromised from 'node:fs/promises'; import { chunkToLines } from '../text/chunk-to-lines'; export const readText = (filename: string, encoding: BufferEncoding = 'utf-8'): Promise => diff --git a/src/node/index.ts b/src/node/index.ts index a97ee58..81dc3d3 100644 --- a/src/node/index.ts +++ b/src/node/index.ts @@ -1,29 +1,3 @@ -/** - * Read stream until end - * @deprecated use 'node:stream/consumers' instead. - * @see https://nodejs.org/api/webstreams.html#streamconsumersjsonstream - */ -export function readStream(stream: NodeJS.ReadableStream): Promise { - return new Promise((resolve, reject) => { - const buffers = [] as Buffer[]; - - stream.once('end', () => resolve(Buffer.concat(buffers))); - - stream.on('error', reject); - - stream.on('data', (chunk: string | Buffer) => { - if (Buffer.isBuffer(chunk)) { - buffers.push(chunk); - } /* (typeof chunk === "string") */ else { - buffers.push(Buffer.from(chunk)); - } - }); - }); -} - -/** - * @deprecated use 'node:fs/promises' instead. - */ import * as fsp from './fsp'; export { fsp }; diff --git a/src/random/number.ts b/src/random/number.ts new file mode 100644 index 0000000..535abd8 --- /dev/null +++ b/src/random/number.ts @@ -0,0 +1,30 @@ +export const defaultRng = Math.random; + +function sample(from: ReadonlyArray, count: number, rng = defaultRng): T[] { + const sampled: T[] = from.slice(0, count); // 'reservoir' + + for (let i = count; i < from.length; i++) { + const j = Math.floor(1 + Math.random() * i); + if (j < count) { + sampled[j] = from[i]; + } + } + + return sampled; +} + +export function binomialRandom(n: number, p: number, rng = defaultRng): number { + let s = 0; + for (let sample = 0; sample < n; ++sample) { + if (rng() <= p) ++s; + } + return s; +} + +export function gaussianRandom(rng = defaultRng): number { + const u1 = rng(), + u2 = rng(); + + // basic form of Box-Muller transform + return Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2); +} diff --git a/src/random/series.ts b/src/random/series.ts new file mode 100644 index 0000000..4f9e1a3 --- /dev/null +++ b/src/random/series.ts @@ -0,0 +1,14 @@ +import { defaultRng, gaussianRandom } from './number'; + +export function* bernoulliSeries(p: number, rng = defaultRng): Generator { + while (true) yield rng() < p; +} + +export function* wienerSeries(dt: number, rng = defaultRng): Generator { + let sum = 0; + yield sum; + while (true) { + const d = Math.sqrt(dt) * gaussianRandom(rng); + yield (sum += d); + } +} diff --git a/src/react/component/inspect-render-count.tsx b/src/react/component/inspect-render-count.tsx index 54c5731..d8eb3e6 100644 --- a/src/react/component/inspect-render-count.tsx +++ b/src/react/component/inspect-render-count.tsx @@ -6,7 +6,7 @@ import { MutationCounts, resolveHTMLElement, startObserve, -} from '../../frontend/observe-dom-mutation'; +} from '../../web/observe-dom-mutation'; export const RenderCountsToWidget: React.FC = (counter) => ( <> diff --git a/src/react/component/pre-json.tsx b/src/react/component/pre-json.tsx index 531568b..fdb8d76 100644 --- a/src/react/component/pre-json.tsx +++ b/src/react/component/pre-json.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import type React from 'react'; export const PreJson: React.FunctionComponent<{ value: any }> = ({ value }) => { return
{JSON.stringify(value, null, 2)}
; diff --git a/src/react/hook/use-fps.ts b/src/react/hook/use-fps.ts index 41d6b54..6fa67c1 100644 --- a/src/react/hook/use-fps.ts +++ b/src/react/hook/use-fps.ts @@ -1,5 +1,5 @@ import { useMemo } from 'react'; -import { createFpsObservable } from '../../frontend/fps-observable'; +import { createFpsObservable } from '../../web/fps-observable'; import { useExternalObservable } from './use-observable-store'; export function useFps(windowSize: number): number { diff --git a/src/react/hook/use-observable-store.ts b/src/react/hook/use-observable-store.ts index 122b329..f8924b0 100644 --- a/src/react/hook/use-observable-store.ts +++ b/src/react/hook/use-observable-store.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs'; +import type { Observable } from 'rxjs'; import { useDeferredValue, useEffect, useRef, useState, useSyncExternalStore, useTransition } from 'react'; export function useExternalObservable(observable: Observable, defaultValue: T): T { diff --git a/src/react/util/prop-of.ts b/src/react/util/prop-of.ts index d820742..81f4be2 100644 --- a/src/react/util/prop-of.ts +++ b/src/react/util/prop-of.ts @@ -1,3 +1,3 @@ import * as React from 'react'; -export type PropOf> = T extends React.ComponentType ? P : never; +export type PropOf> = T extends React.ComponentType ? P : unknown; diff --git a/src/rxjs/distributions.ts b/src/rxjs/distributions.ts deleted file mode 100644 index 7508967..0000000 --- a/src/rxjs/distributions.ts +++ /dev/null @@ -1,15 +0,0 @@ -export function binomialRandom(n: number, p: number): number { - let s = 0; - for (let sample = 0; sample < n; ++sample) { - if (Math.random() <= p) ++s; - } - return s; -} - -export function gaussianRandom(): number { - const u1 = Math.random(), - u2 = Math.random(); - - // basic form of Box-Muller transform - return Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2); -} diff --git a/src/rxjs/poisson-observable.ts b/src/rxjs/poisson-observable.ts new file mode 100644 index 0000000..a429e7f --- /dev/null +++ b/src/rxjs/poisson-observable.ts @@ -0,0 +1,31 @@ +import { Observable, Subscriber } from 'rxjs'; +import { wait } from '../concurrency/timing'; +import { defaultRng } from '../random/number'; + +/** + * @param {number} lambda expected occurrence rate in {@code $ s^{-1} $ } + * @param rng random number generator + * @returns A cold observable that emits 0-based integers, at Poissonic random interval + */ +export function poissonObservable(lambda = 1, rng = defaultRng): Observable { + return new Observable((subscriber) => { + setTimeout(() => postPoissonEvents(subscriber, lambda, () => subscriber.closed)); + }); +} +/** + * @internal + */ +async function postPoissonEvents( + subscriber: Subscriber, + lambda: number, + shouldStop: () => boolean, + rng = defaultRng, +): Promise { + let eventNo = 0; + while (true) { + const poissonDelay = (-1 / lambda) * Math.log(rng()) * 1e3; + await wait(poissonDelay); + if (shouldStop()) break; + subscriber.next(eventNo++); + } +} diff --git a/src/rxjs/stochastic-processes.ts b/src/rxjs/stochastic-processes.ts deleted file mode 100644 index f9b5067..0000000 --- a/src/rxjs/stochastic-processes.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Observable, from, Subscriber } from 'rxjs'; -import { gaussianRandom } from './distributions'; -import { wait } from '../concurrency/timing'; - -export function bernoulli(p: number): Observable { - return from(bernoulliIterator(p)); -} - -/** - * @internal - * @param p - */ -function* bernoulliIterator(p: number) { - while (true) yield Math.random() < p; -} - -/** - * @internal - * @param dt - */ -export function wiener(dt = 1): Observable { - return from(wienerIterator(dt)); -} - -function* wienerIterator(dt: number) { - let sum = 0; - yield sum; - while (true) { - const d = Math.sqrt(dt) * gaussianRandom(); - yield (sum += d); - } -} - -/** - * @param {number} lambda expected occurrence rate in {@code $ s^{-1} $ } - * @returns {Observable} A observable that emits 0-based integers at Poissonic random interval - */ -export function poisson(lambda = 1): Observable { - return new Observable((subscriber) => { - setTimeout(() => postPoissonEvents(subscriber, lambda, () => subscriber.closed)); - }); -} - -/** - * @internal - */ -async function postPoissonEvents( - subscriber: Subscriber, - lambda: number, - shouldStop: () => boolean, -): Promise { - let eventNo = 0; - while (true) { - const poissonDelay = (-1 / lambda) * Math.log(Math.random()) * 1e3; - await wait(poissonDelay); - if (shouldStop()) break; - subscriber.next(eventNo++); - } -} diff --git a/src/type/index.ts b/src/type/index.ts index ef184bf..7bd710a 100644 --- a/src/type/index.ts +++ b/src/type/index.ts @@ -2,16 +2,3 @@ * Type transformers and etc */ export * from './freeze'; - -/** - * lift2 f to Promise - */ -export function liftA2(f: (a1: T1, a2: T2) => T3) { - async function transformed(pa1: PromiseLike | T1, pa2: PromiseLike | T2): Promise { - const v1 = await pa1; - const v2 = await pa2; - return Promise.resolve(f(v1, v2)); - } - - return transformed; -} diff --git a/src/type/type.spec.ts b/src/type/type.spec.ts deleted file mode 100644 index 7de1ee9..0000000 --- a/src/type/type.spec.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { liftA2 } from './index'; - -describe('liftA2', () => { - it('lifts a sync function to promise', async () => { - const liftedPlus = liftA2((a: number, b: number) => a + b); - const sum = await liftedPlus(3, Promise.resolve(5)); - expect(sum).toEqual(8); - }); -}); diff --git a/src/util/proxys.ts b/src/util/proxys.ts deleted file mode 100644 index 3eef599..0000000 --- a/src/util/proxys.ts +++ /dev/null @@ -1,8 +0,0 @@ -export const Proxies = { - // eslint-disable-next-line @typescript-eslint/ban-types - revoked(): T { - const { proxy, revoke } = Proxy.revocable({} as any, {}); - revoke(); - return proxy; - }, -} as const; diff --git a/src/util/randoms.ts b/src/util/randoms.ts deleted file mode 100644 index df621d0..0000000 --- a/src/util/randoms.ts +++ /dev/null @@ -1,12 +0,0 @@ -function sample(from: ReadonlyArray, count: number): T[] { - const sampled: T[] = from.slice(0, count); // 'reservoir' - - for (let i = count; i < from.length; i++) { - const j = Math.floor(1 + Math.random() * i); - if (j < count) { - sampled[j] = from[i]; - } - } - - return sampled; -} diff --git a/src/frontend/dummy-img.ts b/src/web/dummy-img.ts similarity index 100% rename from src/frontend/dummy-img.ts rename to src/web/dummy-img.ts diff --git a/src/frontend/fps-observable.ts b/src/web/fps-observable.ts similarity index 100% rename from src/frontend/fps-observable.ts rename to src/web/fps-observable.ts diff --git a/src/frontend/measure-img.ts b/src/web/measure-img.ts similarity index 100% rename from src/frontend/measure-img.ts rename to src/web/measure-img.ts diff --git a/src/frontend/observe-dom-mutation.ts b/src/web/observe-dom-mutation.ts similarity index 100% rename from src/frontend/observe-dom-mutation.ts rename to src/web/observe-dom-mutation.ts diff --git a/yarn.lock b/yarn.lock index 06e61c8..9b52c24 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2430,6 +2430,15 @@ json5@^2.1.3, json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +jsr@^0.12.4: + version "0.12.4" + resolved "https://registry.yarnpkg.com/jsr/-/jsr-0.12.4.tgz#f353cf10f9dadf147528c7be56bf38db51536b69" + integrity sha512-ZWDvqQE8014fWz9QBrkiuvRQ8mH97PRD13VIDzoMXDem3ff2S+wfXw+YAvrZE0aKzxh9FuHJX0HQRQ2MUHshig== + dependencies: + kolorist "^1.8.0" + node-stream-zip "^1.15.0" + semiver "^1.1.0" + keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -2447,6 +2456,11 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +kolorist@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c" + integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== + kuler@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" @@ -2673,6 +2687,11 @@ node-releases@^2.0.14: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +node-stream-zip@^1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/node-stream-zip/-/node-stream-zip-1.15.0.tgz#158adb88ed8004c6c49a396b50a6a5de3bca33ea" + integrity sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw== + normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -3059,6 +3078,11 @@ scheduler@^0.23.0: dependencies: loose-envify "^1.1.0" +semiver@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/semiver/-/semiver-1.1.0.tgz#9c97fb02c21c7ce4fcf1b73e2c7a24324bdddd5f" + integrity sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg== + "semver@2 || 3 || 4 || 5": version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"