| 
									
										
										
										
											2020-11-02 18:24:20 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							| 
									
										
										
										
											2021-01-05 04:49:24 +03:00
										 |  |  | * | 
					
						
							|  |  |  | * This defines the following extensions to Promise: | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * 	Promise.iter(seq) | 
					
						
							|  |  |  | * 		Iterable promise object. | 
					
						
							|  |  |  | * 		Similar to Promise.all(..) but adds basic iterator/generator | 
					
						
							|  |  |  | * 		API and will resolve the items as they are ready (resolved). | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * 	Promise.interactive(handler) | 
					
						
							|  |  |  | * 		Interactive promise object. | 
					
						
							|  |  |  | * 		This adds a basic message passing API to the promise. | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * 	Promise.cooperative() | 
					
						
							|  |  |  | * 		Cooperative promise object. | 
					
						
							|  |  |  | * 		Exposes the API to resolve/reject the promise object  | 
					
						
							|  |  |  | * 		externally. | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							| 
									
										
										
										
											2020-11-02 18:24:20 +03:00
										 |  |  | **********************************************/  /* c8 ignore next 2 */ | 
					
						
							|  |  |  | ((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define) | 
					
						
							|  |  |  | (function(require){ var module={} // make module AMD/node compatible...
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var object = require('ig-object') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-27 08:46:51 +03:00
										 |  |  | // XXX required for STOP...
 | 
					
						
							|  |  |  | //var generator = require('./generator')
 | 
					
						
							| 
									
										
										
										
											2020-11-02 18:24:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 16:12:13 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-02 18:24:20 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							| 
									
										
										
										
											2021-05-27 08:46:51 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* XXX not used yet... | 
					
						
							|  |  |  | // NOTE: this is used in a similar fashion to Python's StopIteration...
 | 
					
						
							|  |  |  | var STOP = | 
					
						
							|  |  |  | module.STOP = | 
					
						
							|  |  |  | 	object.STOP | 
					
						
							|  |  |  | //*/
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2020-11-24 20:23:22 +03:00
										 |  |  | // Iterable promise...
 | 
					
						
							|  |  |  | // 
 | 
					
						
							|  |  |  | // Like Promise.all(..) but adds ability to iterate through results
 | 
					
						
							|  |  |  | // via generators .map(..)/.reduce(..) and friends...
 | 
					
						
							|  |  |  | // 
 | 
					
						
							| 
									
										
										
										
											2020-11-02 18:24:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-09 06:22:32 +03:00
										 |  |  | var IterablePromise = | 
					
						
							|  |  |  | module.IterablePromise = | 
					
						
							|  |  |  | object.Constructor('IterablePromise', Promise, { | 
					
						
							| 
									
										
										
										
											2021-05-27 08:46:51 +03:00
										 |  |  | 	// XXX
 | 
					
						
							|  |  |  | 	//STOP: object.STOP,
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// Format:
 | 
					
						
							|  |  |  | 	// 	[
 | 
					
						
							|  |  |  | 	//		[ <value> ],
 | 
					
						
							|  |  |  | 	//		<promise>,
 | 
					
						
							|  |  |  | 	//		...
 | 
					
						
							|  |  |  | 	// 	]
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2020-11-10 01:58:51 +03:00
										 |  |  | 	__list: null, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 21:35:04 +03:00
										 |  |  | 	// iterator methods...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// These will return a new IterablePromise instance...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 	// When called from a resolved promise these will return a new 
 | 
					
						
							|  |  |  | 	// resolved promise with updated values...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// When called from a rejected promise these will return a rejected 
 | 
					
						
							|  |  |  | 	// with the same reason promise...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2020-11-17 21:35:04 +03:00
										 |  |  | 	// NOTE: these are different to Array's equivalents in that the handler
 | 
					
						
							|  |  |  | 	// 		is called not in the order of the elements but rather in order 
 | 
					
						
							|  |  |  | 	// 		of promise resolution...
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:15:30 +03:00
										 |  |  | 	// NOTE: index of items is unknowable because items can expand and
 | 
					
						
							| 
									
										
										
										
											2020-11-17 21:35:04 +03:00
										 |  |  | 	// 		contract depending on handlrs (e.g. .filter(..) can remove 
 | 
					
						
							|  |  |  | 	// 		items)...
 | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 	// 		This the following can not be implemented here:
 | 
					
						
							|  |  |  | 	// 			.slice(..)
 | 
					
						
							|  |  |  | 	// 			.splice(..)
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:15:30 +03:00
										 |  |  | 	// 			.values() / .keys()
 | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 	// 			.at(..)
 | 
					
						
							|  |  |  | 	// 			[Symbol.iterator]()		- needs to be sync...
 | 
					
						
							|  |  |  | 	// 		The followng methods are questionable:
 | 
					
						
							|  |  |  | 	// 			.indexOf(..)
 | 
					
						
							|  |  |  | 	// 			.includes(..)
 | 
					
						
							|  |  |  | 	// 			.some(..) / .every(..)
 | 
					
						
							|  |  |  | 	// 			.sort(..)
 | 
					
						
							| 
									
										
										
										
											2022-06-03 21:23:23 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2021-04-28 17:21:45 +03:00
										 |  |  | 	// XXX should these support STOP???
 | 
					
						
							| 
									
										
										
										
											2020-11-10 01:58:51 +03:00
										 |  |  | 	map: function(func){ | 
					
						
							| 
									
										
										
										
											2022-06-03 19:41:13 +03:00
										 |  |  | 		return this.constructor(this,  | 
					
						
							| 
									
										
										
										
											2021-05-26 11:57:21 +03:00
										 |  |  | 			function(e){ | 
					
						
							|  |  |  | 				return [func(e)] }) }, | 
					
						
							| 
									
										
										
										
											2020-11-16 02:38:19 +03:00
										 |  |  | 	filter: function(func){ | 
					
						
							| 
									
										
										
										
											2022-06-03 19:41:13 +03:00
										 |  |  | 		return this.constructor(this,  | 
					
						
							| 
									
										
										
										
											2020-11-17 21:35:04 +03:00
										 |  |  | 			function(e){ | 
					
						
							| 
									
										
										
										
											2021-05-26 11:57:21 +03:00
										 |  |  | 				return func(e) ?  | 
					
						
							|  |  |  | 					[e]  | 
					
						
							|  |  |  | 					: [] }) }, | 
					
						
							| 
									
										
										
										
											2022-06-01 16:15:30 +03:00
										 |  |  | 	// NOTE: this does not return an iterable promise as we can't know 
 | 
					
						
							|  |  |  | 	// 		what the user reduces to...
 | 
					
						
							| 
									
										
										
										
											2022-06-03 21:23:23 +03:00
										 |  |  | 	// 		XXX we could look at the initial state though...
 | 
					
						
							| 
									
										
										
										
											2022-06-02 12:05:37 +03:00
										 |  |  | 	// NOTE: the items can be handled out of order because the nested 
 | 
					
						
							|  |  |  | 	// 		promises can resolve in any order.
 | 
					
						
							|  |  |  | 	//		XXX write how to go around this...
 | 
					
						
							|  |  |  | 	// NOTE: since order of execution can not be guaranteed there is no
 | 
					
						
							|  |  |  | 	// 		point in implementing .reduceRight(..)
 | 
					
						
							| 
									
										
										
										
											2021-05-26 11:57:21 +03:00
										 |  |  | 	reduce: function(func, res){ | 
					
						
							| 
									
										
										
										
											2022-06-03 19:41:13 +03:00
										 |  |  | 		return this.constructor(this,  | 
					
						
							| 
									
										
										
										
											2021-05-26 11:57:21 +03:00
										 |  |  | 				function(e){ | 
					
						
							|  |  |  | 					res = func(res, e) | 
					
						
							|  |  |  | 					return [] }) | 
					
						
							| 
									
										
										
										
											2020-11-17 21:35:04 +03:00
										 |  |  | 			.then(function(){  | 
					
						
							|  |  |  | 				return res }) }, | 
					
						
							| 
									
										
										
										
											2022-06-04 03:01:54 +03:00
										 |  |  | 	/* // XXX since order of execution is not fixed there is no point in  | 
					
						
							|  |  |  | 	//		adding this.
 | 
					
						
							|  |  |  | 	reduceRight: function(func, res){ | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 			.reverse() | 
					
						
							|  |  |  | 			.reduce(...arguments) | 
					
						
							|  |  |  | 			.reverse() }, | 
					
						
							|  |  |  | 	//*/
 | 
					
						
							| 
									
										
										
										
											2020-11-17 16:12:13 +03:00
										 |  |  | 	flat: function(depth=1){ | 
					
						
							| 
									
										
										
										
											2022-06-03 19:41:13 +03:00
										 |  |  | 		return this.constructor(this,  | 
					
						
							| 
									
										
										
										
											2021-05-26 11:57:21 +03:00
										 |  |  | 			function(e){  | 
					
						
							| 
									
										
										
										
											2022-06-01 16:15:30 +03:00
										 |  |  | 				return (depth > 1  | 
					
						
							|  |  |  | 							&& e != null  | 
					
						
							|  |  |  | 							&& e.flat) ?  | 
					
						
							|  |  |  | 						e.flat(depth-1)  | 
					
						
							|  |  |  | 					: depth != 0 ? | 
					
						
							|  |  |  | 						e | 
					
						
							|  |  |  | 					: [e] }) }, | 
					
						
							| 
									
										
										
										
											2022-06-02 12:05:37 +03:00
										 |  |  | 	reverse: function(){ | 
					
						
							| 
									
										
										
										
											2022-06-03 19:41:13 +03:00
										 |  |  | 		var lst = this.__list | 
					
						
							|  |  |  | 		return this.constructor( | 
					
						
							|  |  |  | 			lst instanceof Promise ? | 
					
						
							|  |  |  | 				lst.then(function(elems){ | 
					
						
							|  |  |  | 					return elems instanceof Array ? | 
					
						
							|  |  |  | 						elems.slice() | 
					
						
							| 
									
										
										
										
											2022-06-02 12:05:37 +03:00
										 |  |  | 							.reverse() | 
					
						
							| 
									
										
										
										
											2022-06-03 19:41:13 +03:00
										 |  |  | 						: elems }) | 
					
						
							|  |  |  | 			: lst | 
					
						
							|  |  |  | 				.map(function(elems){ | 
					
						
							|  |  |  | 					return elems instanceof Array ? | 
					
						
							| 
									
										
										
										
											2022-06-03 21:23:23 +03:00
										 |  |  | 							elems.slice() | 
					
						
							|  |  |  | 								.reverse() | 
					
						
							|  |  |  | 						: elems instanceof Promise ? | 
					
						
							|  |  |  | 							elems.then(function(elems){ | 
					
						
							|  |  |  | 								return elems.reverse() }) | 
					
						
							| 
									
										
										
										
											2022-06-03 19:41:13 +03:00
										 |  |  | 						: elems }) | 
					
						
							|  |  |  | 				.reverse(), | 
					
						
							|  |  |  | 			'raw') }, | 
					
						
							| 
									
										
										
										
											2022-06-01 16:15:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-04 03:10:49 +03:00
										 |  |  | 	// NOTE: these can create an unresolved promise from a resolved 
 | 
					
						
							|  |  |  | 	// 		promise...
 | 
					
						
							| 
									
										
										
										
											2022-06-04 03:01:54 +03:00
										 |  |  | 	// XXX EXPEREMENTAL...
 | 
					
						
							|  |  |  | 	// 		....can we remove a level of indirection here???
 | 
					
						
							|  |  |  | 	// 		would be better to use the raw mode...
 | 
					
						
							|  |  |  | 	concat: function(other){ | 
					
						
							|  |  |  | 		var lst = this.__list | 
					
						
							|  |  |  | 		return lst instanceof Promise ? | 
					
						
							|  |  |  | 				this.constructor([this, other]) | 
					
						
							|  |  |  | 					.flat() | 
					
						
							|  |  |  | 			: other instanceof IterablePromise ? | 
					
						
							|  |  |  | 				this.constructor( | 
					
						
							|  |  |  | 					lst.concat(other.__list), | 
					
						
							|  |  |  | 					'raw') | 
					
						
							|  |  |  | 			: other instanceof Promise ? | 
					
						
							|  |  |  | 				this.constructor( | 
					
						
							|  |  |  | 					lst.concat(other | 
					
						
							|  |  |  | 						.then(function(res){  | 
					
						
							|  |  |  | 							return res instanceof Array ? | 
					
						
							|  |  |  | 					   			res | 
					
						
							|  |  |  | 								: [res] })), | 
					
						
							|  |  |  | 					'raw') | 
					
						
							|  |  |  | 			: this.constructor( | 
					
						
							|  |  |  | 				// XXX this is cheating -- need a more direct way to form the array...
 | 
					
						
							|  |  |  | 				lst.concat(this.constructor(other).__list), | 
					
						
							|  |  |  | 				'raw') }, | 
					
						
							|  |  |  | 	push: function(elem){ | 
					
						
							|  |  |  | 		return this.concat([elem]) }, | 
					
						
							|  |  |  | 	unshift: function(elem){ | 
					
						
							|  |  |  | 		return this.constructor([elem]) | 
					
						
							|  |  |  | 			.concat(this) }, | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-04 03:10:49 +03:00
										 |  |  | 	// XXX do we need these?
 | 
					
						
							|  |  |  | 	// 			.pop()
 | 
					
						
							|  |  |  | 	// 			.shift()
 | 
					
						
							|  |  |  | 	// 			.first() / .last()
 | 
					
						
							|  |  |  | 	// 		...would be nice if these could stop everything that's not
 | 
					
						
							|  |  |  | 	// 		needed to execute...
 | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Overload .then(..), .catch(..) and .finally(..) to return a plain 
 | 
					
						
							|  |  |  | 	// Promise instnace...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: .catch(..) and .finally(..) are implemented through .then(..)
 | 
					
						
							|  |  |  | 	// 		so we do not need to overload those...
 | 
					
						
							| 
									
										
										
										
											2021-04-07 14:47:25 +03:00
										 |  |  | 	// NOTE: this is slightly different from .then(..) in that it can be 
 | 
					
						
							|  |  |  | 	// 		called without arguments and return a promise wrapper. This can
 | 
					
						
							|  |  |  | 	// 		be useful to hide special promise functionality...
 | 
					
						
							| 
									
										
										
										
											2020-11-24 05:48:54 +03:00
										 |  |  | 	then: function (onfulfilled, onrejected){ | 
					
						
							| 
									
										
										
										
											2021-04-07 14:47:25 +03:00
										 |  |  | 		var p = new Promise( | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 			function(resolve, reject){ | 
					
						
							| 
									
										
										
										
											2020-11-24 05:48:54 +03:00
										 |  |  | 				Promise.prototype.then.call(this, | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 					// NOTE: resolve(..) / reject(..) return undefined so
 | 
					
						
							|  |  |  | 					// 		we can't pass them directly here...
 | 
					
						
							|  |  |  | 					function(res){  | 
					
						
							|  |  |  | 						resolve(res) | 
					
						
							|  |  |  | 						return res }, | 
					
						
							|  |  |  | 					function(res){ | 
					
						
							|  |  |  | 						reject(res) | 
					
						
							|  |  |  | 						return res }) }.bind(this)) | 
					
						
							| 
									
										
										
										
											2021-04-07 14:47:25 +03:00
										 |  |  | 		return arguments.length > 0 ? | 
					
						
							|  |  |  | 			p.then(...arguments)  | 
					
						
							|  |  |  | 			: p }, | 
					
						
							| 
									
										
										
										
											2020-11-24 05:48:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 21:35:04 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Promise.iter([ .. ])
 | 
					
						
							|  |  |  | 	//		-> iterable-promise
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Promise.iter([ .. ], handler)
 | 
					
						
							|  |  |  | 	//		-> iterable-promise
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	handler(e)
 | 
					
						
							| 
									
										
										
										
											2020-11-16 02:38:19 +03:00
										 |  |  | 	// 		-> [value]
 | 
					
						
							|  |  |  | 	// 		-> []
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2020-11-17 21:35:04 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: element index is unknowable untill the full list is expanded
 | 
					
						
							|  |  |  | 	// 		as handler(..)'s return value can expand to any number of 
 | 
					
						
							|  |  |  | 	// 		items...
 | 
					
						
							|  |  |  | 	// 		XXX we can make the index a promise, then if the client needs
 | 
					
						
							|  |  |  | 	// 			the value they can wait for it...
 | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2020-11-18 06:09:43 +03:00
										 |  |  | 	// Spectial cases usefull for extending this constructor...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2022-06-03 19:41:13 +03:00
										 |  |  | 	//	Set raw .__list without any pre-processing...
 | 
					
						
							|  |  |  | 	//	Promise.iter([ .. ], 'raw')
 | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 	//		-> iterable-promise
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2022-06-03 21:23:23 +03:00
										 |  |  | 	//	Create a rejected iterator...
 | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 	//	Promise.iter(false)
 | 
					
						
							|  |  |  | 	//		-> iterable-promise
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2020-12-02 05:29:38 +03:00
										 |  |  | 	// XXX if list is an iterator, can we fill this async???
 | 
					
						
							| 
									
										
										
										
											2021-04-21 13:45:26 +03:00
										 |  |  | 	// XXX iterator/generator as input:
 | 
					
						
							|  |  |  | 	// 		- do we unwind here or externally?
 | 
					
						
							| 
									
										
										
										
											2021-05-26 11:57:21 +03:00
										 |  |  | 	// 			...feels like with the generator external unwinding is 
 | 
					
						
							|  |  |  | 	// 			needed...
 | 
					
						
							|  |  |  | 	// XXX would be nice to support trowing STOP...
 | 
					
						
							|  |  |  | 	// 		- this is more complicated than simply suing .smap(..) instead 
 | 
					
						
							|  |  |  | 	// 			of .map(..) because the list can contain async promises...
 | 
					
						
							|  |  |  | 	// 			...would need to wrap each .then(..) call in try-catch and
 | 
					
						
							|  |  |  | 	// 			manually handle the stop...
 | 
					
						
							|  |  |  | 	// 		- another issue here is that the stop would happen in order of 
 | 
					
						
							|  |  |  | 	// 			execution and not order of elements...
 | 
					
						
							| 
									
										
										
										
											2020-11-17 21:35:04 +03:00
										 |  |  | 	__new__: function(_, list, handler){ | 
					
						
							| 
									
										
										
										
											2020-11-10 01:58:51 +03:00
										 |  |  | 		// instance...
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:15:30 +03:00
										 |  |  | 		var promise | 
					
						
							| 
									
										
										
										
											2020-11-24 05:48:54 +03:00
										 |  |  | 		var obj = Reflect.construct( | 
					
						
							|  |  |  | 			IterablePromise.__proto__,  | 
					
						
							|  |  |  | 			[function(resolve, reject){ | 
					
						
							| 
									
										
										
										
											2020-11-10 01:58:51 +03:00
										 |  |  | 				// NOTE: this is here for Promise compatibilty...
 | 
					
						
							|  |  |  | 				if(typeof(list) == 'function'){ | 
					
						
							| 
									
										
										
										
											2020-11-17 16:12:13 +03:00
										 |  |  | 					return list.call(this, ...arguments) }  | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 				// initial reject... 
 | 
					
						
							|  |  |  | 				if(list === false){ | 
					
						
							|  |  |  | 					return reject() } | 
					
						
							| 
									
										
										
										
											2020-11-17 16:12:13 +03:00
										 |  |  | 				promise = {resolve, reject} }],  | 
					
						
							| 
									
										
										
										
											2020-11-10 01:58:51 +03:00
										 |  |  | 			IterablePromise) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 16:12:13 +03:00
										 |  |  | 		if(promise){ | 
					
						
							| 
									
										
										
										
											2022-06-01 16:15:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-03 19:41:13 +03:00
										 |  |  | 			if(handler != 'raw'){ | 
					
						
							|  |  |  | 				handler = handler | 
					
						
							|  |  |  | 					?? function(e){  | 
					
						
							|  |  |  | 						return [e] } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:15:30 +03:00
										 |  |  | 				// NOTE: this is recursive to handle expanding nested promises...
 | 
					
						
							|  |  |  | 				var handle = function(elem){ | 
					
						
							|  |  |  | 					// call the handler...
 | 
					
						
							|  |  |  | 					return (elem && elem.then) ? | 
					
						
							| 
									
										
										
										
											2022-06-03 21:23:23 +03:00
										 |  |  | 						//elem.then(function(elem){
 | 
					
						
							|  |  |  | 						//	return handler(elem) })
 | 
					
						
							|  |  |  | 						elem.then(handler) | 
					
						
							| 
									
										
										
										
											2022-06-03 19:41:13 +03:00
										 |  |  | 						: handler(elem) } | 
					
						
							| 
									
										
										
										
											2022-06-01 16:15:30 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// handle the list...
 | 
					
						
							| 
									
										
										
										
											2022-06-03 19:41:13 +03:00
										 |  |  | 				// NOTE: we can't .flat() the results here as we need to 
 | 
					
						
							|  |  |  | 				// 		wait till all the promises resolve...
 | 
					
						
							|  |  |  | 				list = | 
					
						
							|  |  |  | 					(list instanceof IterablePromise  | 
					
						
							|  |  |  | 							&& !(list.__list instanceof Promise)) ? | 
					
						
							|  |  |  | 						// NOTE: this is essentially the same as below but 
 | 
					
						
							|  |  |  | 						// 		with a normalized list as input...
 | 
					
						
							|  |  |  | 						// 		XXX can we merge the two???
 | 
					
						
							|  |  |  | 						list.__list | 
					
						
							|  |  |  | 							.map(function(elems){ | 
					
						
							|  |  |  | 								return elems instanceof Promise ? | 
					
						
							|  |  |  | 									elems.then(function(elems){ | 
					
						
							|  |  |  | 										return elems | 
					
						
							|  |  |  | 											.map(handle)  | 
					
						
							|  |  |  | 											.flat() }) | 
					
						
							|  |  |  | 									: elems | 
					
						
							|  |  |  | 										.map(handle) | 
					
						
							|  |  |  | 										.flat() }) | 
					
						
							|  |  |  | 					: list instanceof Promise ? | 
					
						
							|  |  |  | 						// special case: promised list...
 | 
					
						
							|  |  |  | 						list.then(function(list){ | 
					
						
							|  |  |  | 							return [list].flat() | 
					
						
							|  |  |  | 								.map(handle) })	 | 
					
						
							|  |  |  | 					: [list].flat() | 
					
						
							|  |  |  | 						.map(handle) } | 
					
						
							| 
									
										
										
										
											2020-11-17 21:35:04 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			Object.defineProperty(obj, '__list', { | 
					
						
							|  |  |  | 				value: list, | 
					
						
							|  |  |  | 				enumerable: false, | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2020-11-17 16:12:13 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// handle promise state...
 | 
					
						
							| 
									
										
										
										
											2022-06-03 19:41:13 +03:00
										 |  |  | 			;(list instanceof Promise ? | 
					
						
							|  |  |  | 					// special case: promised list...
 | 
					
						
							|  |  |  | 					list | 
					
						
							|  |  |  | 					: Promise.all([list].flat())) | 
					
						
							| 
									
										
										
										
											2020-11-17 16:12:13 +03:00
										 |  |  | 				.then(function(res){ | 
					
						
							| 
									
										
										
										
											2022-06-03 19:41:13 +03:00
										 |  |  | 					promise.resolve(handler ? | 
					
						
							|  |  |  | 						res.flat() | 
					
						
							|  |  |  | 						: res) }) | 
					
						
							| 
									
										
										
										
											2020-11-17 16:12:13 +03:00
										 |  |  | 				.catch(promise.reject) } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-10 01:58:51 +03:00
										 |  |  | 		return obj }, | 
					
						
							| 
									
										
										
										
											2020-11-09 06:22:32 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-24 05:48:54 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2020-11-24 20:23:22 +03:00
										 |  |  | // Interactive promise...
 | 
					
						
							|  |  |  | // 
 | 
					
						
							|  |  |  | // Adds ability to send messages to the running promise.
 | 
					
						
							|  |  |  | // 
 | 
					
						
							| 
									
										
										
										
											2020-11-24 05:48:54 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | var InteractivePromise = | 
					
						
							|  |  |  | module.InteractivePromise = | 
					
						
							|  |  |  | object.Constructor('InteractivePromise', Promise, { | 
					
						
							| 
									
										
										
										
											2021-04-07 03:32:23 +03:00
										 |  |  | 	// XXX do we need a way to remove handlers???
 | 
					
						
							| 
									
										
										
										
											2020-11-24 05:48:54 +03:00
										 |  |  | 	__message_handlers: null, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	send: function(...args){ | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		;(this.__message_handlers || []) | 
					
						
							|  |  |  | 			.forEach(function(h){ h.call(that, ...args) }) | 
					
						
							|  |  |  | 		return this }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	then: IterablePromise.prototype.then, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Promise.interactive(handler)
 | 
					
						
							|  |  |  | 	//		-> interacive-promise
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	handler(resolve, reject, onmessage)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	onmessage(func)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	__new__: function(_, handler){ | 
					
						
							|  |  |  | 		var handlers = [] | 
					
						
							| 
									
										
										
										
											2021-04-07 03:32:23 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-24 05:48:54 +03:00
										 |  |  | 		var onmessage = function(func){ | 
					
						
							| 
									
										
										
										
											2021-04-07 12:30:38 +03:00
										 |  |  | 			// remove all handlers...
 | 
					
						
							| 
									
										
										
										
											2021-04-07 03:32:23 +03:00
										 |  |  | 			if(func === false){ | 
					
						
							| 
									
										
										
										
											2021-04-07 12:30:38 +03:00
										 |  |  | 				var h = (obj == null ? | 
					
						
							|  |  |  | 					handlers | 
					
						
							|  |  |  | 					: (obj.__message_handlers || [])) | 
					
						
							|  |  |  | 				h.splice(0, handlers.length) | 
					
						
							|  |  |  | 			// remove a specific handler...
 | 
					
						
							| 
									
										
										
										
											2021-04-07 03:32:23 +03:00
										 |  |  | 			} else if(arguments[1] === false){ | 
					
						
							|  |  |  | 				var h = (obj == null ? | 
					
						
							|  |  |  | 					handlers | 
					
						
							|  |  |  | 					: (obj.__message_handlers || [])) | 
					
						
							|  |  |  | 				h.splice(h.indexOf(func), 1) | 
					
						
							|  |  |  | 			// register a handler...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				var h = obj == null ? | 
					
						
							|  |  |  | 					// NOTE: we need to get the handlers from .__message_handlers
 | 
					
						
							|  |  |  | 					// 		unless we are not fully defined yet, then use the 
 | 
					
						
							|  |  |  | 					// 		bootstrap container (handlers)...
 | 
					
						
							|  |  |  | 					// 		...since we can call onmessage(..) while the promise 
 | 
					
						
							|  |  |  | 					// 		is still defined there is no way to .send(..) until it
 | 
					
						
							|  |  |  | 					// 		returns a promise object, this races here are highly 
 | 
					
						
							|  |  |  | 					// 		unlikely...
 | 
					
						
							|  |  |  | 					handlers | 
					
						
							|  |  |  | 					: (obj.__message_handlers =  | 
					
						
							|  |  |  | 						obj.__message_handlers ?? []) | 
					
						
							|  |  |  | 				handlers.push(func) } } | 
					
						
							| 
									
										
										
										
											2020-11-24 05:48:54 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		var obj = Reflect.construct( | 
					
						
							|  |  |  | 			InteractivePromise.__proto__,  | 
					
						
							|  |  |  | 			!handler ? | 
					
						
							|  |  |  | 				[] | 
					
						
							|  |  |  | 				: [function(resolve, reject){ | 
					
						
							|  |  |  | 					return handler(resolve, reject, onmessage) }],  | 
					
						
							|  |  |  | 			InteractivePromise) | 
					
						
							|  |  |  | 		Object.defineProperty(obj, '__message_handlers', { | 
					
						
							|  |  |  | 			value: handlers, | 
					
						
							|  |  |  | 			enumerable: false, | 
					
						
							| 
									
										
										
										
											2021-04-07 12:30:38 +03:00
										 |  |  | 			// XXX should this be .configurable???
 | 
					
						
							|  |  |  | 			configurable: true, | 
					
						
							| 
									
										
										
										
											2020-11-24 05:48:54 +03:00
										 |  |  | 		}) | 
					
						
							|  |  |  |    		return obj }, | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2020-11-24 20:23:22 +03:00
										 |  |  | // Cooperative promise...
 | 
					
						
							|  |  |  | // 
 | 
					
						
							|  |  |  | // A promise that can be resolved/rejected externally.
 | 
					
						
							|  |  |  | // NOTE: normally this has no internal resolver logic...
 | 
					
						
							|  |  |  | // 
 | 
					
						
							| 
									
										
										
										
											2020-11-24 05:48:54 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | var CooperativePromise = | 
					
						
							|  |  |  | module.CooperativePromise = | 
					
						
							|  |  |  | object.Constructor('CooperativePromise', Promise, { | 
					
						
							|  |  |  | 	__handlers: null, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	get isSet(){ | 
					
						
							|  |  |  | 		return this.__handlers === false }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	set: function(value, resolve=true){ | 
					
						
							|  |  |  | 		// can't set twice...
 | 
					
						
							|  |  |  | 		if(this.isSet){ | 
					
						
							|  |  |  | 			throw new Error('.set(..): can not set twice') } | 
					
						
							|  |  |  | 		// bind to promise...
 | 
					
						
							|  |  |  | 		if(value && value.then && value.catch){ | 
					
						
							|  |  |  | 			value.then(handlers.resolve) | 
					
						
							|  |  |  | 			value.catch(handlers.reject) | 
					
						
							|  |  |  | 		// resolve with value...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			resolve ? | 
					
						
							|  |  |  | 				this.__handlers.resolve(value)  | 
					
						
							|  |  |  | 				: this.__handlers.reject(value) } | 
					
						
							|  |  |  | 		// cleanup and prevent setting twice...
 | 
					
						
							|  |  |  | 		this.__handlers = false | 
					
						
							|  |  |  | 		return this }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	then: IterablePromise.prototype.then, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__new__: function(){ | 
					
						
							|  |  |  | 		var handlers | 
					
						
							|  |  |  | 		var resolver = arguments[1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var obj = Reflect.construct( | 
					
						
							|  |  |  | 			CooperativePromise.__proto__,  | 
					
						
							|  |  |  | 			[function(resolve, reject){ | 
					
						
							|  |  |  | 				handlers = {resolve, reject}  | 
					
						
							|  |  |  | 				// NOTE: this is here to support builtin .then(..)
 | 
					
						
							|  |  |  | 				resolver | 
					
						
							|  |  |  | 					&& resolver(resolve, reject) }],  | 
					
						
							|  |  |  | 			CooperativePromise)  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Object.defineProperty(obj, '__handlers', { | 
					
						
							|  |  |  | 			value: handlers, | 
					
						
							|  |  |  | 			enumerable: false, | 
					
						
							|  |  |  | 			writable: true, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		return obj }, | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-22 23:50:05 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-30 12:12:00 +03:00
										 |  |  | // XXX EXPEREMENTAL...
 | 
					
						
							| 
									
										
										
										
											2022-05-30 12:07:28 +03:00
										 |  |  | var ProxyPromise = | 
					
						
							|  |  |  | module.ProxyPromise = | 
					
						
							|  |  |  | object.Constructor('ProxyPromise', Promise, { | 
					
						
							|  |  |  | 	__new__: function(context, constructor){ | 
					
						
							|  |  |  | 		var proto = 'prototype' in constructor ? | 
					
						
							|  |  |  | 			constructor.prototype | 
					
						
							|  |  |  | 			: constructor | 
					
						
							|  |  |  | 		var obj = Reflect.construct( | 
					
						
							|  |  |  | 			ProxyPromise.__proto__,  | 
					
						
							|  |  |  | 			[function(resolve, reject){ | 
					
						
							|  |  |  | 				context.then(resolve) | 
					
						
							|  |  |  | 				context.catch(reject) }],  | 
					
						
							|  |  |  | 			ProxyPromise)  | 
					
						
							|  |  |  | 		// populate...
 | 
					
						
							|  |  |  | 		// NOTE: we are not using object.deepKeys(..) here as we need 
 | 
					
						
							|  |  |  | 		// 		the key origin not to trigger property getters...
 | 
					
						
							|  |  |  | 		var seen = new Set() | 
					
						
							|  |  |  | 		while(proto != null){ | 
					
						
							|  |  |  | 			Object.entries(Object.getOwnPropertyDescriptors(proto)) | 
					
						
							|  |  |  | 				.forEach(function([key, value]){ | 
					
						
							|  |  |  | 					// skip overloaded keys...
 | 
					
						
							|  |  |  | 					if(seen.has(key)){ | 
					
						
							|  |  |  | 						return } | 
					
						
							|  |  |  | 					// skip non-functions...
 | 
					
						
							|  |  |  | 					if(typeof(value.value) != 'function'){ | 
					
						
							|  |  |  | 						return } | 
					
						
							|  |  |  | 					// skip non-enumerable except for Object.prototype.run(..)...
 | 
					
						
							|  |  |  | 					if(!(key == 'run'  | 
					
						
							|  |  |  | 								&& Object.prototype.run === value.value)  | 
					
						
							|  |  |  | 							&& !value.enumerable){ | 
					
						
							|  |  |  | 						return } | 
					
						
							|  |  |  | 					// proxy...
 | 
					
						
							|  |  |  | 					obj[key] = function(...args){ | 
					
						
							|  |  |  | 						// XXX should we also .catch(..) here???
 | 
					
						
							|  |  |  | 						return context.then(function(res){ | 
					
						
							|  |  |  | 							return res[key](...args) }) } }) | 
					
						
							|  |  |  | 			proto = proto.__proto__ }  | 
					
						
							|  |  |  | 		return obj }, | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-22 23:50:05 +03:00
										 |  |  | var PromiseMixin = | 
					
						
							|  |  |  | module.PromiseMixin = | 
					
						
							|  |  |  | object.Mixin('PromiseMixin', 'soft', { | 
					
						
							|  |  |  | 	iter: IterablePromise, | 
					
						
							| 
									
										
										
										
											2020-11-24 05:48:54 +03:00
										 |  |  | 	interactive: InteractivePromise, | 
					
						
							|  |  |  | 	cooperative: CooperativePromise, | 
					
						
							| 
									
										
										
										
											2020-11-22 23:50:05 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PromiseMixin(Promise) | 
					
						
							| 
									
										
										
										
											2022-06-01 16:15:30 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-30 12:07:28 +03:00
										 |  |  | // XXX EXPEREMENTAL...
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:15:30 +03:00
										 |  |  | var PromiseProtoMixin = | 
					
						
							|  |  |  | module.PromiseProtoMixin = | 
					
						
							|  |  |  | object.Mixin('PromiseProtoMixin', 'soft', { | 
					
						
							|  |  |  | 	as: ProxyPromise, | 
					
						
							| 
									
										
										
										
											2022-06-02 12:05:37 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// XXX
 | 
					
						
							|  |  |  | 	iter: function(){ | 
					
						
							|  |  |  | 		return IterablePromise(this) }, | 
					
						
							| 
									
										
										
										
											2022-06-01 16:15:30 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-30 12:07:28 +03:00
										 |  |  | PromiseProtoMixin(Promise.prototype) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-22 23:50:05 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-02 18:24:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set ts=4 sw=4 :                               */ return module }) |