123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899openEio.Stdtypetristate=No|Yes|Unknown(* Note: [blocking] and [seekable] are not atomic,
but it doesn't matter if we query twice in rare cases. *)typet={fd:Rcfd.t;mutableblocking:tristate;mutableseekable:tristate;close_unix:bool;(* Whether closing this also closes the underlying FD. *)mutablerelease_hook:Eio.Switch.hook;(* Use this on close to remove switch's [on_release] hook. *)}leterr_closedop=Invalid_argument(op^": file descriptor used after calling close!")letusetf~if_closed=Rcfd.uset.fdf~if_closedletuse_exnoptf=Rcfd.uset.fdf~if_closed:(fun()->raise(err_closedop))letcloset=Switch.remove_hookt.release_hook;ift.close_unixthen(ignore(Rcfd.closet.fd:bool))else(ignore(Rcfd.removet.fd:Unix.file_descroption))letremovet=Switch.remove_hookt.release_hook;Rcfd.removet.fdlettristate_of_bool_opt=function|None->Unknown|Sometrue->Yes|Somefalse->Noletof_unix_no_hook?(close_unix=true)?blocking?seekablefd=letseekable=tristate_of_bool_optseekableinletblocking=tristate_of_bool_optblockingin{fd=Rcfd.makefd;blocking;seekable;close_unix;release_hook=Switch.null_hook}letof_unix~sw?blocking?seekable~close_unixfd=lett=of_unix_no_hook?blocking?seekable~close_unixfdint.release_hook<-Switch.on_release_cancellablesw(fun()->closet);tletof_unix_list~swfds=matchSwitch.get_errorswwith|Somee->List.iterUnix.closefds;raisee|None->List.map(of_unix~sw~close_unix:true)fdsexternaleio_is_blocking:Unix.file_descr->bool="eio_unix_is_blocking"letis_blockingt=matcht.blockingwith|No->false|Yes->true|Unknown->uset~if_closed:(Fun.constfalse)@@funfd->letblocking=eio_is_blockingfdint.blocking<-ifblockingthenYeselseNo;blockingletis_seekablet=matcht.seekablewith|No->false|Yes->true|Unknown->uset~if_closed:(Fun.constfalse)@@funfd->letseekable=matchUnix.lseekfd0Unix.SEEK_CURwith|(_:int)->true|exceptionUnix.Unix_error(Unix.ESPIPE,"lseek","")->falseint.seekable<-ifseekablethenYeselseNo;seekableletis_opent=Rcfd.is_opent.fdletrecuse_exn_listopxsk=matchxswith|[]->k[]|x::xs->use_exnopx@@funx->use_exn_listopxs@@funxs->k(x::xs)letuse_exn_optopxf=matchxwith|None->fNone|Somex->use_exnopx(funx->f(Somex))letstdin=of_unix_no_hookUnix.stdinletstdout=of_unix_no_hookUnix.stdoutletstderr=of_unix_no_hookUnix.stderrletppft=Rcfd.ppft.fd