123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184openCore_kernelopen!ImportopenTypes.Internal_observermodulePacked_=structincludeTypes.Internal_observer.Packedletsexp_of_t(Tinternal_observer)=internal_observer.observing|>[%sexp_of:_Types.Node.t];;letprev_in_all(Tt)=t.prev_in_allletnext_in_all(Tt)=t.next_in_allletset_prev_in_all(Tt1)t2=t1.prev_in_all<-t2letset_next_in_all(Tt1)t2=t1.next_in_all<-t2endmoduleState=structtypet=Types.Internal_observer.State.t=|Created|In_use|Disallowed|Unlinked[@@derivingsexp_of]endtype'at='aTypes.Internal_observer.t={(* State transitions:
{v
Created --> In_use --> Disallowed --> Unlinked
| ^
\-------------------------------------/
v} *)mutablestate:State.t;observing:'aNode.t;mutableon_update_handlers:'aOn_update_handler.tlist;(* [{prev,next}_in_all] doubly link all observers in [state.all_observers]. *)mutableprev_in_all:Packed_.tUopt.t;mutablenext_in_all:Packed_.tUopt.t;(* [{prev,next}_in_observing] doubly link all observers of [observing]. *)mutableprev_in_observing:('at[@sexp.opaque])Uopt.t;mutablenext_in_observing:('at[@sexp.opaque])Uopt.t}[@@derivingfields,sexp_of]type'ainternal_observer='at[@@derivingsexp_of]letuse_is_allowedt=matcht.statewith|Created|In_use->true|Disallowed|Unlinked->false;;letsame(t1:_t)(t2:_t)=phys_samet1t2letsame_as_packed(t1:_t)(Packed_.Tt2)=samet1t2letinvariantinvariant_at=Invariant.invariant[%here]t[%sexp_of:_t](fun()->letcheckf=Invariant.check_fieldtfinFields.iter~state:ignore~observing:(check(Node.invariantinvariant_a))~on_update_handlers:(check(funon_update_handlers->matcht.statewith|Created|In_use|Disallowed->()|Unlinked->assert(List.is_emptyon_update_handlers)))~prev_in_all:(check(funprev_in_all->(matcht.statewith|In_use|Disallowed->()|Created|Unlinked->assert(Uopt.is_noneprev_in_all));ifUopt.is_someprev_in_allthenassert(same_as_packedt(Uopt.value_exn(Packed_.next_in_all(Uopt.value_exnprev_in_all))))))~next_in_all:(check(funnext_in_all->(matcht.statewith|In_use|Disallowed->()|Created|Unlinked->assert(Uopt.is_nonenext_in_all));ifUopt.is_somenext_in_allthenassert(same_as_packedt(Uopt.value_exn(Packed_.prev_in_all(Uopt.value_exnnext_in_all))))))~prev_in_observing:(check(funprev_in_observing->(matcht.statewith|In_use|Disallowed->()|Created|Unlinked->assert(Uopt.is_noneprev_in_observing));ifUopt.is_someprev_in_observingthenassert(phys_equalt(Uopt.value_exn(next_in_observing(Uopt.value_exnprev_in_observing))))))~next_in_observing:(check(funnext_in_observing->(matcht.statewith|In_use|Disallowed->()|Created|Unlinked->assert(Uopt.is_nonenext_in_observing));ifUopt.is_somenext_in_observingthenassert(phys_equalt(Uopt.value_exn(prev_in_observing(Uopt.value_exnnext_in_observing)))))));;letvalue_exnt=matcht.statewith|Created->failwiths"Observer.value_exn called without stabilizing"t[%sexp_of:_t]|Disallowed|Unlinked->failwiths"Observer.value_exn called after disallow_future_use"t[%sexp_of:_t]|In_use->letuopt=t.observing.value_optinifUopt.is_noneuoptthenfailwiths"attempt to get value of an invalid node"t[%sexp_of:_t];Uopt.unsafe_valueuopt;;leton_update_exnton_update_handler=matcht.statewith|Disallowed|Unlinked->failwiths"on_update disallowed"t[%sexp_of:_t]|Created|In_use->t.on_update_handlers<-on_update_handler::t.on_update_handlers;(matcht.statewith|Disallowed|Unlinked->assertfalse|Created->(* We'll bump [observing.num_on_update_handlers] when [t] is actually added to
[observing.observers] at the start of the next stabilization. *)()|In_use->letobserving=t.observinginobserving.num_on_update_handlers<-observing.num_on_update_handlers+1);;letunlink_from_observingt=letprev=t.prev_in_observinginletnext=t.next_in_observingint.prev_in_observing<-Uopt.none;t.next_in_observing<-Uopt.none;ifUopt.is_somenextthen(Uopt.unsafe_valuenext).prev_in_observing<-prev;ifUopt.is_someprevthen(Uopt.unsafe_valueprev).next_in_observing<-next;letobserving=t.observinginifphys_equalt(Uopt.value_exnobserving.observers)thenobserving.observers<-next;observing.num_on_update_handlers<-observing.num_on_update_handlers-List.lengtht.on_update_handlers;t.on_update_handlers<-[];;letunlink_from_allt=letprev=t.prev_in_allinletnext=t.next_in_allint.prev_in_all<-Uopt.none;t.next_in_all<-Uopt.none;ifUopt.is_somenextthenPacked_.set_prev_in_all(Uopt.unsafe_valuenext)prev;ifUopt.is_someprevthenPacked_.set_next_in_all(Uopt.unsafe_valueprev)next;;letunlinkt=unlink_from_observingt;unlink_from_allt;;modulePacked=structincludePacked_letsexp_of_t(Tinternal_observer)=internal_observer|>[%sexp_of:_internal_observer];;letinvariant(Tt)=invariantignoretend