michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: */ michael@0: "use strict"; michael@0: michael@0: module.metadata = { michael@0: "stability": "experimental" michael@0: }; michael@0: michael@0: const method = require("method/core"); michael@0: michael@0: // Utility function that is just an enhancement over `method` to michael@0: // allow predicate based dispatch in addition to polymorphic michael@0: // dispatch. Unfortunately polymorphic dispatch does not quite michael@0: // cuts it in the world of XPCOM where no types / classes exist michael@0: // and all the XUL nodes share same type / prototype. michael@0: // Probably this is more generic and belongs some place else, but michael@0: // we can move it later once this will be relevant. michael@0: let dispatcher = hint => { michael@0: const base = method(hint); michael@0: // Make a map for storing predicate, implementation mappings. michael@0: let implementations = new Map(); michael@0: michael@0: // Dispatcher function goes through `predicate, implementation` michael@0: // pairs to find predicate that matches first argument and michael@0: // returns application of arguments on the associated michael@0: // `implementation`. If no matching predicate is found delegates michael@0: // to a `base` polymorphic function. michael@0: let dispatch = (value, ...rest) => { michael@0: for (let [predicate, implementation] of implementations) { michael@0: if (predicate(value)) michael@0: return implementation(value, ...rest); michael@0: } michael@0: michael@0: return base(value, ...rest); michael@0: }; michael@0: michael@0: // Expose base API. michael@0: dispatch.define = base.define; michael@0: dispatch.implement = base.implement; michael@0: dispatch.toString = base.toString; michael@0: michael@0: // Add a `when` function to allow extending function via michael@0: // predicates. michael@0: dispatch.when = (predicate, implementation) => { michael@0: if (implementations.has(predicate)) michael@0: throw TypeError("Already implemented for the given predicate"); michael@0: implementations.set(predicate, implementation); michael@0: }; michael@0: michael@0: return dispatch; michael@0: }; michael@0: michael@0: exports.dispatcher = dispatcher;