feat: Incremental building and simultaneous overloading of object values
So we can start with literal objects whose keys are operator names, and whose values are arrays of implementations, and merge them, and then replace every value with the overloaded function it specifies.
This commit is contained in:
parent
2f0a9936a3
commit
a848e2af88
3 changed files with 103 additions and 2 deletions
|
|
@ -10,7 +10,8 @@ export default function overload<T extends readonly [...any[]]>(
|
|||
const impTypes = reflect(callSite).parameters[0].elements
|
||||
return <any>((...a: any[]) => {
|
||||
for (let i = 0; i < imps.length; ++i) {
|
||||
const paramTypes = impTypes[i].type.parameters
|
||||
const paramTypes = imps[i].functionType.parameters
|
||||
|| impTypes[i].type.parameters
|
||||
let match = true
|
||||
const haveArgs = a.length
|
||||
let onArg = 0
|
||||
|
|
@ -40,3 +41,77 @@ export default function overload<T extends readonly [...any[]]>(
|
|||
+ 'did not match any implementation')
|
||||
})
|
||||
}
|
||||
|
||||
type AVO = Record<string, readonly [...any[]]>
|
||||
|
||||
type MergeArrayValues<L extends AVO, R extends AVO> =
|
||||
Pick<L, Exclude<keyof L, keyof R>>
|
||||
& Pick<R, Exclude<keyof R, keyof L>>
|
||||
& { [P in (keyof L & keyof R)]: [...L[P], ...R[P]] }
|
||||
|
||||
function mergeImps<T extends AVO, U extends AVO>(
|
||||
impT: T, impU: U): MergeArrayValues<T, U> {
|
||||
const dummy = Object.assign({}, impT, impU)
|
||||
const result = {} as AVO
|
||||
for (const key in dummy) {
|
||||
if (key in impT) {
|
||||
if (key in impU) {
|
||||
const k = key as Extract<keyof T & keyof U, string>
|
||||
result[k] = [...impT[k], ...impU[k]]
|
||||
} else {
|
||||
result[key] = impT[key]
|
||||
}
|
||||
} else {
|
||||
result[key] = impU[key]
|
||||
}
|
||||
}
|
||||
return result as MergeArrayValues<T, U>
|
||||
}
|
||||
|
||||
class ImpMerger<T extends AVO> {
|
||||
implementations: T
|
||||
constructor(imps: T) {
|
||||
this.implementations = imps
|
||||
}
|
||||
with<U extends AVO>(
|
||||
moreImps: U, callSite?: CallSite): ImpMerger<MergeArrayValues<T,U>> {
|
||||
const Utype = reflect(callSite).parameters[0]
|
||||
// Annotate the implementations with their RTTI while we have it
|
||||
for (const [key, imps] of Object.entries(moreImps)) {
|
||||
if (!(imps[0].functionType)) {
|
||||
const tuple = Utype.members.find(m => m.name === key)
|
||||
for (let i = 0; i < imps.length; ++i) {
|
||||
imps[i].functionType = tuple.type.elements[i].type
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ImpMerger(mergeImps<T,U>(this.implementations, moreImps))
|
||||
}
|
||||
imps(): T {
|
||||
return this.implementations
|
||||
}
|
||||
}
|
||||
|
||||
function merge<T extends AVO>(impsObject: T, callSite?: CallSite) {
|
||||
const Ttype = reflect(callSite).parameters[0]
|
||||
// Annotate the implementations with their RTTI while we have it
|
||||
for (const [key, imps] of Object.entries(impsObject)) {
|
||||
if (!(imps[0].functionType)) {
|
||||
const tuple = Ttype.members.find(m => m.name === key)
|
||||
for (let i = 0; i < imps.length; ++i) {
|
||||
imps[i].functionType = tuple.type.elements[i].type
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ImpMerger(impsObject)
|
||||
}
|
||||
|
||||
type OverloadedValues<T extends AVO> = {
|
||||
[P in keyof T]: UnionToIntersection<T[P][number]>}
|
||||
|
||||
function overloadValues<T extends AVO>(impObject: T) : OverloadedValues<T> {
|
||||
return Object.fromEntries(Object.entries(impObject).map(
|
||||
([k, v]) => [k, overload(v)])) as OverloadedValues<T>
|
||||
}
|
||||
|
||||
export {merge, mergeImps, overloadValues}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue