Skip to content

Commit dae6009

Browse files
refactor(defmulti): split into separate files
1 parent cff9e30 commit dae6009

File tree

5 files changed

+624
-606
lines changed

5 files changed

+624
-606
lines changed

packages/defmulti/src/api.ts

+305
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
import {
2+
Fn,
3+
Fn2,
4+
Fn3,
5+
Fn4,
6+
Fn5,
7+
Fn6,
8+
Fn7,
9+
Fn8,
10+
FnAny,
11+
IObjectOf
12+
} from "@thi.ng/api";
13+
14+
export const DEFAULT: unique symbol = Symbol();
15+
16+
export type DispatchFn = FnAny<PropertyKey>;
17+
export type DispatchFn1<A> = Fn<A, PropertyKey>;
18+
export type DispatchFn1O<A, B> = (a: A, b?: B) => PropertyKey;
19+
export type DispatchFn2<A, B> = Fn2<A, B, PropertyKey>;
20+
export type DispatchFn2O<A, B, C> = (a: A, b: B, c?: C) => PropertyKey;
21+
export type DispatchFn3<A, B, C> = Fn3<A, B, C, PropertyKey>;
22+
export type DispatchFn3O<A, B, C, D> = (a: A, b: B, c: C, d?: D) => PropertyKey;
23+
export type DispatchFn4<A, B, C, D> = Fn4<A, B, C, D, PropertyKey>;
24+
export type DispatchFn4O<A, B, C, D, E> = (
25+
a: A,
26+
b: B,
27+
c: C,
28+
d: D,
29+
e?: E
30+
) => PropertyKey;
31+
export type DispatchFn5<A, B, C, D, E> = Fn5<A, B, C, D, E, PropertyKey>;
32+
export type DispatchFn5O<A, B, C, D, E, F> = (
33+
a: A,
34+
b: B,
35+
c: C,
36+
d: D,
37+
e: E,
38+
f?: F
39+
) => PropertyKey;
40+
export type DispatchFn6<A, B, C, D, E, F> = Fn6<A, B, C, D, E, F, PropertyKey>;
41+
export type DispatchFn6O<A, B, C, D, E, F, G> = (
42+
a: A,
43+
b: B,
44+
c: C,
45+
d: D,
46+
e: E,
47+
f: F,
48+
g?: G
49+
) => PropertyKey;
50+
export type DispatchFn7<A, B, C, D, E, F, G> = Fn7<
51+
A,
52+
B,
53+
C,
54+
D,
55+
E,
56+
F,
57+
G,
58+
PropertyKey
59+
>;
60+
export type DispatchFn7O<A, B, C, D, E, F, G, H> = (
61+
a: A,
62+
b: B,
63+
c: C,
64+
d: D,
65+
e: E,
66+
f: F,
67+
g: G,
68+
h?: H
69+
) => PropertyKey;
70+
export type DispatchFn8<A, B, C, D, E, F, G, H> = Fn8<
71+
A,
72+
B,
73+
C,
74+
D,
75+
E,
76+
F,
77+
G,
78+
H,
79+
PropertyKey
80+
>;
81+
export type DispatchFn8O<A, B, C, D, E, F, G, H, I> = (
82+
a: A,
83+
b: B,
84+
c: C,
85+
d: D,
86+
e: E,
87+
f: F,
88+
g: G,
89+
h: H,
90+
i?: I
91+
) => PropertyKey;
92+
93+
export type Implementation<T> = FnAny<T>;
94+
export type Implementation1<A, T> = Fn<A, T>;
95+
export type Implementation1O<A, B, T> = (a: A, b?: B) => T;
96+
export type Implementation2<A, B, T> = Fn2<A, B, T>;
97+
export type Implementation2O<A, B, C, T> = (a: A, b: B, c?: C) => T;
98+
export type Implementation3<A, B, C, T> = Fn3<A, B, C, T>;
99+
export type Implementation3O<A, B, C, D, T> = (a: A, b: B, c: C, d?: D) => T;
100+
export type Implementation4<A, B, C, D, T> = Fn4<A, B, C, D, T>;
101+
export type Implementation4O<A, B, C, D, E, T> = (
102+
a: A,
103+
b: B,
104+
c: C,
105+
d: D,
106+
e?: E
107+
) => T;
108+
export type Implementation5<A, B, C, D, E, T> = Fn5<A, B, C, D, E, T>;
109+
export type Implementation5O<A, B, C, D, E, F, T> = (
110+
a: A,
111+
b: B,
112+
c: C,
113+
d: D,
114+
e: E,
115+
f?: F
116+
) => T;
117+
export type Implementation6<A, B, C, D, E, F, T> = Fn6<A, B, C, D, E, F, T>;
118+
export type Implementation6O<A, B, C, D, E, F, G, T> = (
119+
a: A,
120+
b: B,
121+
c: C,
122+
d: D,
123+
e: E,
124+
f: F,
125+
g?: G
126+
) => T;
127+
export type Implementation7<A, B, C, D, E, F, G, T> = Fn7<
128+
A,
129+
B,
130+
C,
131+
D,
132+
E,
133+
F,
134+
G,
135+
T
136+
>;
137+
export type Implementation7O<A, B, C, D, E, F, G, H, T> = (
138+
a: A,
139+
b: B,
140+
c: C,
141+
d: D,
142+
e: E,
143+
f: F,
144+
g: G,
145+
h?: H
146+
) => T;
147+
export type Implementation8<A, B, C, D, E, F, G, H, T> = Fn8<
148+
A,
149+
B,
150+
C,
151+
D,
152+
E,
153+
F,
154+
G,
155+
H,
156+
T
157+
>;
158+
export type Implementation8O<A, B, C, D, E, F, G, H, I, T> = (
159+
a: A,
160+
b: B,
161+
c: C,
162+
d: D,
163+
e: E,
164+
f: F,
165+
g: G,
166+
h: H,
167+
i?: I
168+
) => T;
169+
170+
export interface MultiFnBase<I> {
171+
/**
172+
* Registers implementation for dispatch value `id`. Returns true,
173+
* if successful. Returns false if an implementation already exists
174+
* (and does nothing in this case).
175+
*
176+
* @param id
177+
* @param impl
178+
*/
179+
add(id: PropertyKey, impl: I): boolean;
180+
/**
181+
* Takes an object of dispatch values and their implementations and
182+
* calls `.add()` for each KV pair. Returns true, if all impls were
183+
* added successfully. Note: Only numbers or strings are accepted as
184+
* dispatch values here.
185+
*
186+
* @param impls
187+
*/
188+
addAll(impls: IObjectOf<I>): boolean;
189+
/**
190+
* Removes implementation for dispatch value `id`. Returns true, if
191+
* successful.
192+
*
193+
* @param id
194+
*/
195+
remove(id: PropertyKey): boolean;
196+
/**
197+
* Returns true, if the function is callable (has a valid
198+
* implementation) for given arguments.
199+
*
200+
* @param args
201+
*/
202+
callable(...args: any[]): boolean;
203+
/**
204+
* Returns a set of all registered dispatch values.
205+
*/
206+
impls(): Set<PropertyKey>;
207+
/**
208+
* Updates dispatch hierarchy by declaring dispatch value `id` to
209+
* delegate to `parent`'s implementation. I.e. in terms of dispatch
210+
* logic, `id` is considered the same as `parent.
211+
*
212+
* @param id
213+
* @param parent
214+
*/
215+
isa(id: PropertyKey, parent: PropertyKey): boolean;
216+
/**
217+
* Returns all known dispatch relationships. This is an object with
218+
* all registered dispatch values as keys, each with a set of parent
219+
* dispatch values.
220+
*/
221+
rels(): IObjectOf<Set<PropertyKey>>;
222+
/**
223+
* Returns a set of immediate parent dispatch values for given
224+
* dispatch value `id`.
225+
*
226+
* @param id
227+
*/
228+
parents(id: PropertyKey): Set<PropertyKey>;
229+
/**
230+
* Similar to `parents()`, but includes all transitive parent dispatch
231+
* values for given dispatch value `id`.
232+
* @param id
233+
*/
234+
ancestors(id: PropertyKey): Set<PropertyKey>;
235+
}
236+
237+
export interface MultiFn<T>
238+
extends Implementation<T>,
239+
MultiFnBase<Implementation<T>> {}
240+
241+
export interface MultiFn1<A, T>
242+
extends Implementation1<A, T>,
243+
MultiFnBase<Implementation1<A, T>> {}
244+
245+
export interface MultiFn1O<A, B, T>
246+
extends Implementation1O<A, B, T>,
247+
MultiFnBase<Implementation1O<A, B, T>> {}
248+
249+
export interface MultiFn2<A, B, T>
250+
extends Implementation2<A, B, T>,
251+
MultiFnBase<Implementation2<A, B, T>> {}
252+
253+
export interface MultiFn2O<A, B, C, T>
254+
extends Implementation2O<A, B, C, T>,
255+
MultiFnBase<Implementation2O<A, B, C, T>> {}
256+
257+
export interface MultiFn3<A, B, C, T>
258+
extends Implementation3<A, B, C, T>,
259+
MultiFnBase<Implementation3<A, B, C, T>> {}
260+
261+
export interface MultiFn3O<A, B, C, D, T>
262+
extends Implementation3O<A, B, C, D, T>,
263+
MultiFnBase<Implementation3O<A, B, C, D, T>> {}
264+
265+
export interface MultiFn4<A, B, C, D, T>
266+
extends Implementation4<A, B, C, D, T>,
267+
MultiFnBase<Implementation4<A, B, C, D, T>> {}
268+
269+
export interface MultiFn4O<A, B, C, D, E, T>
270+
extends Implementation4O<A, B, C, D, E, T>,
271+
MultiFnBase<Implementation4O<A, B, C, D, E, T>> {}
272+
273+
export interface MultiFn5<A, B, C, D, E, T>
274+
extends Implementation5<A, B, C, D, E, T>,
275+
MultiFnBase<Implementation5<A, B, C, D, E, T>> {}
276+
277+
export interface MultiFn5O<A, B, C, D, E, F, T>
278+
extends Implementation5O<A, B, C, D, E, F, T>,
279+
MultiFnBase<Implementation5O<A, B, C, D, E, F, T>> {}
280+
281+
export interface MultiFn6<A, B, C, D, E, F, T>
282+
extends Implementation6<A, B, C, D, E, F, T>,
283+
MultiFnBase<Implementation6<A, B, C, D, E, F, T>> {}
284+
285+
export interface MultiFn6O<A, B, C, D, E, F, G, T>
286+
extends Implementation6O<A, B, C, D, E, F, G, T>,
287+
MultiFnBase<Implementation6O<A, B, C, D, E, F, G, T>> {}
288+
289+
export interface MultiFn7<A, B, C, D, E, F, G, T>
290+
extends Implementation7<A, B, C, D, E, F, G, T>,
291+
MultiFnBase<Implementation7<A, B, C, D, E, F, G, T>> {}
292+
293+
export interface MultiFn7O<A, B, C, D, E, F, G, H, T>
294+
extends Implementation7O<A, B, C, D, E, F, G, H, T>,
295+
MultiFnBase<Implementation7O<A, B, C, D, E, F, G, H, T>> {}
296+
297+
export interface MultiFn8<A, B, C, D, E, F, G, H, T>
298+
extends Implementation8<A, B, C, D, E, F, G, H, T>,
299+
MultiFnBase<Implementation8<A, B, C, D, E, F, G, H, T>> {}
300+
301+
export interface MultiFn8O<A, B, C, D, E, F, G, H, I, T>
302+
extends Implementation8O<A, B, C, D, E, F, G, H, I, T>,
303+
MultiFnBase<Implementation8O<A, B, C, D, E, F, G, H, I, T>> {}
304+
305+
export type AncestorDefs = IObjectOf<Iterable<PropertyKey>>;

packages/defmulti/src/defmulti-n.ts

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { illegalArity } from "@thi.ng/errors";
2+
import { DEFAULT, Implementation } from "./api";
3+
import { defmulti } from "./defmulti";
4+
5+
/**
6+
* Returns a multi-dispatch function which delegates to one of the
7+
* provided implementations, based on the arity (number of args) when
8+
* the function is called. Internally uses `defmulti`, so new arities
9+
* can be dynamically added (or removed) at a later time. If no
10+
* `fallback` is provided, `defmultiN` also registers a `DEFAULT`
11+
* implementation which simply throws an `IllegalArityError` when
12+
* invoked.
13+
*
14+
* **Note:** Unlike `defmulti` no argument type checking is supported,
15+
* however you can specify the return type for the generated function.
16+
*
17+
* ```
18+
* const foo = defmultiN<string>({
19+
* 0: () => "zero",
20+
* 1: (x) => `one: ${x}`,
21+
* 3: (x, y, z) => `three: ${x}, ${y}, ${z}`
22+
* });
23+
*
24+
* foo();
25+
* // zero
26+
* foo(23);
27+
* // one: 23
28+
* foo(1, 2, 3);
29+
* // three: 1, 2, 3
30+
* foo(1, 2);
31+
* // Error: illegal arity: 2
32+
*
33+
* foo.add(2, (x, y) => `two: ${x}, ${y}`);
34+
* foo(1, 2);
35+
* // two: 1, 2
36+
* ```
37+
*
38+
* @param impls
39+
* @param fallback
40+
*/
41+
export const defmultiN = <T>(
42+
impls: { [id: number]: Implementation<T> },
43+
fallback?: Implementation<T>
44+
) => {
45+
const fn = defmulti<T>((...args: any[]) => args.length);
46+
fn.add(DEFAULT, fallback || ((...args) => illegalArity(args.length)));
47+
for (let id in impls) {
48+
fn.add(id, impls[id]);
49+
}
50+
return fn;
51+
};

0 commit comments

Comments
 (0)