reactive-channel
Version:
A simple yet powerful abstraction that enables communication between asynchronous tasks.
2 lines • 6.96 kB
JavaScript
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports):typeof define==`function`&&define.amd?define([`exports`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.reactiveChannel={}))})(this,function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(){let e=[];function t(t){if(e.length!==0)for(let n of e.slice())n(t)}function n(t){let n=e.indexOf(t);n!==-1&&e.splice(n,1)}function r(t){return e.indexOf(t)===-1&&e.push(t),()=>n(t)}function i(e){let t=r(n=>{t(),e(n)});return t}return{emit:t,subscribe:r,subscribeOnce:i,nOfSubscriptions(){return e.length}}}var n={instantiatingEffect:void 0,effectCount:0,isBatching:0,pendingEffectBatch:new Map,effectById:new Map,reactiveRootCount:0,rootByEffectId:new Map,rootUnsubscribes:new Map};function r(e,t){if(n.instantiatingEffect!==void 0){let r=n.instantiatingEffect,i=r.id;if(!r.dependencies.includes(e)){r.dependencies.push(e);let a=n.rootByEffectId.get(i),o=n.rootUnsubscribes.get(a);o||(o=[],n.rootUnsubscribes.set(a,o));let s=!0,c,l=t.subscribe(e=>{if(c=e,s){s=!1;return}let t=()=>{let e=n.instantiatingEffect;n.instantiatingEffect=void 0;try{r.cleanupFn?.(),r.cleanupFn=r.effectFn()}finally{n.instantiatingEffect=e}};n.isBatching>0?n.pendingEffectBatch.set(i,t):t()});return o.push(l),c}}return t.content()}var i={storeCount:0};function a(e,n){let a=e,o=t(),s,c=typeof n==`function`?n:n?.start,l=(typeof n==`function`?void 0:n?.comparator)??((e,t)=>e===t),u=()=>{if(o.nOfSubscriptions()>0)return a;let e;return f(t=>e=t)(),e},d=e=>{a!==void 0&&l(a,e)||(a=e,o.emit(a))},f=e=>{o.nOfSubscriptions()===0&&(s=c?.(d));let t=o.subscribe(e);return e(a),()=>{t(),o.nOfSubscriptions()===0&&(s?.(),s=void 0)}},p=e=>{d(e(u()))};i.storeCount++;let m=i.storeCount;return{content:u,set:d,watch:()=>r(m,{content:u,subscribe:f}),subscribe:f,update:p,nOfSubscriptions:o.nOfSubscriptions}}function o(e,t){let{content:n,nOfSubscriptions:r,subscribe:i,watch:o}=a(e,t);return{content:n,nOfSubscriptions:r,subscribe:i,watch:o}}function s(e,t,n){let r=Array.isArray(e),i=!r&&`subscribe`in e&&`nOfSubscriptions`in e&&`content`in e,a=i?1:r?e.length:Object.keys(e).length;return o(void 0,{comparator:n?.comparator,start:a===0?e=>{e(t(r?[]:{}))}:i?n=>e.subscribe(e=>n(t(e))):r?n=>{let r=Array(e.length),i=0,o=e.map((e,o)=>e.subscribe(e=>{if(i<a&&(r[o]=e,i++),i===a){let i=[...r];i[o]=e,n(t(i)),r=i}}));return()=>{for(let e of o)e();i=0}}:n=>{let r={},i=0,o=Object.entries(e).map(([e,o])=>o.subscribe(o=>{if(i<a&&(r[e]=o,i++),i===a){let i={...r};i[e]=o,n(t(i)),r=i}}));return()=>{for(let e of o)e();i=0}}})}var c=class extends Error{constructor(e,t){super(`queue doesn't contain enough elements, requested ${e}, filled slots ${t}`),this.requestedItems=e,this.filledSlots=t}},l=class extends Error{constructor(e,t){super(`queue doesn't have enough space, requested ${e}, available slots ${t}`),this.requestedItems=e,this.availableSlots=t}};function u(e,t){let n=Array.isArray(e),r=n?t??e.length:e,i=Array(r),o=0,u=0,d=a(0),f=s(d,e=>e===r),p=s(d,e=>e===0),m=s(d,e=>r-e);if(n){let t=Math.min(e.length,r);for(let n=0;n<t;n++)i[u]=e[n],u=(u+1)%r;d.update(e=>e+t)}let h=e=>{if(f.content())throw new l(1,0);i[u]=e,u=(u+1)%r,d.update(e=>e+1)},g=e=>{let t=m.content();if(t<e.length)throw new l(e.length,t);for(let t=0;t<e.length;t++)i[u]=e[t],u=(u+1)%r;d.update(t=>t+e.length)},_=()=>{o=0,u=0,i=Array(r),d.set(0)};function v(e){let t=d.content();if(e===void 0){if(t===0)throw new c(1,0);let e=i[o];return i[o]=void 0,o=(o+1)%r,d.update(e=>e-1),e}else{if(e>t)throw new c(e,t);let n=Array(e);for(let e=0;e<n.length;e++)n[e]=i[(o+e)%r],i[(o+e)%r]=void 0;return o=(o+e)%r,d.set(t-e),n}}let y=()=>v(d.content());function*b(){for(;d.content()>0;)yield v()}return{enqueue:h,enqueueMulti:g,dequeue:v,dequeueAll:y,toArray:()=>{let e=Array(d.content());for(let t=0;t<e.length;t++)e[t]=i[(o+t)%r];return e},at:e=>{let t=d.content();if(!(e>=t||e<-t))return e>=0?i[(o+e)%r]:i[(o+t+e)%r]},indexOf:e=>{let t=d.content();for(let n=0;n<t;n++)if(i[(o+n)%r]===e)return n;return-1},replace:(e,t)=>{let n=d.content();if(e>=n||e<-n)throw RangeError(`${e} is not a valid positive nor negative index. The number of filled slots is ${n}`);let a=e>=0?e:n+e,s=(o+a)%r,c=i[s];return i[s]=t,c},remove:e=>{let t=d.content();if(e>=t||e<-t)throw RangeError(`${e} is not a valid positive nor negative index. The number of filled slots is ${t}`);let n=e>=0?e:t+e,a=(o+n)%r,s=i[a];if(t-n<n){for(let e=o;e<o+t-n-1;e++)i[e%r]=i[(e+1)%r];u=(u+r-1)%r}else{for(let e=o+n-1;e>=o;e--)i[(e+1)%r]=i[e%r];o=(o+1)%r}return d.set(t-1),s},availableSlots$:m,filledSlots$:d,capacity:r,iter:b,[Symbol.iterator]:b,full$:f,empty$:p,clear:_}}var d=()=>void 0,f=class extends Error{constructor(){super(`channel full, cannot enqueue data`)}},p=class extends Error{constructor(){super(`channel closed`)}},m=class extends Error{constructor(){super(`channel has already too many pending recv`)}};function h(e){let{capacity:t=1024,maxConcurrentPendingRecv:n=1024}=e||{},r=u(t),i=u(t),o=u(n),c=a(!1),l=s([c,r.availableSlots$],([e,t])=>e?0:t),h=s([c,r.filledSlots$],([e,t])=>e?0:t),g=s(l,e=>e>0),_=s([h,o.full$],([e,t])=>e>0&&!t);async function v(e,t){if(c.content())throw new p;if(r.full$.content())throw new f;let n=d,a=d,s=new Promise((e,t)=>{n=e,a=t}),l;o.empty$.content()?(l={promise:s,resolveSend:n,rejectSend:a},r.enqueue(l),i.enqueue(e)):o.dequeue().resolveRecv({promise:s,resolveSend:n,rejectSend:a,value:e});try{if(!t?.signal)await s;else{let e=t.signal;e.throwIfAborted(),await Promise.race([s,new Promise((t,n)=>{e.addEventListener(`abort`,()=>{Promise.resolve().then(()=>n(e.reason)).catch(d)})})])}}catch(e){if(l){let e=r.indexOf(l);e!==-1&&(r.remove(e),i.remove(e))}throw e}}function y(e){if(c.content())throw new p;if(r.full$.content())throw new f;v(e).catch(d)}async function b(e){if(c.content())throw new p;let t;if(!r.empty$.content())t={...r.dequeue(),value:i.dequeue()};else{if(o.full$.content())throw new m;let n={resolveRecv:d,rejectRecv:d},r=new Promise((e,t)=>{n.resolveRecv=e,n.rejectRecv=t,o.enqueue(n)});try{if(!e?.signal)t=await r;else{let n=e.signal;n.throwIfAborted(),t=await Promise.race([r,new Promise((e,t)=>{n.addEventListener(`abort`,()=>{Promise.resolve().then(()=>t(n.reason)).catch(d)})})])}}catch(e){let t=o.indexOf(n);throw t!==-1&&o.remove(t),e}}return t.resolveSend(),t.value}async function*x(){for(;r.filledSlots$.content()>0;)yield await b()}function S(){if(c.content())return;c.set(!0);let e=new p;for(let t of o)t.rejectRecv(e);for(let t of r)t.rejectSend(e);i.clear()}return{buffer:i,tx:{send:y,sendWait:v,canWrite$:g,closed$:c,close:S,availableOutboxSlots$:l,capacity:t},rx:{pendingRecvPromises$:o.filledSlots$,recv:b,iter:x,[Symbol.asyncIterator]:x,canRead$:_,closed$:c,close:S,capacity:t,filledInboxSlots$:h}}}e.ChannelClosedError=p,e.ChannelFullError=f,e.ChannelTooManyPendingRecvError=m,e.NotEnoughAvailableSlotsQueueError=l,e.NotEnoughFilledSlotsQueueError=c,e.makeChannel=h});
//# sourceMappingURL=index.umd.js.map