import { BiMultiMapBuilder, BiMultiMapEmpty, BiMultiMapNonEmpty, type BiMultiMapBase, } from '@rimbu/bimultimap/custom'; import type { WithKeyValue } from '@rimbu/collection-types/map-custom'; import type { ArrayNonEmpty } from '@rimbu/common'; import { Reducer, type StreamSource } from '@rimbu/stream'; import { isEmptyStreamSourceInstance } from '@rimbu/stream/custom'; export interface ContextTypesImpl extends BiMultiMapBase.Types { readonly context: BiMultiMapContext; } export class BiMultiMapContext< UK, UV, N extends string, Tp extends ContextTypesImpl = ContextTypesImpl, > implements BiMultiMapBase.Context { constructor( readonly typeTag: N, readonly keyValueMultiMapContext: WithKeyValue< Tp, UK, UV >['keyValueMultiMapContext'], readonly valueKeyMultiMapContext: WithKeyValue< Tp, UK, UV >['valueKeyMultiMapContext'] ) {} readonly _fixTypes!: any; get _types(): Tp { return undefined as any; } readonly _empty = Object.freeze( new BiMultiMapEmpty(this) ) as WithKeyValue['normal']; readonly empty = (): WithKeyValue< Tp, K, V >['normal'] => { return this._empty; }; readonly of: any = ( ...entries: ArrayNonEmpty ): [K, V] extends [UK, UV] ? WithKeyValue['nonEmpty'] : never => { return this.from(entries); }; readonly from = ( ...sources: ArrayNonEmpty> ): [K, V] extends [UK, UV] ? WithKeyValue['normal'] | any : never => { if (sources.length === 1) { const source = sources[0]; if (source instanceof BiMultiMapNonEmpty && source.context === this) return source as any; } let builder = this.builder(); let i = -1; const length = sources.length; while (++i < length) { const source = sources[i]; if (isEmptyStreamSourceInstance(source)) continue; if ( builder.isEmpty && source instanceof BiMultiMapNonEmpty && source.context === this ) { if (i === length - 1) return source as any; builder = source.toBuilder(); continue; } builder.addEntries(source); } return builder.build() as any; }; readonly builder = (): WithKeyValue< Tp, K, V >['builder'] => { return new BiMultiMapBuilder(this) as WithKeyValue< Tp, K, V >['builder']; }; readonly reducer = ( source?: StreamSource ): Reducer['normal']> => { return Reducer.create( () => undefined === source ? this.builder() : (this.from(source) as WithKeyValue['normal']).toBuilder(), (builder, entry) => { builder.add(entry[0], entry[1]); return builder; }, (builder) => builder.build() ); }; createBuilder( source?: WithKeyValue['nonEmpty'] ): WithKeyValue['builder'] { return new BiMultiMapBuilder(this, source) as WithKeyValue< Tp, K, V >['builder']; } createNonEmpty( keyValueMultiMap: WithKeyValue['keyValueMultiMapNonEmpty'], valueKeyMultiMap: WithKeyValue['valueKeyMultiMapNonEmpty'] ): WithKeyValue['nonEmpty'] { return new BiMultiMapNonEmpty( this, keyValueMultiMap, valueKeyMultiMap ) as WithKeyValue['nonEmpty']; } }