123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131moduleLog=Debug.LogmoduleMake(C:S.CORE_TYPES)=structopenCmoduleLocal_struct_promise=Local_struct_promise.Make(C)classtyperesolver_cap=objectinheritC.capmethodresolve:C.cap->unitmethodbreak:Exception.t->unitend(* Operations to perform when resolved. *)typepending=|CallofC.struct_resolver*Wire.Request.t|Watcherof(cap->unit)typeunresolved={queue:pendingQueue.t;on_release:(unit->unit)Queue.t;mutablerc:RC.t;}typecap_promise_state=|Unresolvedofunresolved|Resolvedofcapletreleased=C.broken_cap(Exception.v"(released)")classlocal_promise=object(self:#cap)valmutablestate=Unresolved{rc=RC.one;queue=Queue.create();on_release=Queue.create()}valid=Debug.OID.next()methodprivaterelease_while_unresolved=()methodcallresultsmsg=matchstatewith|Unresolved{queue;_}->Queue.add(Call(results,msg))queue|Resolvedcap->cap#callresultsmsgmethodupdate_rcd=matchstatewith|Unresolvedu->u.rc<-RC.sumu.rcd~pp:(funf->self#ppf);ifRC.is_zerou.rcthen(state<-Resolvedreleased;self#release_while_unresolved;Queue.iter(funf->f())u.on_release)|Resolvedx->x#update_rcdmethodwhen_releasedfn=matchstatewith|Unresolvedu->Queue.addfnu.on_release|Resolvedx->x#when_releasedfnmethodresolve(cap:cap)=matchstatewith|UnresolveduwhenRC.is_zerou.rc->Log.debug(funf->f"Ignoring resolution of unused promise %t to %t"self#ppcap#pp);C.dec_refcap|Unresolved{queue;rc;on_release}->letppf=self#ppfinRC.check~pprc;letcap=matchcap#blockerwith|Someblockerwhenblocker=(self:>base_ref)->letmsg=Fmt.str"@[<v>Attempt to create a cycle detected:@,\
Resolving %t with %t would create a cycle@]"self#ppcap#ppinLog.info(funf->f"%s"msg);C.dec_refcap;C.broken_cap(Exception.vmsg)|_->capinbeginmatchRC.to_intrcwith|Somerc->cap#update_rc(rc-1);(* Transfer our ref-count *)|None->()end;state<-Resolvedcap;Log.debug(funf->f"Resolved local cap promise: %t"self#pp);letforward=function|Watcherfn->C.inc_refcap;fncap|Call(result,msg)->cap#callresultmsginQueue.iterforwardqueue;Queue.iter(funf->cap#when_releasedf)on_release|Resolved_->Fmt.failwith"Can't resolve %t to %t; it's already resolved!"self#ppcap#ppmethodbreakex=self#resolve(broken_capex)methodshortest=matchstatewith|Unresolved_->(self:>cap)|Resolvedcap->cap#shortestmethodproblem=matchstatewith|Unresolved_->None|Resolvedcap->cap#problemmethodblocker=matchstatewith|Unresolved_->Some(self:>base_ref)|Resolvedcap->cap#blockermethodwhen_more_resolvedfn=matchstatewith|Unresolved{queue;_}->Queue.add(Watcherfn)queue|Resolvedx->x#when_more_resolvedfnmethodppf=matchstatewith|Unresolvedu->Fmt.pff"local-cap-promise(%a, %a) -> (unresolved)"Debug.OID.ppidRC.ppu.rc|Resolvedcap->Fmt.pff"local-cap-promise(%a) -> %t"Debug.OID.ppidcap#ppmethodcheck_invariants=letppf=self#ppfinmatchstatewith|Unresolvedu->RC.check~ppu.rc|Resolvedcap->cap#check_invariantsmethodsealed_dispatch_=Noneendletlocal_promise()=(newlocal_promise:>resolver_cap)end