123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687(* Copyright (C) 2023 Petter A. Urkedal <paurkedal@gmail.com>
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version, with the LGPL-3.0 Linking Exception.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* and the LGPL-3.0 Linking Exception along with this library. If not, see
* <http://www.gnu.org/licenses/> and <https://spdx.org>, respectively.
*)moduletypeFIBER=sigtype'atvalreturn:'a->'atmoduleInfix:sigval(>>=):'at->('a->'bt)->'btendvalfinally:(unit->'at)->(unit->unitt)->'atendmoduletypeS=sigtype'afibertypettypehookexceptionOffvaleternal:tvalcreate:unit->tvalrelease:t->unitfibervalrun:(t->'afiber)->'afibervalcheck:t->unitvalon_release_cancellable:t->(unit->unitfiber)->hookvalremove_hook:hook->unitendmoduleMake(Fiber:FIBER)=structopenFiber.Infixtypestate=|Onof(unit->unitFiber.t)Lwt_dllist.t|Offtypet=|Eternal|Ephemeralof{mutablestate:state}typehook=(unit->unitFiber.t)Lwt_dllist.nodeoptionexceptionOffleteternal=Eternalletcreate()=Ephemeral{state=On(Lwt_dllist.create())}letrelease=function|Eternal->failwith"Tried to release eternal switch."|Ephemeral{state=Off}->Fiber.return()|Ephemeral({state=Ontasks}asarg)->letrecloop()=ifLwt_dllist.is_emptytasksthenFiber.return(arg.state<-Off)elseLwt_dllist.take_ltasks()>>=loopinloop()letrunf=letsw=create()inFiber.finally(fun()->fsw)(fun()->releasesw)letcheck=function|Ephemeral{state=On_}|Eternal->()|Ephemeral{state=Off}->raiseOffleton_release_cancellableswf=(matchswwith|Eternal->None|Ephemeral{state=Ontasks}->Some(Lwt_dllist.add_lftasks)|Ephemeral{state=Off}->raiseOff)letremove_hookhook=Option.iterLwt_dllist.removehookend