123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172openCore_kernelopenAsync_kernelmoduleDurable=structtype'at=|Void|Buildingof'aDeferred.Or_error.t|Builtof'aendtype'at={mutabledurable:'aDurable.t;to_create:unit->'aDeferred.Or_error.t;is_broken:'a->bool;to_rebuild:('a->'aDeferred.Or_error.t)option}letcreate~to_create~is_broken?to_rebuild()={durable=Void;to_create;is_broken;to_rebuild};;letcreate_or_fail~to_create~is_broken?to_rebuild()=lett=create~to_create~is_broken?to_rebuild()int.to_create()>>=?fundur->ift.is_brokendurthenreturn(Or_error.error_string"Initial durable value is broken.")else(t.durable<-Builtdur;return(Okt));;letget_durablet=letbuildbuilding=letbuilding=let%mapresult=buildinginassert(matcht.durablewith|Building_->true|_->false);t.durable<-(matchresultwith(* Errors that show up here will also be returned by [get_durable]. We aren't
losing any information *)|Error_->Void|Okdurable->Builtdurable);resultint.durable<-Buildingbuilding;buildinginmatcht.durablewith|Void->build(t.to_create())|Buildingdurable->durable|Builtdurable->ift.is_brokendurablethenbuild(matcht.to_rebuildwith|None->t.to_create()|Someto_rebuild->to_rebuilddurable)elsereturn(Okdurable);;letwith_t~f=get_durablet>>=?fundurable->ift.is_brokendurablethenreturn(Or_error.error_string"Durable value was broken immediately after being created or rebuilt.")elsefdurable;;let%test_module_=(modulestructletgo()=Async_kernel_scheduler.Expert.run_cycles_until_no_jobs_remain()letcreate_counter=ref0letfix_counter=ref0moduleFragile=structtypet={mutableis_broken:bool}letis_brokent=t.is_brokenletbreakt=t.is_broken<-trueletcreate_()=return(Ok{is_broken=false})letcreate()=create_counter:=!create_counter+1;create_();;letfix_t=fix_counter:=!fix_counter+1;create_();;endletreset()=create_counter:=0;fix_counter:=0;;letcreate~use_fix~now=letto_rebuild=ifuse_fixthenSomeFragile.fixelseNoneinifnowthencreate_or_fail~to_create:Fragile.create~is_broken:Fragile.is_broken?to_rebuild()>>|ok_exnelsereturn(create~to_create:Fragile.create~is_broken:Fragile.is_broken?to_rebuild());;letpoket=ignore(with_t~f:(fun_t->return(Ok())))let%test_unit_=letpass=reffalsein(create~use_fix:false~now:true>>>funt->matcht.durablewith|Built_->pass:=true|_->());go();assert!pass;;letbuild_break_poke~use_fix~now=reset();(create~use_fix~now>>>funt->with_t~f:(funfragile->Fragile.breakfragile;return(Ok()))>>>funresult->Or_error.ok_exnresult;poket;poket;poket);go();;let%test_unit_=build_break_poke~use_fix:true~now:true;assert(!create_counter=1);assert(!fix_counter=1);;let%test_unit_=build_break_poke~use_fix:true~now:false;assert(!create_counter=1);assert(!fix_counter=1);;let%test_unit_=build_break_poke~use_fix:false~now:true;assert(!create_counter=2);assert(!fix_counter=0);;let%test_unit_=build_break_poke~use_fix:false~now:false;assert(!create_counter=2);assert(!fix_counter=0);;end);;