import type { IObjectOf , Pair } from "@thi.ng/api" ; import { unsupported } from "@thi.ng/errors/unsupported" ; import type { AncestorDefs , DispatchFn , DispatchFn1 , DispatchFn1O , DispatchFn2 , DispatchFn2O , DispatchFn3 , DispatchFn3O , DispatchFn4 , DispatchFn4O , DispatchFn5 , DispatchFn5O , DispatchFn6 , DispatchFn6O , DispatchFn7 , DispatchFn7O , DispatchFn8 , DispatchFn8O , Implementation , Implementation1 , Implementation1O , Implementation2 , Implementation2O , Implementation3 , Implementation3O , Implementation4 , Implementation4O , Implementation5 , Implementation5O , Implementation6 , Implementation6O , Implementation7 , Implementation7O , Implementation8 , Implementation8O , MultiFn , MultiFn1 , MultiFn1O , MultiFn2 , MultiFn2O , MultiFn3 , MultiFn3O , MultiFn4 , MultiFn4O , MultiFn5 , MultiFn5O , MultiFn6 , MultiFn6O , MultiFn7 , MultiFn7O , MultiFn8 , MultiFn8O , } from "./api.js" ; import { LOGGER } from "./logger.js" ; /**
 * Unique symbol used for registering a default / fallback
 * implementation.
 */ export const DEFAULT = Symbol ( ) ; remarks export function defmulti < T > ( f , rels ? , impls ? ) ; export function defmulti < A , T > ( f , rels ? , impls ? ) ; export function defmulti < A , B , T > ( f , rels ? , impls ? ) ; export function defmulti < A , B , T > ( f , rels ? , impls ? ) ; export function defmulti < A , B , C , T > ( f , rels ? , impls ? ) ; export function defmulti < A , B , C , T > ( f , rels ? , impls ? ) ; export function defmulti < A , B , C , D , T > ( f , rels ? , impls ? ) ; export function defmulti < A , B , C , D , T > ( f , rels ? , impls ? ) ; export function defmulti < A , B , C , D , E , T > ( f , rels ? , impls ? ) ; export function defmulti < A , B , C , D , E , T > ( f , rels ? , impls ? ) ; export function defmulti < A , B , C , D , E , F , T > ( f , rels ? , impls ? ) ; export function defmulti < A , B , C , D , E , F , T > ( f , rels ? , impls ? ) ; export function defmulti < A , B , C , D , E , F , G , T > ( f , rels ? , impls ? ) ; export function defmulti < A , B , C , D , E , F , G , T > ( f , rels ? , impls ? ) ; export function defmulti < A , B , C , D , E , F , G , H , T > ( f , rels ? , impls ? ) ; export function defmulti < A , B , C , D , E , F , G , H , T > ( f , rels ? , impls ? ) ; export function defmulti < A , B , C , D , E , F , G , H , I , T > ( f , rels ? , impls ? ) ; export function defmulti < T > ( f , _rels ? , _impls ? ) { const impls = { } ; const rels = _rels ? makeRels ( _rels ) : { } ; const fn = ( ... args ) => { const id = f ( ... args ) ; const g = impls [ id ] || findImpl ( impls , rels , id ) || impls [ < any > DEFAULT ] ; return g ? g ( ... args ) : unsupported ( `missing implementation for: "${ id . toString ( ) }"` ) ; } ; fn . add = ( id , _impl ) => { if ( impls [ < any > id ] ) { LOGGER . warn ( `overwriting '${ id . toString ( ) }' impl` ) ; } impls [ < any > id ] = _impl ; return true ; } ; fn . addAll = ( _impls ) => { let ok = true ; for ( let id in _impls ) { ok = fn . add ( id , _impls [ id ] ) && ok ; } DEFAULT in _impls && fn . setDefault ( _impls [ < any > DEFAULT ] ) ; return ok ; } ; fn . setDefault = ( impl ) => fn . add ( DEFAULT , impl ) ; fn . remove = ( id ) => { if ( ! impls [ < any > id ] ) return false ; delete impls [ < any > id ] ; return true ; } ; fn . callable = ( ... args ) => { const id = f ( ... args ) ; return ! ! ( impls [ id ] || findImpl ( impls , rels , id ) || impls [ < any > DEFAULT ] ) ; } ; fn . isa = ( id , parent ) => { let val = rels [ < any > id ] ; ! val && ( rels [ < any > id ] = val = new Set ( ) ) ; val . add ( parent ) ; } ; fn . impls = ( ) => { const res = new Set < PropertyKey > ( Object . keys ( impls ) ) ; for ( let id in rels ) { findImpl ( impls , rels , id ) && res . add ( id ) ; } impls [ < any > DEFAULT ] && res . add ( DEFAULT ) ; return res ; } ; fn . rels = ( ) => rels ; fn . parents = ( id ) => rels [ < any > id ] ; fn . ancestors = ( id ) => new Set < PropertyKey > ( findAncestors ( [ ] , rels , id ) ) ; fn . dependencies = function * ( ) : IterableIterator < Pair < PropertyKey , PropertyKey | undefined > > { for ( let a in rels ) { for ( let b of rels [ a ] ) yield [ a , b ] ; } for ( let id in impls ) { ! rels [ id ] && ( yield [ id , undefined ] ) ; } } ; _impls && fn . addAll ( _impls ) ; return fn ; } const findImpl = ( impls , rels , id ) => { const parents = rels [ < any > id ] ; if ( ! parents ) return ; for ( let p of parents ) { let impl = impls [ < any > p ] || findImpl ( impls , rels , p ) ; if ( impl ) return impl ; } } ; const findAncestors = ( acc , rels , id ) => { const parents = rels [ < any > id ] ; if ( parents ) { for ( let p of parents ) { acc . push ( p ) ; findAncestors ( acc , rels , p ) ; } } return acc ; } ; const makeRels = ( spec ) => { const rels = { } ; for ( let k in spec ) { const val = spec [ k ] ; rels [ k ] = val instanceof Set ? val : Array . isArray ( val ) ? new Set ( val ) : new Set ( [ val ] ) ; } return rels ; } ;