12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061open!Core_kernelopen!ImportmoduleIvar=Ivar0moduleHandler=Ivar.Handler(* Deferreds present a covariant view of ivars. We could actually implement deferreds
using a record of closures, as in the [essence_of_deferred] record below, for which the
OCaml type checker can infer covariance. However, doing so would make [Ivar.read] very
costly, because it would have to allocate lots of closures and a record. Instead of
doing this, we make deferreds an abstract covariant type, which concretely is just the
ivar, and use [Obj.magic] to convert back and forth between a deferred and its concrete
representation as an ivar. This [Obj.magic] is safe because the representation is
always just an ivar, and the covariance follows from the fact that all the deferred
operations are equivalent to those implemented directly on top of the
[essence_of_deferred].
{[
type (+'a, 'execution_context) essence_of_deferred =
{ peek : unit -> 'a option
; is_determined : unit -> bool
; upon : ('a -> unit) -> unit
; upon' : ('a -> unit) -> Unregister.t
; install_removable_handler : ('a, 'execution_context) Raw_handler.t -> Unregister.t; } ]} *)type+'at='aTypes.Deferred.t(* the abstract covariant type, equivalent to ivar *)type'adeferred='atletof_ivar(typea)(ivar:aIvar.t):at=Obj.magicivarletto_ivar(typea)t:aIvar.t=Obj.magic(t:at)letinvariantinvariant_at=Ivar.invariantinvariant_a(to_ivart)letsexp_of_tsexp_of_at=Ivar.sexp_of_tsexp_of_a(to_ivart)letpeekt=Ivar.peek(to_ivart)letreturna=of_ivar(Ivar.create_fulla)letis_determinedt=Ivar.is_full(to_ivart)letvalue_exnt=Ivar.value(to_ivart)~if_empty_then_failwith:"Deferred.value_exn called on undetermined deferred";;letupontf=Ivar.upon(to_ivart)fletcreatef=letresult=Ivar.create()infresult;of_ivarresult;;(* don't use [create] here as it would allocate one more closure *)letbindt~f=letbind_result=Ivar.create()inupont(funa->Ivar.connect~bind_result~bind_rhs:(to_ivar(fa)));of_ivarbind_result;;letadd_handlertfexecution_context=Ivar.add_handler(to_ivart)fexecution_contextletremove_handlerth=Ivar.remove_handler(to_ivart)h