| 
									
										
										
										
											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) | 
					
						
							| 
									
										
										
										
											2022-06-09 11:46:05 +03:00
										 |  |  | * 	<promise>.iter() | 
					
						
							| 
									
										
										
										
											2021-01-05 04:49:24 +03:00
										 |  |  | * 		Iterable promise object. | 
					
						
							| 
									
										
										
										
											2022-06-14 10:37:01 +03:00
										 |  |  | * 		Similar to Promise.all(..) but adds basic iterator API. | 
					
						
							| 
									
										
										
										
											2021-01-05 04:49:24 +03:00
										 |  |  | * | 
					
						
							|  |  |  | * 	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. | 
					
						
							|  |  |  | * | 
					
						
							| 
									
										
										
										
											2022-06-09 11:46:05 +03:00
										 |  |  | * 	<promise>.as(obj) | 
					
						
							|  |  |  | * 		Promise proxy. | 
					
						
							|  |  |  | * 		Proxies the methods available from obj to promise value. | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							| 
									
										
										
										
											2021-01-05 04:49:24 +03:00
										 |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							| 
									
										
										
										
											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') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-17 12:01:04 +03:00
										 |  |  | //var generator = require('./generator')
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-27 08:46:51 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											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...
 | 
					
						
							|  |  |  | // 
 | 
					
						
							| 
									
										
										
										
											2022-06-11 14:35:16 +03:00
										 |  |  | // NOTE: the following can not be implemented here:
 | 
					
						
							|  |  |  | // 			.splice(..)				- can't both modify and return
 | 
					
						
							|  |  |  | // 									  a result...
 | 
					
						
							|  |  |  | // 			.pop() / .shift()		- can't modify the promise, use 
 | 
					
						
							|  |  |  | // 									  .first() / .last() instead.
 | 
					
						
							|  |  |  | // 			[Symbol.iterator]()		- needs to be sync and we can't
 | 
					
						
							|  |  |  | // 									  know the number of elements to
 | 
					
						
							|  |  |  | // 									  return promises before the whole
 | 
					
						
							|  |  |  | // 									  iterable promise is resolved.
 | 
					
						
							| 
									
										
										
										
											2022-06-09 11:15:20 +03:00
										 |  |  | // NOTE: we are not using async/await here as we need to control the 
 | 
					
						
							|  |  |  | // 		type of promise returned in cases where we know we are returning 
 | 
					
						
							|  |  |  | // 		an array...
 | 
					
						
							| 
									
										
										
										
											2022-06-12 10:28:01 +03:00
										 |  |  | // NOTE: there is no point in implementing a 1:1 version of this that 
 | 
					
						
							|  |  |  | // 		would not support element expansion/contraction as it would only 
 | 
					
						
							|  |  |  | // 		simplify a couple of methods that are 1:1 (like .map(..) and 
 | 
					
						
							|  |  |  | // 		.some(..)) while methods like .filter(..) will throw everything
 | 
					
						
							|  |  |  | // 		back to the complex IterablePromise...
 | 
					
						
							| 
									
										
										
										
											2022-06-11 14:35:16 +03:00
										 |  |  | // 		
 | 
					
						
							|  |  |  | // XXX how do we handle errors/rejections???
 | 
					
						
							| 
									
										
										
										
											2022-06-14 10:37:01 +03:00
										 |  |  | // 		...mostly the current state is OK, but need more testing...
 | 
					
						
							| 
									
										
										
										
											2022-06-17 12:01:04 +03:00
										 |  |  | // XXX add support for async generators...
 | 
					
						
							| 
									
										
										
										
											2022-06-11 19:35:35 +03:00
										 |  |  | // 		
 | 
					
						
							| 
									
										
										
										
											2022-06-11 15:49:05 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-09 11:12:39 +03:00
										 |  |  | var iterPromiseProxy =  | 
					
						
							| 
									
										
										
										
											2022-06-15 03:44:24 +03:00
										 |  |  | module.iterPromiseProxy =  | 
					
						
							| 
									
										
										
										
											2022-06-09 11:12:39 +03:00
										 |  |  | function(name){ | 
					
						
							|  |  |  | 	return function(...args){ | 
					
						
							|  |  |  | 		return this.constructor( | 
					
						
							|  |  |  | 			this.then(function(lst){ | 
					
						
							|  |  |  | 				return lst[name](...args) })) } } | 
					
						
							|  |  |  | var promiseProxy = | 
					
						
							| 
									
										
										
										
											2022-06-15 03:44:24 +03:00
										 |  |  | module.promiseProxy = | 
					
						
							| 
									
										
										
										
											2022-06-09 11:12:39 +03:00
										 |  |  | function(name){ | 
					
						
							|  |  |  | 	return async function(...args){ | 
					
						
							|  |  |  | 		return (await this)[name](...args) } } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-09 06:22:32 +03:00
										 |  |  | var IterablePromise = | 
					
						
							|  |  |  | module.IterablePromise = | 
					
						
							|  |  |  | object.Constructor('IterablePromise', Promise, { | 
					
						
							| 
									
										
										
										
											2022-06-13 19:43:45 +03:00
										 |  |  | 	get STOP(){ | 
					
						
							|  |  |  | 		return Array.STOP }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }, { | 
					
						
							| 
									
										
										
										
											2022-06-11 14:35:16 +03:00
										 |  |  | 	// packed array...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Holds promise state.
 | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// Format:
 | 
					
						
							|  |  |  | 	// 	[
 | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 	//		<non-array-value>,
 | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 	//		[ <value> ],
 | 
					
						
							|  |  |  | 	//		<promise>,
 | 
					
						
							|  |  |  | 	//		...
 | 
					
						
							|  |  |  | 	// 	]
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2022-06-08 16:03:35 +03:00
										 |  |  | 	// This format has several useful features:
 | 
					
						
							| 
									
										
										
										
											2022-06-12 12:36:45 +03:00
										 |  |  | 	// 	- concatenating packed lists results in a packed list
 | 
					
						
							| 
									
										
										
										
											2022-06-08 16:03:35 +03:00
										 |  |  | 	// 	- adding an iterable promise (as-is) into a packed list results 
 | 
					
						
							|  |  |  | 	// 		in a packed list
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2022-06-09 01:33:14 +03:00
										 |  |  | 	// NOTE: in general iterable promises are implicitly immutable, so
 | 
					
						
							| 
									
										
										
										
											2022-06-12 12:36:45 +03:00
										 |  |  | 	// 		it is not recomended to ever edit this in-place...
 | 
					
						
							|  |  |  | 	// NOTE: we are not isolating or "protecting" any internals to 
 | 
					
						
							|  |  |  | 	// 		enable users to responsibly extend the code.
 | 
					
						
							| 
									
										
										
										
											2022-06-11 15:49:05 +03:00
										 |  |  | 	__packed: null, | 
					
						
							| 
									
										
										
										
											2020-11-10 01:58:51 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-11 15:49:05 +03:00
										 |  |  | 	// low-level .__packed handlers/helpers...
 | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2022-06-07 20:58:34 +03:00
										 |  |  | 	// NOTE: these can be useful for debugging and extending...
 | 
					
						
							| 
									
										
										
										
											2022-06-11 14:35:16 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// pack and oprionally transform/handle an array (sync)...
 | 
					
						
							| 
									
										
										
										
											2022-06-13 13:26:31 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: if 'types/Array' is imported this will support throwing STOP
 | 
					
						
							|  |  |  | 	// 		from the handler.
 | 
					
						
							|  |  |  | 	// 		Due to the async nature of promises though the way stops are 
 | 
					
						
							|  |  |  | 	// 		handled may be unpredictable -- the handlers can be run out 
 | 
					
						
							|  |  |  | 	// 		of order, as the nested promises resolve and thus throwing 
 | 
					
						
							|  |  |  | 	// 		stop will stop the handlers not yet run and not the next 
 | 
					
						
							|  |  |  | 	// 		handlers in sequence.
 | 
					
						
							|  |  |  | 	// 		XXX EXPEREMENTAL: STOP...
 | 
					
						
							| 
									
										
										
										
											2022-06-17 12:01:04 +03:00
										 |  |  | 	// XXX add support for async generators...
 | 
					
						
							| 
									
										
										
										
											2022-06-18 17:15:26 +03:00
										 |  |  | 	// 		...an async generator is not "parallel", i.e. intil one 
 | 
					
						
							| 
									
										
										
										
											2022-06-17 12:01:04 +03:00
										 |  |  | 	// 		returned promise is resolved the generator blocks (will not 
 | 
					
						
							|  |  |  | 	// 		advance)...
 | 
					
						
							| 
									
										
										
										
											2022-06-18 17:15:26 +03:00
										 |  |  | 	// 		...can we feed out a results one by one???
 | 
					
						
							| 
									
										
										
										
											2022-06-11 14:35:16 +03:00
										 |  |  | 	__pack: function(list, handler=undefined){ | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 		var that = this | 
					
						
							|  |  |  | 		// handle iterable promise list...
 | 
					
						
							|  |  |  | 		if(list instanceof IterablePromise){ | 
					
						
							| 
									
										
										
										
											2022-06-11 15:49:05 +03:00
										 |  |  | 			return this.__handle(list.__packed, handler) } | 
					
						
							| 
									
										
										
										
											2022-06-07 20:58:34 +03:00
										 |  |  | 		// handle promise list...
 | 
					
						
							|  |  |  | 		if(list instanceof Promise){ | 
					
						
							|  |  |  | 			return list.then(function(list){ | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 				return that.__pack(list, handler) }) } | 
					
						
							|  |  |  | 		// do the work...
 | 
					
						
							|  |  |  | 		// NOTE: packing and handling are mixed here because it's faster
 | 
					
						
							|  |  |  | 		// 		to do them both on a single list traverse...
 | 
					
						
							| 
									
										
										
										
											2022-06-07 20:58:34 +03:00
										 |  |  | 		var handle = !!handler | 
					
						
							|  |  |  | 		handler = handler  | 
					
						
							|  |  |  | 			?? function(elem){  | 
					
						
							|  |  |  | 				return [elem] } | 
					
						
							| 
									
										
										
										
											2022-06-13 03:27:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-13 03:31:38 +03:00
										 |  |  | 		//* XXX EXPEREMENTAL: STOP...
 | 
					
						
							| 
									
										
										
										
											2022-06-13 13:26:31 +03:00
										 |  |  | 		var stoppable = false | 
					
						
							| 
									
										
										
										
											2022-06-13 03:27:47 +03:00
										 |  |  | 		var stop = false | 
					
						
							| 
									
										
										
										
											2022-06-13 13:26:31 +03:00
										 |  |  | 		var map = 'map' | 
					
						
							|  |  |  | 		var pack = function(){ | 
					
						
							|  |  |  | 			return [list].flat() | 
					
						
							|  |  |  | 				[map](function(elem){ | 
					
						
							|  |  |  | 					return elem && elem.then ? | 
					
						
							|  |  |  | 							(stoppable ? | 
					
						
							| 
									
										
										
										
											2022-06-13 13:32:35 +03:00
										 |  |  | 								// stoppable -- need to handle stop async...
 | 
					
						
							| 
									
										
										
										
											2022-06-13 13:26:31 +03:00
										 |  |  | 								elem | 
					
						
							|  |  |  | 									.then(function(res){ | 
					
						
							|  |  |  | 										return !stop ? | 
					
						
							|  |  |  | 											handler(res) | 
					
						
							|  |  |  | 											: [] })  | 
					
						
							|  |  |  | 									// NOTE: we are using .catch(..) here
 | 
					
						
							|  |  |  | 									// 		instead of directly passing the
 | 
					
						
							|  |  |  | 									// 		error handler to be able to catch
 | 
					
						
							|  |  |  | 									// 		the STOP from the handler...
 | 
					
						
							|  |  |  | 									.catch(handleSTOP) | 
					
						
							|  |  |  | 								// non-stoppable...
 | 
					
						
							|  |  |  | 								: elem.then(handler)) | 
					
						
							|  |  |  | 						: elem instanceof Array ? | 
					
						
							|  |  |  | 							handler(elem) | 
					
						
							|  |  |  | 						// NOTE: we keep things that do not need protecting 
 | 
					
						
							|  |  |  | 						// 		from .flat() as-is...
 | 
					
						
							|  |  |  | 						: !handle ? | 
					
						
							|  |  |  | 							elem | 
					
						
							|  |  |  | 						: handler(elem) }) } | 
					
						
							| 
									
										
										
										
											2022-06-13 03:27:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-13 13:26:31 +03:00
										 |  |  | 		// pack (stoppable)...
 | 
					
						
							| 
									
										
										
										
											2022-06-13 19:43:45 +03:00
										 |  |  | 		if(!!this.constructor.STOP){ | 
					
						
							| 
									
										
										
										
											2022-06-13 13:26:31 +03:00
										 |  |  | 			stoppable = true | 
					
						
							|  |  |  | 			map = 'smap' | 
					
						
							|  |  |  | 			var handleSTOP = function(err){ | 
					
						
							|  |  |  | 				stop = err | 
					
						
							| 
									
										
										
										
											2022-06-13 19:43:45 +03:00
										 |  |  | 				if(err === that.constructor.STOP | 
					
						
							|  |  |  | 						|| err instanceof that.constructor.STOP){ | 
					
						
							| 
									
										
										
										
											2022-06-13 13:26:31 +03:00
										 |  |  | 					return 'value' in err ? | 
					
						
							|  |  |  | 						err.value | 
					
						
							|  |  |  | 						: [] } | 
					
						
							|  |  |  | 				throw err } | 
					
						
							|  |  |  | 			try{ | 
					
						
							|  |  |  | 				return pack() | 
					
						
							|  |  |  | 			}catch(err){ | 
					
						
							| 
									
										
										
										
											2022-06-13 13:32:35 +03:00
										 |  |  | 				return handleSTOP(err) } } | 
					
						
							| 
									
										
										
										
											2022-06-13 13:26:31 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// pack (non-stoppable)...
 | 
					
						
							| 
									
										
										
										
											2022-06-13 13:32:35 +03:00
										 |  |  | 		return pack() }, | 
					
						
							| 
									
										
										
										
											2022-06-13 03:31:38 +03:00
										 |  |  | 		/*/ | 
					
						
							|  |  |  | 		return [list].flat() | 
					
						
							|  |  |  | 			.map(function(elem){ | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 				return elem && elem.then ? | 
					
						
							|  |  |  | 						//that.__pack(elem, handler)
 | 
					
						
							| 
									
										
										
										
											2022-06-13 13:26:31 +03:00
										 |  |  | 						elem.then(handler) | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 					: elem instanceof Array ? | 
					
						
							|  |  |  | 						handler(elem) | 
					
						
							|  |  |  | 					// NOTE: we keep things that do not need protecting 
 | 
					
						
							|  |  |  | 					// 		from .flat() as-is...
 | 
					
						
							| 
									
										
										
										
											2022-06-07 20:58:34 +03:00
										 |  |  | 					: !handle ? | 
					
						
							|  |  |  | 						elem | 
					
						
							|  |  |  | 					: handler(elem) }) }, | 
					
						
							| 
									
										
										
										
											2022-06-13 13:26:31 +03:00
										 |  |  | 		//*/
 | 
					
						
							| 
									
										
										
										
											2022-06-11 14:35:16 +03:00
										 |  |  | 	// transform/handle packed array (sync)...
 | 
					
						
							|  |  |  | 	__handle: function(list, handler=undefined){ | 
					
						
							| 
									
										
										
										
											2022-06-07 20:58:34 +03:00
										 |  |  | 		var that = this | 
					
						
							|  |  |  | 		if(typeof(list) == 'function'){ | 
					
						
							|  |  |  | 			handler = list | 
					
						
							| 
									
										
										
										
											2022-06-11 15:49:05 +03:00
										 |  |  | 			list = this.__packed } | 
					
						
							| 
									
										
										
										
											2022-06-07 20:58:34 +03:00
										 |  |  | 		if(!handler){ | 
					
						
							|  |  |  | 			return list } | 
					
						
							|  |  |  | 		// handle promise list...
 | 
					
						
							|  |  |  | 		if(list instanceof Promise){ | 
					
						
							|  |  |  | 			return list.then(function(list){ | 
					
						
							|  |  |  | 				return that.__handle(list, handler) }) } | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 		// do the work...
 | 
					
						
							|  |  |  | 		// NOTE: since each section of the packed .__array is the same 
 | 
					
						
							|  |  |  | 		// 		structure as the input we'll use .__pack(..) to handle 
 | 
					
						
							|  |  |  | 		// 		them, this also keeps all the handling code in one place.
 | 
					
						
							| 
									
										
										
										
											2022-06-13 03:31:38 +03:00
										 |  |  | 		//* XXX EXPEREMENTAL: STOP...
 | 
					
						
							| 
									
										
										
										
											2022-06-13 19:43:45 +03:00
										 |  |  | 		var map = !!this.constructor.STOP ? | 
					
						
							| 
									
										
										
										
											2022-06-13 03:27:47 +03:00
										 |  |  | 			'smap' | 
					
						
							|  |  |  | 			: 'map' | 
					
						
							|  |  |  | 		return list[map](function(elem){ | 
					
						
							| 
									
										
										
										
											2022-06-13 03:31:38 +03:00
										 |  |  | 		/*/ | 
					
						
							|  |  |  | 		return list.map(function(elem){ | 
					
						
							|  |  |  | 		//*/
 | 
					
						
							| 
									
										
										
										
											2022-06-07 20:58:34 +03:00
										 |  |  | 			return elem instanceof Array ? | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 					that.__pack(elem, handler) | 
					
						
							| 
									
										
										
										
											2022-06-07 20:58:34 +03:00
										 |  |  | 				: elem instanceof Promise ? | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 					that.__pack(elem, handler) | 
					
						
							| 
									
										
										
										
											2022-06-16 00:32:58 +03:00
										 |  |  | 						//.then(function(elem){
 | 
					
						
							|  |  |  | 						.then(function([elem]){ | 
					
						
							|  |  |  | 							return elem }) | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 				: [handler(elem)] }) | 
					
						
							| 
									
										
										
										
											2022-06-07 20:58:34 +03:00
										 |  |  |    			.flat() }, | 
					
						
							| 
									
										
										
										
											2022-06-11 14:35:16 +03:00
										 |  |  | 	// unpack array (async)...
 | 
					
						
							|  |  |  | 	__unpack: async function(list){ | 
					
						
							| 
									
										
										
										
											2022-06-07 20:58:34 +03:00
										 |  |  | 		list = list  | 
					
						
							| 
									
										
										
										
											2022-06-11 15:49:05 +03:00
										 |  |  | 			?? this.__packed | 
					
						
							| 
									
										
										
										
											2022-06-07 20:58:34 +03:00
										 |  |  | 		// handle promise list...
 | 
					
						
							| 
									
										
										
										
											2022-06-11 14:35:16 +03:00
										 |  |  | 		return list instanceof Promise ? | 
					
						
							|  |  |  | 			this.__unpack(await list) | 
					
						
							|  |  |  | 			// do the work...
 | 
					
						
							|  |  |  | 			: (await Promise.all(list)) | 
					
						
							|  |  |  | 				.flat() }, | 
					
						
							| 
									
										
										
										
											2022-06-07 20:58:34 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 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
 | 
					
						
							| 
									
										
										
										
											2022-06-11 11:36:13 +03:00
										 |  |  | 	// 		contract depending on handlers (e.g. .filter(..) can remove 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 21:35:04 +03:00
										 |  |  | 	// 		items)...
 | 
					
						
							| 
									
										
										
										
											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){ | 
					
						
							| 
									
										
										
										
											2022-06-06 12:29:13 +03:00
										 |  |  | 				var res = func(e) | 
					
						
							|  |  |  | 				return res instanceof Promise ? | 
					
						
							|  |  |  | 		   			res.then(function(e){  | 
					
						
							|  |  |  | 						return [e] }) | 
					
						
							|  |  |  | 					: [res] }) }, | 
					
						
							| 
									
										
										
										
											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){ | 
					
						
							| 
									
										
										
										
											2022-06-06 12:29:13 +03:00
										 |  |  | 				var res = func(e) | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 				var _filter = function(elem){ | 
					
						
							|  |  |  | 					return res ? | 
					
						
							|  |  |  | 						[elem] | 
					
						
							|  |  |  | 						: [] } | 
					
						
							| 
									
										
										
										
											2022-06-06 12:29:13 +03:00
										 |  |  | 				return res instanceof Promise ? | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 					res.then(_filter) | 
					
						
							|  |  |  | 					: _filter(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-02 12:05:37 +03:00
										 |  |  | 	// NOTE: the items can be handled out of order because the nested 
 | 
					
						
							| 
									
										
										
										
											2022-06-08 03:54:14 +03:00
										 |  |  | 	// 		promises can resolve in any order...
 | 
					
						
							| 
									
										
										
										
											2022-06-02 12:05:37 +03:00
										 |  |  | 	// NOTE: since order of execution can not be guaranteed there is no
 | 
					
						
							| 
									
										
										
										
											2022-06-12 10:28:01 +03:00
										 |  |  | 	// 		point in implementing .reduceRight(..) in the same way 
 | 
					
						
							|  |  |  | 	// 		(see below)...
 | 
					
						
							| 
									
										
										
										
											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-09 01:33:14 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-11 15:49:05 +03:00
										 |  |  | 		var lst = this.__packed | 
					
						
							| 
									
										
										
										
											2022-06-03 19:41:13 +03:00
										 |  |  | 		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-08 03:10:36 +03:00
										 |  |  | 	// NOTE: the following methods can create an unresolved promise from 
 | 
					
						
							|  |  |  | 	// 		a resolved promise...
 | 
					
						
							| 
									
										
										
										
											2022-06-04 03:01:54 +03:00
										 |  |  | 	concat: function(other){ | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 		var that = this | 
					
						
							|  |  |  | 		var cur = this.__pack(this) | 
					
						
							|  |  |  | 		var other = this.__pack(other) | 
					
						
							| 
									
										
										
										
											2022-06-07 20:58:34 +03:00
										 |  |  | 		return this.constructor( | 
					
						
							| 
									
										
										
										
											2022-06-08 03:38:47 +03:00
										 |  |  | 			// NOTE: we need to keep things as exposed as possible, this 
 | 
					
						
							|  |  |  | 			// 		is why we're not blanketing all the cases with 
 | 
					
						
							|  |  |  | 			// 		Promise.all(..)...
 | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 			(cur instanceof Promise  | 
					
						
							|  |  |  | 					&& other instanceof Promise) ? | 
					
						
							| 
									
										
										
										
											2022-06-08 03:38:47 +03:00
										 |  |  | 				[cur, other] | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 			: cur instanceof Promise ? | 
					
						
							| 
									
										
										
										
											2022-06-08 03:38:47 +03:00
										 |  |  | 				[cur, ...other] | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 			: other instanceof Promise ? | 
					
						
							| 
									
										
										
										
											2022-06-08 03:38:47 +03:00
										 |  |  | 				[...cur, other] | 
					
						
							| 
									
										
										
										
											2022-06-08 03:45:06 +03:00
										 |  |  | 			: [...cur, ...other], | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 			'raw') }, | 
					
						
							| 
									
										
										
										
											2022-06-04 03:01:54 +03:00
										 |  |  | 	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-11 14:35:16 +03:00
										 |  |  | 	// proxy methods...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// These require the whole promise to resolve to trigger.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// An exception to this would be .at(0)/.first() and .at(-1)/.last()
 | 
					
						
							|  |  |  | 	// that can get the target element if it's accessible.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: methods that are guaranteed to return an array will return
 | 
					
						
							|  |  |  | 	// 		an iterable promise (created with iterPromiseProxy(..))...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2022-06-09 01:33:14 +03:00
										 |  |  | 	at: async function(i){ | 
					
						
							| 
									
										
										
										
											2022-06-11 15:49:05 +03:00
										 |  |  | 		var list = this.__packed | 
					
						
							| 
									
										
										
										
											2022-06-09 01:33:14 +03:00
										 |  |  | 		return ((i != 0 && i != -1) | 
					
						
							|  |  |  | 					|| list instanceof Promise | 
					
						
							| 
									
										
										
										
											2022-06-15 10:36:33 +03:00
										 |  |  | 					// XXX not sure if this is correct...
 | 
					
						
							| 
									
										
										
										
											2022-06-09 01:33:14 +03:00
										 |  |  | 					|| list.at(i) instanceof Promise) ? | 
					
						
							|  |  |  | 				(await this).at(i) | 
					
						
							|  |  |  | 			// NOTE: we can only reason about first/last explicit elements, 
 | 
					
						
							| 
									
										
										
										
											2022-06-09 11:12:39 +03:00
										 |  |  | 			// 		anything else is non-deterministic...
 | 
					
						
							| 
									
										
										
										
											2022-06-09 01:33:14 +03:00
										 |  |  | 			: list.at(i) instanceof Promise ? | 
					
						
							|  |  |  | 				[await list.at(i)].flat().at(i) | 
					
						
							|  |  |  | 			: list.at(i) instanceof Array ? | 
					
						
							|  |  |  | 				list.at(i).at(i) | 
					
						
							|  |  |  | 			: list.at(i) }, | 
					
						
							|  |  |  | 	first: function(){ | 
					
						
							|  |  |  | 		return this.at(0) }, | 
					
						
							|  |  |  | 	last: function(){ | 
					
						
							|  |  |  | 		return this.at(-1) }, | 
					
						
							| 
									
										
										
										
											2022-06-04 03:10:49 +03:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2022-06-11 19:35:35 +03:00
										 |  |  | 	// NOTE: unlike .reduce(..) this needs the parent fully resolved 
 | 
					
						
							|  |  |  | 	// 		to be able to iterate from the end.
 | 
					
						
							| 
									
										
										
										
											2022-06-13 19:43:45 +03:00
										 |  |  | 	// XXX is it faster to do .reverse().reduce(..) ???
 | 
					
						
							| 
									
										
										
										
											2022-06-11 19:35:35 +03:00
										 |  |  | 	reduceRight: promiseProxy('reduceRight'), | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-09 11:12:39 +03:00
										 |  |  | 	// NOTE: there is no way we can do a sync generator returning 
 | 
					
						
							| 
									
										
										
										
											2022-06-13 20:10:09 +03:00
										 |  |  | 	// 		promises for values because any promise in .__packed makes 
 | 
					
						
							|  |  |  | 	// 		the value count/index non-deterministic...
 | 
					
						
							| 
									
										
										
										
											2022-06-09 11:12:39 +03:00
										 |  |  | 	sort: iterPromiseProxy('sort'), | 
					
						
							|  |  |  | 	slice: iterPromiseProxy('slice'), | 
					
						
							| 
									
										
										
										
											2022-06-12 10:28:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-09 11:12:39 +03:00
										 |  |  | 	entries: iterPromiseProxy('entries'), | 
					
						
							|  |  |  | 	keys: iterPromiseProxy('keys'), | 
					
						
							|  |  |  | 	values: iterPromiseProxy('values'), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	indexOf: promiseProxy('indexOf'), | 
					
						
							| 
									
										
										
										
											2022-06-11 19:35:35 +03:00
										 |  |  | 	lastIndexOf: promiseProxy('lastIndexOf'), | 
					
						
							| 
									
										
										
										
											2022-06-09 11:12:39 +03:00
										 |  |  | 	includes: promiseProxy('includes'), | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-13 22:48:07 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	.find(<func>)
 | 
					
						
							|  |  |  | 	// 	.find(<func>, 'value')
 | 
					
						
							|  |  |  | 	// 		-> <promise>(<value>)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	.find(<func>, 'result')
 | 
					
						
							|  |  |  | 	// 		-> <promise>(<result>)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	.find(<func>, 'bool')
 | 
					
						
							|  |  |  | 	// 		-> <promise>(<bool>)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this is slightly different to Array's .find(..) in that it 
 | 
					
						
							|  |  |  | 	// 		accepts the result value enabling returning both the value 
 | 
					
						
							|  |  |  | 	// 		itself ('value', default), the test function's result 
 | 
					
						
							|  |  |  | 	// 		('result') or true/false ('bool') -- this is added to be 
 | 
					
						
							|  |  |  | 	// 		able to distinguish between the undefined as a stored value 
 | 
					
						
							|  |  |  | 	// 		and undefined as a "nothing found" result.
 | 
					
						
							| 
									
										
										
										
											2022-06-13 20:10:09 +03:00
										 |  |  | 	// NOTE: I do not get how essentially identical methods .some(..) 
 | 
					
						
							| 
									
										
										
										
											2022-06-13 22:48:07 +03:00
										 |  |  | 	// 		and .find(..) got added to JS's Array...
 | 
					
						
							|  |  |  | 	// 		the only benefit is that .some(..) handles undefined values 
 | 
					
						
							|  |  |  | 	// 		stored in the array better...
 | 
					
						
							| 
									
										
										
										
											2022-06-13 19:43:45 +03:00
										 |  |  | 	// NOTE: this will return the result as soon as it's available but 
 | 
					
						
							| 
									
										
										
										
											2022-06-13 20:10:09 +03:00
										 |  |  | 	// 		it will not stop the created but unresolved at the time 
 | 
					
						
							|  |  |  | 	// 		promises from executing, this is both good and bad:
 | 
					
						
							|  |  |  | 	// 		+ it will not break other clients waiting for promises 
 | 
					
						
							|  |  |  | 	// 			to resolve...
 | 
					
						
							|  |  |  | 	// 		- if no clients are available this can lead to wasted 
 | 
					
						
							|  |  |  | 	// 			CPU time...
 | 
					
						
							| 
									
										
										
										
											2022-06-13 22:48:07 +03:00
										 |  |  | 	find: async function(func, result='value'){ | 
					
						
							| 
									
										
										
										
											2022-06-13 19:43:45 +03:00
										 |  |  | 		var that = this | 
					
						
							| 
									
										
										
										
											2022-06-13 20:10:09 +03:00
										 |  |  | 		// NOTE: not using pure await here as this is simpler to actually 
 | 
					
						
							|  |  |  | 		// 		control the moment the resulting promise resolves without 
 | 
					
						
							|  |  |  | 		// 		the need for juggling state...
 | 
					
						
							|  |  |  | 		return new Promise(function(resolve, reject){ | 
					
						
							|  |  |  | 			var resolved = false | 
					
						
							|  |  |  | 			that.map(function(elem){ | 
					
						
							| 
									
										
										
										
											2022-06-13 22:48:07 +03:00
										 |  |  | 					var res = func(elem) | 
					
						
							|  |  |  | 					if(res){ | 
					
						
							| 
									
										
										
										
											2022-06-13 20:10:09 +03:00
										 |  |  | 						resolved = true | 
					
						
							| 
									
										
										
										
											2022-06-13 22:48:07 +03:00
										 |  |  | 						resolve( | 
					
						
							|  |  |  | 							result == 'bool' ? | 
					
						
							|  |  |  | 								true | 
					
						
							|  |  |  | 							: result == 'result' ? | 
					
						
							|  |  |  | 								res | 
					
						
							|  |  |  | 							: elem) | 
					
						
							| 
									
										
										
										
											2022-06-13 20:10:09 +03:00
										 |  |  | 						// XXX EXPEREMENTAL: STOP...
 | 
					
						
							|  |  |  | 						// NOTE: we do not need to throw STOP here 
 | 
					
						
							|  |  |  | 						// 		but it can prevent some overhead...
 | 
					
						
							|  |  |  | 						if(that.constructor.STOP){ | 
					
						
							|  |  |  | 							throw that.constructor.STOP } } }) | 
					
						
							|  |  |  | 				.then(function(){ | 
					
						
							|  |  |  | 					resolved | 
					
						
							| 
									
										
										
										
											2022-06-13 22:48:07 +03:00
										 |  |  | 						|| resolve( | 
					
						
							|  |  |  | 							result == 'bool' ? | 
					
						
							|  |  |  | 								false | 
					
						
							|  |  |  | 								: undefined) }) }) }, | 
					
						
							| 
									
										
										
										
											2022-06-13 20:10:09 +03:00
										 |  |  | 	findIndex: promiseProxy('findIndex'), | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-13 22:48:07 +03:00
										 |  |  | 	// NOTE: this is just a special-case of .find(..)
 | 
					
						
							| 
									
										
										
										
											2022-06-13 20:10:09 +03:00
										 |  |  | 	some: async function(func){ | 
					
						
							| 
									
										
										
										
											2022-06-13 22:48:07 +03:00
										 |  |  | 		return this.find(func, 'bool') }, | 
					
						
							| 
									
										
										
										
											2022-06-13 20:10:09 +03:00
										 |  |  | 	every: promiseProxy('every'), | 
					
						
							| 
									
										
										
										
											2022-06-09 01:33:14 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-15 10:36:33 +03:00
										 |  |  | 	// this is defined globally as Promise.prototype.iter(..)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// for details see: PromiseMixin(..) below...
 | 
					
						
							|  |  |  | 	//iter: function(handler=undefined){ ... },
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-11 14:35:16 +03:00
										 |  |  | 	// promise api...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-11 14:35:16 +03:00
										 |  |  | 	// constructor...
 | 
					
						
							| 
									
										
										
										
											2020-11-17 21:35:04 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Promise.iter([ .. ])
 | 
					
						
							|  |  |  | 	//		-> iterable-promise
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Promise.iter([ .. ], handler)
 | 
					
						
							|  |  |  | 	//		-> iterable-promise
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	handler(e)
 | 
					
						
							| 
									
										
										
										
											2022-06-09 22:49:43 +03:00
										 |  |  | 	// 		-> [value, ..]
 | 
					
						
							| 
									
										
										
										
											2020-11-16 02:38:19 +03:00
										 |  |  | 	// 		-> []
 | 
					
						
							| 
									
										
										
										
											2022-06-09 22:49:43 +03:00
										 |  |  | 	// 		-> <promise>
 | 
					
						
							| 
									
										
										
										
											2020-11-16 02:38:19 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2020-11-17 21:35:04 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2022-06-08 03:54:14 +03:00
										 |  |  | 	// NOTE: element index is unknowable until the full list is expanded
 | 
					
						
							| 
									
										
										
										
											2020-11-17 21:35:04 +03:00
										 |  |  | 	// 		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...
 | 
					
						
							| 
									
										
										
										
											2022-06-15 03:44:24 +03:00
										 |  |  | 	// 			...this may be quite an overhead...
 | 
					
						
							| 
									
										
										
										
											2020-11-18 01:02:00 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2022-06-08 03:54:14 +03:00
										 |  |  | 	// Special cases useful for extending this constructor...
 | 
					
						
							| 
									
										
										
										
											2020-11-18 06:09:43 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2022-06-11 15:49:05 +03:00
										 |  |  | 	//	Set raw .__packed without any pre-processing...
 | 
					
						
							| 
									
										
										
										
											2022-06-03 19:41:13 +03:00
										 |  |  | 	//	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
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2022-06-13 13:26:31 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: if 'types/Array' is imported this will support throwing STOP,
 | 
					
						
							|  |  |  | 	// 		for more info see notes for .__pack(..)
 | 
					
						
							|  |  |  | 	// 		XXX EXPEREMENTAL: STOP...
 | 
					
						
							| 
									
										
										
										
											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){ | 
					
						
							| 
									
										
										
										
											2022-06-08 03:58:43 +03:00
										 |  |  | 				// NOTE: this is here for Promise compatibility...
 | 
					
						
							| 
									
										
										
										
											2020-11-10 01:58:51 +03:00
										 |  |  | 				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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-08 16:03:35 +03:00
										 |  |  | 		// populate new instance...
 | 
					
						
							| 
									
										
										
										
											2020-11-17 16:12:13 +03:00
										 |  |  | 		if(promise){ | 
					
						
							| 
									
										
										
										
											2022-06-08 03:54:14 +03:00
										 |  |  | 			// handle/pack input data...
 | 
					
						
							| 
									
										
										
										
											2022-06-03 19:41:13 +03:00
										 |  |  | 			if(handler != 'raw'){ | 
					
						
							| 
									
										
										
										
											2022-06-07 20:58:34 +03:00
										 |  |  | 				list = list instanceof IterablePromise ? | 
					
						
							| 
									
										
										
										
											2022-06-11 15:49:05 +03:00
										 |  |  | 					this.__handle(list.__packed, handler) | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 					: this.__pack(list, handler) } | 
					
						
							| 
									
										
										
										
											2022-06-11 15:49:05 +03:00
										 |  |  | 			Object.defineProperty(obj, '__packed', { | 
					
						
							| 
									
										
										
										
											2020-11-17 21:35:04 +03:00
										 |  |  | 				value: list, | 
					
						
							|  |  |  | 				enumerable: false, | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2020-11-17 16:12:13 +03:00
										 |  |  | 			// handle promise state...
 | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 			this.__unpack(list) | 
					
						
							| 
									
										
										
										
											2022-06-07 20:58:34 +03:00
										 |  |  | 				.then(function(list){ | 
					
						
							|  |  |  | 					promise.resolve(list) }) | 
					
						
							| 
									
										
										
										
											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 ? | 
					
						
							| 
									
										
										
										
											2022-06-11 16:04:56 +03:00
										 |  |  | 					// 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...
 | 
					
						
							| 
									
										
										
										
											2021-04-07 03:32:23 +03:00
										 |  |  | 					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.
 | 
					
						
							| 
									
										
										
										
											2022-06-15 03:44:24 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-11-24 20:23:22 +03:00
										 |  |  | // 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, { | 
					
						
							| 
									
										
										
										
											2022-06-11 16:04:56 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	then: IterablePromise.prototype.then, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-12 10:28:01 +03:00
										 |  |  | 	__new__: function(context, other, nooverride=false){ | 
					
						
							|  |  |  | 		var proto = 'prototype' in other ? | 
					
						
							|  |  |  | 			other.prototype | 
					
						
							|  |  |  | 			: other | 
					
						
							| 
									
										
										
										
											2022-05-30 12:07:28 +03:00
										 |  |  | 		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() | 
					
						
							| 
									
										
										
										
											2022-06-12 10:28:01 +03:00
										 |  |  | 		nooverride = nooverride instanceof Array ? | 
					
						
							|  |  |  | 			new Set(nooverride) | 
					
						
							|  |  |  | 			: nooverride | 
					
						
							| 
									
										
										
										
											2022-05-30 12:07:28 +03:00
										 |  |  | 		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 } | 
					
						
							| 
									
										
										
										
											2022-06-12 10:28:01 +03:00
										 |  |  | 					// do not override existing methods...
 | 
					
						
							|  |  |  | 					if(nooverride === true ?  | 
					
						
							|  |  |  | 								key in obj | 
					
						
							|  |  |  | 							: nooverride instanceof Set ? | 
					
						
							|  |  |  | 								nooverride.has(key) | 
					
						
							|  |  |  | 							: nooverride){ | 
					
						
							|  |  |  | 						return } | 
					
						
							| 
									
										
										
										
											2022-05-30 12:07:28 +03:00
										 |  |  | 					// proxy...
 | 
					
						
							| 
									
										
										
										
											2022-06-09 11:12:39 +03:00
										 |  |  | 					obj[key] = promiseProxy(key) }) | 
					
						
							| 
									
										
										
										
											2022-05-30 12:07:28 +03:00
										 |  |  | 			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
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var PromiseProtoMixin = | 
					
						
							|  |  |  | module.PromiseProtoMixin = | 
					
						
							|  |  |  | object.Mixin('PromiseProtoMixin', 'soft', { | 
					
						
							|  |  |  | 	as: ProxyPromise, | 
					
						
							| 
									
										
										
										
											2022-06-11 16:04:56 +03:00
										 |  |  | 	iter: function(handler=undefined){ | 
					
						
							| 
									
										
										
										
											2022-06-08 03:10:36 +03:00
										 |  |  | 		return IterablePromise(this, handler) }, | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  | /********************************************************************** | 
					
						
							| 
									
										
										
										
											2022-06-11 13:53:24 +03:00
										 |  |  | * vim:set ts=4 sw=4 nowrap :                        */ return module }) |