Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file reference.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248(* (c) 2015 Daniel C. Bünzli
* (c) 2020 Romain Calascibetta
*
* This implementation differs a bit from [fpath]
* where absolute path is not valid and we manipulate
* only POSIX path - the backend takes care about Windows
* and POSIX paths then. *)typet=string(* non empty *)letdir_sep="/"letdir_sep_char='/'leterror_msgffmt=Fmt.kstr(funerr->Error(`Msgerr))fmtletvalidate_and_collapse_sepsp=letmax_idx=String.lengthp-1inletrecwith_bufblast_sepki=ifi>max_idxthenOk(Bytes.sub_stringb0k)elseletc=p.[i]inifc='\x00'thenerror_msgf"Malformed reference: %S"pelseifc<>dir_sep_charthen(Bytes.setbkc;with_bufbfalse(k+1)(i+1))elseifnotlast_septhen(Bytes.setbkc;with_bufbtrue(k+1)(i+1))elsewith_bufbtruek(i+1)inletrectry_no_alloclast_sepi=ifi>max_idxthenOkpelseletc=p.[i]inifc='\x00'thenerror_msgf"Malformed reference: %S"pelseifc<>dir_sep_charthentry_no_allocfalse(i+1)elseifnotlast_septhentry_no_alloctrue(i+1)elseletb=Bytes.of_stringpinwith_bufbtruei(i+1)inletstart=ifmax_idx>0thenifp.[0]=dir_sep_charthen1else0else0intry_no_allocfalsestartletof_stringp=ifp=""thenerror_msgf"Empty path"elsematchvalidate_and_collapse_sepspwith|Okp->ifp.[0]=dir_sep_charthenerror_msgf"Absolute reference"elseOkp|Error_aserr->errletvp=matchof_stringpwithOkv->v|Error(`Msgerr)->invalid_argerrletis_segs=letzero=String.containss'\x00'inletsep=String.containssdir_sep_charin(notzero)&¬sepletadd_segpseg=ifnot(is_segseg)thenFmt.invalid_arg"Invalid segment: %S"seg;letsep=ifp.[String.lengthp-1]=dir_sep_charthen""elsedir_sepinString.concatsep[p;sep]letappendp0p1=ifp1.[0]=dir_sep_charthenp1elseletsep=ifp0.[String.lengthp0-1]=dir_sep_charthen""elsedir_sepinString.concatsep[p0;p1]let(/)pseg=add_segpseglet(//)p0p1=appendp0p1letsegsp=Astring.String.cuts~sep:dir_seppletppppfp=Fmt.stringppfpletto_stringx=xletequalp0p1=String.equalp0p1letcomparep0p1=String.comparep0p1lethead="HEAD"letmaster="refs/heads/master"moduleOrdered=structtypenonrect=tletcompareab=compareabendmoduleMap=Map.Make(Ordered)moduleSet=Set.Make(Ordered)type'uidcontents=Uidof'uid|Refoftletequal_contents~equal:equal_uidab=matcha,bwith|Uida,Uidb->equal_uidab|Refa,Refb->equalab|_->falseletpp_contents~pp:pp_uidppf=function|Refv->ppppfv|Uidv->pp_uidppfvletcompare_contents~compare:compare_uidab=letinf=-1andsup=1inmatcha,bwith|Refa,Refb->compareab|Uida,Uidb->compare_uidab|Ref_,_->sup|Uid_,_->infopenCartonmodulePacked=structtype'uidelt=Refoft*'uid|Peeledof'uidtype'uidpacked='uideltlisttype('fd,'s)input_line='fd->(stringoption,'s)io(* XXX(dinosaure): [Digestif.of_hex] is able to ignore '\n' character.
* This code relies on this behavior. *)letload{Carton.bind;Carton.return}~input_line~of_hexfd=let(>>=)=bindinletrecgoacc=input_linefd>>=function|Someline->(matchAstring.String.headlinewith|None->goacc|Some'#'->goacc|Some'^'->letuid=String.subline1(String.lengthline-1)inletuid=of_hexuidingo(Peeleduid::acc)|Some_->(matchAstring.String.cut~sep:" "linewith|Some(uid,reference)->letreference=vreferenceinletuid=of_hexuidingo(Ref(reference,uid)::acc)|None->goacc))|None->return(List.revacc)ingo[]exceptionFoundletexistsreferencepacked=letres=reffalseinletf=function|Ref(reference',_)->ifequalreferencereference'then(res:=true;raiseFound)|_->()in(tryList.iterfpackedwithFound->());!resletgetreferencepacked=letres=refNoneinletf=function|Ref(reference',uid)->ifequalreferencereference'then(res:=Someuid;raiseFound)|_->()in(tryList.iterfpackedwithFound->());!resletremovereferencepacked=letfoldacc=function|Ref(reference',uid)->ifequalreferencereference'thenaccelseRef(reference',uid)::acc|v->v::accinList.rev(List.fold_leftfold[]packed)endtype('t,'uid,'error,'s)store={atomic_wr:'t->t->string->((unit,'error)result,'s)io;atomic_rd:'t->t->((string,'error)result,'s)io;uid_of_hex:string->'uidoption;uid_to_hex:'uid->string;packed:'uidPacked.packed;}letreword_errorf=functionOk_aso->o|Errorerr->Error(ferr)letcontentsstorestr=matchstore.uid_of_hex(String.trimstr)with|Someuid->Uiduid|None->(letis_sepchr=Astring.Char.Ascii.is_whitechr||chr=':'inmatchAstring.String.fields~empty:false~is_sepstrwith|[_ref;value]->Ref(vvalue)|_->Fmt.invalid_arg"Invalid reference contents: %S"str)letresolve{Carton.bind;Carton.return}tstorereference=let(>>=)=bindinletrecgovisitedreference=store.atomic_rdtreference>>=function|Error_->(matchPacked.getreferencestore.packedwith|Someuid->return(Okuid)|None->return(Error(`Not_foundreference)))|Okstr->(matchcontentsstorestrwith|Uiduid->return(Okuid)|Refreference->ifList.exists(equalreference)visitedthenreturn(Error`Cycle)elsego(reference::visited)reference)ingo[reference]referenceletread{Carton.bind;Carton.return}tstorereference=let(>>=)=bindinstore.atomic_rdtreference>>=function|Error_->(matchPacked.getreferencestore.packedwith|Someuid->return(Ok(Uiduid))|None->return(Error(`Not_foundreference)))|Okstr->return(Ok(contentsstorestr))letwrite{Carton.bind;Carton.return}tstorereferencecontents=let(>>=)=bindinlet(>>|)xf=x>>=funx->return(fx)inletstr=matchcontentswith|Uiduid->Fmt.str"%s\n"(store.uid_to_hexuid)|Reft->Fmt.str"ref: %s\n"tinstore.atomic_wrtreferencestr>>|reword_error(funerr->`Storeerr)moduletypeS=sigtypehashtypenonrect=ttypenonreccontents=hashcontentsendletuiduid=Uiduidletreft=Reft